diff --git a/README.md b/README.md index 3c6e74a5..6504fced 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ 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. +(`v1.1.0`), using a canonical Layer 228 schema with sparse `tlprofile` +exact Layer 225-228 compatibility profiles. If you are looking for a **Telegram server**, **MTProto server**, **Telegram backend**, **Telegram clone server**, or **self-hosted @@ -45,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, canonical Layer 228, and exact Layer 225-228 compatibility profiles. | +| ✅ | MTProto server edge | TCP transport, RSA key exchange, auth keys, encrypted sessions, salts, ack/resend, bad messages, RPC dispatch, canonical Layer 228, and sparse 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. | diff --git a/README.zh-CN.md b/README.zh-CN.md index 1c226bdf..8dbd5f44 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -6,8 +6,8 @@ 协议栈基于已发布的 [`github.com/iamxvbaba/td`](https://github.com/iamxvbaba/td) module -(`v1.0.0`),使用 canonical Layer 228 schema,并提供 exact Layer 225-228 -compatibility profiles。 +(`v1.1.0`),使用 canonical Layer 228 schema,并通过 sparse `tlprofile` +提供 exact Layer 225-228 compatibility profiles。 如果你正在搜索 **Telegram server 实现**、**MTProto server 实现**、 **Telegram 后端**、**Telegram clone server**、**自建 Telegram-like 聊天服务器**, @@ -42,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、canonical Layer 228,以及 exact Layer 225-228 compatibility profiles。 | +| ✅ | MTProto server 接入层 | TCP transport、RSA key exchange、auth key、加密 session、salt、ack/resend、bad message、RPC dispatch、canonical Layer 228,以及 sparse 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 恢复。 | diff --git a/go.mod b/go.mod index 3688ffe4..c333b6b8 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +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/iamxvbaba/td v1.0.0 + github.com/iamxvbaba/td v1.1.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 3d710f5b..1be70761 100644 --- a/go.sum +++ b/go.sum @@ -78,8 +78,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY 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/iamxvbaba/td v1.1.0 h1:6Ddxi8sOuxOioGs3vyDGWlC6q53j4AQ2hFJ4AirJvFk= +github.com/iamxvbaba/td v1.1.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= diff --git a/internal/compat/android/layer_rpc.go b/internal/compat/android/layer_rpc.go index 6ad05a69..6a1e3ee5 100644 --- a/internal/compat/android/layer_rpc.go +++ b/internal/compat/android/layer_rpc.go @@ -4,7 +4,7 @@ import ( "errors" "github.com/iamxvbaba/td/bin" - "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) var ErrPrivateLayerRPCInvalid = errors.New("android private layer RPC is invalid") @@ -12,13 +12,13 @@ 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) +func AdaptPrivateLayerRPC(view tlprofile.UnknownMethodView) (tlprofile.OutboundCall, bool, error) { + outbound, handled, err := view.AdaptClientRPCOverlay(tlprofile.ClientRPCOverlayDrkloAndroid) if err == nil && !handled { - outbound, handled, err = view.AdaptClientRPCOverlay(tg.LayerClientRPCOverlayDrkloAndroidTheme) + outbound, handled, err = view.AdaptClientRPCOverlay(tlprofile.ClientRPCOverlayDrkloAndroidTheme) } if err != nil { - return tg.LayerOutboundCall{}, handled, errors.Join(ErrPrivateLayerRPCInvalid, err) + return tlprofile.OutboundCall{}, handled, errors.Join(ErrPrivateLayerRPCInvalid, err) } return outbound, handled, nil } @@ -26,10 +26,10 @@ func AdaptPrivateLayerRPC(view tg.LayerRPCUnknownMethodView) (tg.LayerOutboundCa // 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) +func UpgradePrivateLayerRPC(profile tlprofile.Profile, in *bin.Buffer, limits tlprofile.Limits) (*bin.Buffer, bool, error) { + upgraded, handled, err := tlprofile.AdaptClientRPCOverlayWithLimits(profile, tlprofile.ClientRPCOverlayDrkloAndroid, in, limits) if err == nil && !handled { - upgraded, handled, err = tg.AdaptClientRPCOverlayWithLimits(profile, tg.LayerClientRPCOverlayDrkloAndroidTheme, in, limits) + upgraded, handled, err = tlprofile.AdaptClientRPCOverlayWithLimits(profile, tlprofile.ClientRPCOverlayDrkloAndroidTheme, in, limits) } if err != nil { return nil, handled, errors.Join(ErrPrivateLayerRPCInvalid, err) diff --git a/internal/compat/android/layer_rpc_test.go b/internal/compat/android/layer_rpc_test.go index 6dd9c53c..a9989325 100644 --- a/internal/compat/android/layer_rpc_test.go +++ b/internal/compat/android/layer_rpc_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/iamxvbaba/td/bin" - "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) func TestUpgradePrivateLayerRPCOnlyAcceptsAuditedAndroidConstructors(t *testing.T) { @@ -20,7 +20,7 @@ func TestUpgradePrivateLayerRPCOnlyAcceptsAuditedAndroidConstructors(t *testing. private.PutID(0x7f3b18ea) // inputPeerEmpty in := &bin.Buffer{Buf: private.Copy()} - upgraded, ok, err := UpgradePrivateLayerRPC(tg.LayerProfileCanonical, in, tg.LayerDecodeLimits{}) + upgraded, ok, err := UpgradePrivateLayerRPC(tlprofile.ProfileCanonical, in, tlprofile.Limits{}) if err != nil || !ok { t.Fatalf("upgrade private method = ok:%v err:%v", ok, err) } @@ -33,13 +33,13 @@ func TestUpgradePrivateLayerRPCOnlyAcceptsAuditedAndroidConstructors(t *testing. 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 { + if value, handled, err := UpgradePrivateLayerRPC(tlprofile.ProfileCanonical, &official, tlprofile.Limits{}); 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 { + if got, want := tlprofile.ClientRPCOverlayMethodCount(tlprofile.ClientRPCOverlayDrkloAndroid), 15; got != want { t.Fatalf("generated DrKLO method count = %d, want %d", got, want) } } @@ -47,7 +47,7 @@ func TestGeneratedPrivateLayerRPCOverlayHasAllAuditedMethods(t *testing.T) { func TestUpgradePrivateLayerRPCRejectsMalformedBody(t *testing.T) { malformed := bin.Buffer{} malformed.PutID(0x41d41ade) - _, ok, err := UpgradePrivateLayerRPC(tg.LayerProfileCanonical, &malformed, tg.LayerDecodeLimits{}) + _, ok, err := UpgradePrivateLayerRPC(tlprofile.ProfileCanonical, &malformed, tlprofile.Limits{}) if !ok || !errors.Is(err, ErrPrivateLayerRPCInvalid) { t.Fatalf("malformed private method = ok:%v err:%v", ok, err) } diff --git a/internal/mtprotoedge/conn.go b/internal/mtprotoedge/conn.go index ea27aab8..2ae0d545 100644 --- a/internal/mtprotoedge/conn.go +++ b/internal/mtprotoedge/conn.go @@ -12,7 +12,7 @@ import ( "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/crypto" "github.com/iamxvbaba/td/proto" - "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "github.com/iamxvbaba/td/transport" ) @@ -279,7 +279,7 @@ func (c *Conn) isPhysicalTransportCurrentOpen() bool { // 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) { +func (c *Conn) LayerProfile() (profile tlprofile.Profile, ok bool) { state := c.LayerProfileState() return state.Profile, state.Origin != LayerProfileUnknown } @@ -288,7 +288,7 @@ func (c *Conn) LayerProfile() (profile tg.LayerProfile, ok bool) { // 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 { +func (c *Conn) FreezeLayerProfile(profile tlprofile.Profile) error { _, err := c.setLayerProfile(profile, LayerProfileExplicit, true) return err } @@ -298,14 +298,14 @@ func (c *Conn) FreezeLayerProfile(profile tg.LayerProfile) error { // 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) { +func (c *Conn) FreezeLayerProfileAt(profile tlprofile.Profile, 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 { +func (c *Conn) SeedLayerProfile(profile tlprofile.Profile) error { _, err := c.setLayerProfile(profile, LayerProfileExplicit, true) return err } @@ -313,7 +313,7 @@ func (c *Conn) SeedLayerProfile(profile tg.LayerProfile) error { // 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 { +func (c *Conn) SeedInheritedLayerProfile(profile tlprofile.Profile) error { _, err := c.setLayerProfile(profile, LayerProfileInherited, false) return err } diff --git a/internal/mtprotoedge/conn_layer_profile.go b/internal/mtprotoedge/conn_layer_profile.go index 4ff303ea..c19dc2f7 100644 --- a/internal/mtprotoedge/conn_layer_profile.go +++ b/internal/mtprotoedge/conn_layer_profile.go @@ -5,7 +5,7 @@ import ( "fmt" "math" - "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "go.uber.org/zap" ) @@ -24,7 +24,7 @@ const ( // 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 + Profile tlprofile.Profile Origin LayerProfileOrigin Epoch uint32 } @@ -49,7 +49,7 @@ func unpackLayerProfileState(raw uint64) LayerProfileSnapshot { return LayerProfileSnapshot{} } return LayerProfileSnapshot{ - Profile: tg.LayerProfile(raw & layerProfileValueMask), + Profile: tlprofile.Profile(raw & layerProfileValueMask), Origin: LayerProfileOrigin((raw >> layerProfileOriginShift) & layerProfileOriginMask), Epoch: uint32(raw >> layerProfileEpochShift), } @@ -63,7 +63,7 @@ func (c *Conn) LayerProfileState() LayerProfileSnapshot { return unpackLayerProfileState(c.layerProfileState.Load()) } -func (c *Conn) setLayerProfile(profile tg.LayerProfile, origin LayerProfileOrigin, replace bool) (bool, error) { +func (c *Conn) setLayerProfile(profile tlprofile.Profile, origin LayerProfileOrigin, replace bool) (bool, error) { if err := validateLayerProfile(profile); err != nil { return false, err } @@ -104,8 +104,8 @@ func (c *Conn) setLayerProfile(profile tg.LayerProfile, origin LayerProfileOrigi } } -func validateLayerProfile(profile tg.LayerProfile) error { - resolved, ok := tg.ResolveLayerProfile(int(profile)) +func validateLayerProfile(profile tlprofile.Profile) error { + resolved, ok := tlprofile.ResolveProfile(int(profile)) if !ok || resolved != profile || uint64(profile) > layerProfileValueMask { return fmt.Errorf("%w: %d", ErrLayerProfileUnsupported, profile) } @@ -138,7 +138,7 @@ func (c *Conn) layerProfileRawEvidenceState() (LayerProfileSnapshot, int, int64) // 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) { +func (c *Conn) freezeLayerProfileAt(profile tlprofile.Profile, msgID int64) (bool, error) { if c == nil { return false, fmt.Errorf("nil connection layer profile") } @@ -158,7 +158,7 @@ func (c *Conn) freezeRawLayerProfileAt(layer int, msgID int64) (bool, error) { 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) + profile, supported := tlprofile.ResolveProfile(layer) c.layerProfileMu.Lock() defer c.layerProfileMu.Unlock() @@ -206,7 +206,7 @@ func (c *Conn) freezeRawLayerProfileAt(layer int, msgID int64) (bool, error) { // 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 { +func (c *Conn) seedOrderedLayerProfile(profile tlprofile.Profile, msgID int64) error { if c == nil { return nil } @@ -248,7 +248,7 @@ func (c *Conn) seedRawLayerEvidence(layer int, msgID int64) error { // 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) { +func (c *Conn) refreshInheritedLayerProfile(profile tlprofile.Profile) (bool, error) { if c == nil { return false, nil } @@ -339,7 +339,7 @@ func (s *Server) seedInitialLayerProfile( // 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) + profile, supported := tlprofile.ResolveProfile(layer) if !supported { return nil } @@ -353,7 +353,7 @@ func (s *Server) seedInitialLayerProfile( if msgID > 0 { return c.seedRawLayerEvidence(layer, msgID) } - profile, supported := tg.ResolveLayerProfile(layer) + profile, supported := tlprofile.ResolveProfile(layer) if !supported { return nil } @@ -361,7 +361,7 @@ func (s *Server) seedInitialLayerProfile( } } else if resolver, ok := s.layerRPC.(LayerRPCSessionProfileResolver); ok { if layer, found := resolver.NegotiatedSessionLayer(c.authKeyID, c.sessionID); found { - profile, supported := tg.ResolveLayerProfile(layer) + profile, supported := tlprofile.ResolveProfile(layer) if !supported { return nil } @@ -373,7 +373,7 @@ func (s *Server) seedInitialLayerProfile( // 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) + profile, supported := tlprofile.ResolveProfile(fetchedLayer) if !supported { return nil } @@ -406,7 +406,7 @@ func (s *Server) seedInitialLayerProfile( // 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) + profile, supported := tlprofile.ResolveProfile(layer) if !supported { return nil } @@ -414,7 +414,7 @@ func (s *Server) seedInitialLayerProfile( } } if fetchedLayer != 0 { - profile, supported := tg.ResolveLayerProfile(fetchedLayer) + profile, supported := tlprofile.ResolveProfile(fetchedLayer) if !supported { return nil } @@ -446,7 +446,7 @@ func (s *Server) refreshActivatedInheritedLayerProfile(ctx context.Context, c *C if fetchedLayer == 0 { return nil } - profile, ok := tg.ResolveLayerProfile(fetchedLayer) + profile, ok := tlprofile.ResolveProfile(fetchedLayer) if !ok { return c.clearInheritedLayerProfile() } @@ -472,7 +472,7 @@ func (s *Server) refreshActivatedInheritedLayerProfile(ctx context.Context, c *C zap.String("auth_key_id", c.authKeyHex), zap.Error(err)) } } else if found { - profile, supported := tg.ResolveLayerProfile(layer) + profile, supported := tlprofile.ResolveProfile(layer) if !supported { return c.clearInheritedLayerProfile() } @@ -483,7 +483,7 @@ func (s *Server) refreshActivatedInheritedLayerProfile(ctx context.Context, c *C if fetchedLayer == 0 { return nil } - profile, ok := tg.ResolveLayerProfile(fetchedLayer) + profile, ok := tlprofile.ResolveProfile(fetchedLayer) if !ok { return c.clearInheritedLayerProfile() } diff --git a/internal/mtprotoedge/conn_mgmt_fixes_test.go b/internal/mtprotoedge/conn_mgmt_fixes_test.go index 8d88fc43..3b0cb07c 100644 --- a/internal/mtprotoedge/conn_mgmt_fixes_test.go +++ b/internal/mtprotoedge/conn_mgmt_fixes_test.go @@ -9,6 +9,7 @@ import ( "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) // TestPushSkipsConnReboundToOtherUser 锁定跨账号投递窗口的修复:pushToUserWithSender 在锁外 @@ -28,7 +29,7 @@ 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 { + if err := c.FreezeLayerProfile(tlprofile.ProfileCanonical); err != nil { t.Fatal(err) } sm.Register(c) diff --git a/internal/mtprotoedge/destroy_auth_key.go b/internal/mtprotoedge/destroy_auth_key.go index 3d0ab842..10b66865 100644 --- a/internal/mtprotoedge/destroy_auth_key.go +++ b/internal/mtprotoedge/destroy_auth_key.go @@ -6,7 +6,7 @@ import ( "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/proto" - "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) const ( @@ -20,8 +20,8 @@ var errDestroyAuthKeyMustBeExclusive = errors.New("wrapped destroy_auth_key must // 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 +func wrappedDestroyAuthKeyTerminal(err error) (*tlprofile.UnknownTerminalError, bool) { + var terminal *tlprofile.UnknownTerminalError if !errors.As(err, &terminal) || terminal == nil || terminal.WireID != destroyAuthKeyRequestTypeID { return nil, false } @@ -35,7 +35,7 @@ func wrappedDestroyAuthKeyTerminal(err error) (*tg.LayerRPCUnknownTerminalError, // 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 { +func validWrappedDestroyAuthKeyChain(terminal *tlprofile.UnknownTerminalError) bool { if terminal == nil || terminal.WrapperCount() != 2 { return false } @@ -44,8 +44,8 @@ func validWrappedDestroyAuthKeyChain(terminal *tg.LayerRPCUnknownTerminalError) return outerOK && innerOK && outer.Profile() == terminal.Profile && inner.Profile() == terminal.Profile && - outer.Semantic() == tg.LayerSemanticMethodInvokeWithLayer && - inner.Semantic() == tg.LayerSemanticMethodInitConnection + outer.Semantic() == tlprofile.SemanticMethodInvokeWithLayer && + inner.Semantic() == tlprofile.SemanticMethodInitConnection } type destroyAuthKeyRequest struct{} diff --git a/internal/mtprotoedge/encrypted.go b/internal/mtprotoedge/encrypted.go index d032e162..0338ca81 100644 --- a/internal/mtprotoedge/encrypted.go +++ b/internal/mtprotoedge/encrypted.go @@ -20,10 +20,10 @@ import ( "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" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/observability/dbtrace" "telesrv/internal/postresponse" "telesrv/internal/store" @@ -701,8 +701,8 @@ func (s *Server) handleRPC(ctx context.Context, c *Conn, msgID int64, method str // 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, + admitted, err := tlprofile.NewDispatcher().AdmitDefault( + tlprofile.ProfileCanonical, admissionBody, inboundLayerDecodeLimits, ) diff --git a/internal/mtprotoedge/helpers_test.go b/internal/mtprotoedge/helpers_test.go index 00cbb353..e66ba332 100644 --- a/internal/mtprotoedge/helpers_test.go +++ b/internal/mtprotoedge/helpers_test.go @@ -16,6 +16,7 @@ import ( "github.com/iamxvbaba/td/exchange" "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "github.com/iamxvbaba/td/transport" ) @@ -23,7 +24,7 @@ import ( // 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)) + return legacyLayerWireTestConn(t, c, int(tlprofile.ProfileCanonical)) } // legacyLayerWireTestConn preserves only the old tests' profile setup. It does @@ -34,7 +35,7 @@ func legacyLayerWireTestConn(t testing.TB, c *Conn, layer int) *Conn { if c == nil { t.Fatal("nil legacy exact-layer test Conn") } - profile, ok := tg.ResolveLayerProfile(layer) + profile, ok := tlprofile.ResolveProfile(layer) if !ok { t.Fatalf("unsupported generated test Layer %d", layer) } @@ -62,7 +63,6 @@ func exactTestUpdatesEncoded(t testing.TB, c *Conn, body []byte) *encodedOutboun typeID: tg.UpdatesTooLongTypeID, layer: &outboundLayerBinding{ profile: state.Profile, - typ: tg.LayerClassUpdatesType().Ref(), epoch: state.Epoch, }, } @@ -86,8 +86,7 @@ func (r *opaqueExactTestRPCResult) Encode(b *bin.Buffer) error { return r.result func (r *opaqueExactTestRPCResult) exactLayerRPCResultBinding() outboundLayerBinding { return outboundLayerBinding{ - profile: tg.LayerProfileCanonical, - typ: tg.LayerClassUpdatesType().Ref(), + profile: tlprofile.ProfileCanonical, kind: outboundLayerBindingRequest, } } @@ -180,7 +179,7 @@ func dialTransportOnly(t *testing.T, addr string) transport.Conn { // 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) { +func freezeActiveTestSessionProfile(t *testing.T, sessions *SessionManager, authKeyID [8]byte, sessionID int64, profile tlprofile.Profile) { t.Helper() if sessions == nil { t.Fatal("freeze test session profile on nil SessionManager") diff --git a/internal/mtprotoedge/inbound_layer_rpc.go b/internal/mtprotoedge/inbound_layer_rpc.go index a06c8955..2b23eee2 100644 --- a/internal/mtprotoedge/inbound_layer_rpc.go +++ b/internal/mtprotoedge/inbound_layer_rpc.go @@ -9,10 +9,11 @@ import ( "github.com/iamxvbaba/td/mt" "github.com/iamxvbaba/td/tg" "github.com/iamxvbaba/td/tgerr" + "github.com/iamxvbaba/td/tlprofile" "go.uber.org/zap" ) -var inboundLayerDecodeLimits = tg.LayerDecodeLimits{ +var inboundLayerDecodeLimits = tlprofile.Limits{ MaxWireBytes: maxInflightRPCBytes, // contacts.editCloseFriends and contacts.setBlocked deliberately allow // 5,000 entries. Keep the coarse generated allocation ceiling above every @@ -48,7 +49,7 @@ type layerRPCDependencySet struct { } type layerRPCProfileEvidence struct { - profile tg.LayerProfile + profile tlprofile.Profile admissionSeq uint64 present bool fresh bool @@ -67,7 +68,7 @@ type layerRPCAdmissionCursor struct { evidenceMsgID int64 } -func (c *layerRPCAdmissionCursor) observe(profile tg.LayerProfile, msgID int64) error { +func (c *layerRPCAdmissionCursor) observe(profile tlprofile.Profile, msgID int64) error { return c.observeRaw(int(profile), msgID) } @@ -90,7 +91,7 @@ func (c *layerRPCAdmissionCursor) observeRaw(layer int, msgID int64) error { } } c.state = LayerProfileSnapshot{} - if profile, supported := tg.ResolveLayerProfile(layer); supported { + if profile, supported := tlprofile.ResolveProfile(layer); supported { c.state = LayerProfileSnapshot{Profile: profile, Origin: LayerProfileExplicit} } c.rawLayer = layer @@ -136,7 +137,7 @@ func (s *Server) initialLayerRPCAdmissionCursor(ctx context.Context, c *Conn) (l if registryMsgID == 0 { if cursor.evidenceMsgID == 0 { cursor.state = LayerProfileSnapshot{} - if profile, supported := tg.ResolveLayerProfile(layer); supported { + if profile, supported := tlprofile.ResolveProfile(layer); supported { cursor.state = LayerProfileSnapshot{Profile: profile, Origin: LayerProfileExplicit} } cursor.rawLayer = layer @@ -466,7 +467,7 @@ func (s *Server) prepareInboundLayerRPCBatch(ctx context.Context, c *Conn, plan } plan.rejectNewRPCOwners(indices) for _, index := range candidateItems { - plan.items[index].admitted = tg.LayerRequest{} + plan.items[index].admitted = tlprofile.Admission{} } if err := reservation.retain(nil, nil); err != nil { return err @@ -534,7 +535,7 @@ func (s *Server) prepareInboundLayerRPCBatch(ctx context.Context, c *Conn, plan } plan.rewrapAliases = keptAliases for _, index := range candidateItems { - plan.items[index].admitted = tg.LayerRequest{} + plan.items[index].admitted = tlprofile.Admission{} } if err := reservation.retain(nil, nil); err != nil { return err @@ -581,7 +582,7 @@ func (s *Server) prepareInboundLayerRPCBatch(ctx context.Context, c *Conn, plan } if len(specs) == 0 { for _, index := range candidateItems { - plan.items[index].admitted = tg.LayerRequest{} + plan.items[index].admitted = tlprofile.Admission{} } if err := reservation.retain(nil, nil); err != nil { return err @@ -604,7 +605,7 @@ func (s *Server) prepareInboundLayerRPCBatch(ctx context.Context, c *Conn, plan // 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{} + plan.items[index].admitted = tlprofile.Admission{} } if err := reservation.retain(reservationIndices, specs); err != nil { return err @@ -628,7 +629,7 @@ func (s *Server) acquireAdmittedLayerRPC( return rpcResultAcquire{}, ErrRPCResultFlightInvalid } acquire := func() (rpcResultAcquire, error) { - profile := tg.LayerProfile(0) + profile := tlprofile.Profile(0) if effective, known := item.admitted.EffectiveProfile(); known { profile = effective } @@ -671,7 +672,7 @@ func (s *Server) acquireAdmittedLayerRPC( return acquire() } -func (s *Server) prepareAdmittedLayerRPCReplay(ctx context.Context, c *Conn, msgID int64, admissionSeq uint64, profileEvidenceFresh bool, request tg.LayerRequest) (func() error, error) { +func (s *Server) prepareAdmittedLayerRPCReplay(ctx context.Context, c *Conn, msgID int64, admissionSeq uint64, profileEvidenceFresh bool, request tlprofile.Admission) (func() error, error) { preparer, ok := s.layerRPC.(LayerRPCReplayPreparer) if !ok || c == nil { return nil, nil @@ -703,26 +704,26 @@ func (s *Server) withLayerRPCProfileEvidenceFresh(ctx context.Context, fresh boo // 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) { +func (s *Server) admitInboundLayerRPC(c *Conn, body []byte) (tlprofile.Admission, string, error) { return s.admitInboundLayerRPCAt(c, 0, body) } -func (s *Server) admitInboundLayerRPCAt(c *Conn, msgID int64, body []byte) (tg.LayerRequest, string, error) { +func (s *Server) admitInboundLayerRPCAt(c *Conn, msgID int64, body []byte) (tlprofile.Admission, 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") + return tlprofile.Admission{}, "unknown", fmt.Errorf("invalid exact RPC admission input") } request, method, err := s.decodeInboundLayerRPC(c.LayerProfileState(), body) if err != nil { - return tg.LayerRequest{}, method, err + return tlprofile.Admission{}, 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 + return tlprofile.Admission{}, method, err } if msgID > 0 { if _, localErr := c.freezeLayerProfileAt(profile, msgID); localErr != nil { - return tg.LayerRequest{}, method, localErr + return tlprofile.Admission{}, method, localErr } } } @@ -737,8 +738,8 @@ func (s *Server) admitInboundLayerRPCAt(c *Conn, msgID int64, body []byte) (tg.L // 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 { + var codecErr *tlprofile.LayerCodecError + if errors.As(admissionErr, &codecErr) && codecErr.Semantic == tlprofile.SemanticMethodInvokeWithLayer { return true } @@ -784,13 +785,13 @@ func layerRPCAdmissionHasExplicitSelector(body []byte, admissionErr error) bool // 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) { +func (s *Server) decodeInboundLayerRPC(state LayerProfileSnapshot, body []byte) (tlprofile.Admission, string, error) { if s == nil || s.layerRPC == nil || len(body) < bin.Word { - return tg.LayerRequest{}, "unknown", fmt.Errorf("invalid exact RPC admission input") + return tlprofile.Admission{}, "unknown", fmt.Errorf("invalid exact RPC admission input") } b := &bin.Buffer{Buf: body} var ( - request tg.LayerRequest + request tlprofile.Admission err error ) if state.Origin != LayerProfileUnknown { @@ -806,19 +807,19 @@ func (s *Server) decodeInboundLayerRPC(state LayerProfileSnapshot, body []byte) } method := "unknown" if err == nil { - _, method, _ = tg.LayerSemanticName(request.Call().Method()) + _, method, _ = tlprofile.SemanticName(request.Call().Method()) if b.Len() != 0 { - return tg.LayerRequest{}, method, fmt.Errorf("exact RPC admission left %d bytes", b.Len()) + return tlprofile.Admission{}, 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()) + return tlprofile.Admission{}, 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 tlprofile.Admission{}, method, fmt.Errorf("%w: generated profile evidence %d differs from call profile %d", ErrLayerProfileConflict, profile, request.Call().Profile()) } } return request, method, nil @@ -834,9 +835,9 @@ func (s *Server) decodeInboundLayerRPC(state LayerProfileSnapshot, body []byte) 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 := new(tlprofile.LayerCodecError); errors.As(err, &codecErr) { if codecErr.Semantic != 0 { - if _, semanticMethod, ok := tg.LayerSemanticName(codecErr.Semantic); ok && semanticMethod != "" { + if _, semanticMethod, ok := tlprofile.SemanticName(codecErr.Semantic); ok && semanticMethod != "" { method = semanticMethod } } else if codecErr.WireID != 0 { @@ -846,7 +847,7 @@ func (s *Server) decodeInboundLayerRPC(state LayerProfileSnapshot, body []byte) method = s.typeName(codecErr.WireID) } } - if errors.Is(err, tg.ErrLayerUnknownRPCMethod) && s.log != nil { + if errors.Is(err, tlprofile.ErrUnknownRPCMethod) && s.log != nil { if terminal, recognized := wrappedDestroyAuthKeyTerminal(err); recognized { method = "destroy_auth_key" s.log.Debug("Generated wrapper admission exposed MTProto service terminal", @@ -860,7 +861,7 @@ func (s *Server) decodeInboundLayerRPC(state LayerProfileSnapshot, body []byte) zap.String("method", method), zap.Error(err)) } } - return tg.LayerRequest{}, method, err + return tlprofile.Admission{}, method, err } // commitLayerProfileEvidence publishes one generated invokeWithLayer proof. @@ -868,7 +869,7 @@ func (s *Server) decodeInboundLayerRPC(state LayerProfileSnapshot, body []byte) // 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) { +func (s *Server) commitLayerProfileEvidence(ctx context.Context, c *Conn, profile tlprofile.Profile, msgID int64) (bool, error) { if s == nil || c == nil { return false, fmt.Errorf("invalid layer profile evidence target") } @@ -890,7 +891,7 @@ func (s *Server) commitLayerProfileEvidence(ctx context.Context, c *Conn, profil } else if _, err := c.freezeRawLayerProfileAt(layer, authoritativeMsgID); err != nil { return false, err } - authoritative, supported := tg.ResolveLayerProfile(layer) + authoritative, supported := tlprofile.ResolveProfile(layer) return supported && authoritative == profile && authoritativeMsgID == msgID && publishShared, nil } if registry, ok := s.layerRPC.(LayerRPCOrderedSessionProfileRegistry); ok { @@ -909,7 +910,7 @@ func (s *Server) commitLayerProfileEvidence(ctx context.Context, c *Conn, profil if !found || authoritativeMsgID <= 0 { return false, fmt.Errorf("%w: ordered exact session evidence disappeared after commit", ErrLayerProfileConflict) } - authoritative, supported := tg.ResolveLayerProfile(layer) + authoritative, supported := tlprofile.ResolveProfile(layer) if s.conns != nil { if _, err := s.conns.ApplyOrderedRawLayerForSession(c, c.authKeyID, c.sessionID, layer, authoritativeMsgID); err != nil { return false, err @@ -980,34 +981,34 @@ 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) { + if errors.Is(err, tlprofile.ErrProfileRequired) { 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) { + if errors.Is(err, tlprofile.ErrUnknownRPCMethod) { 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 { +func (s *Server) layerRPCDependencies(c *Conn, msgID int64, request tlprofile.Admission) 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: + case tlprofile.SemanticMethodInvokeAfterMsg: id, err := layerRPCWrapperRequired[int64](wrapper, "msg_id") if err != nil { result.failed = true continue } ids = []int64{id} - case tg.LayerSemanticMethodInvokeAfterMsgs: + case tlprofile.SemanticMethodInvokeAfterMsgs: var err error ids, err = layerRPCWrapperRequired[[]int64](wrapper, "msg_ids") if err != nil || len(ids) > maxLayerRPCDependencyIDs { @@ -1045,16 +1046,16 @@ func (s *Server) layerRPCDependencies(c *Conn, msgID int64, request tg.LayerRequ return result } -func admittedRPCRewrapInit(request tg.LayerRequest) (rpcRewrapInit, bool) { +func admittedRPCRewrapInit(request tlprofile.Admission) (rpcRewrapInit, bool) { if request.WrapperCount() != 2 { return rpcRewrapInit{}, false } layerWrapper, ok := request.Wrapper(0) - if !ok || layerWrapper.Semantic() != tg.LayerSemanticMethodInvokeWithLayer { + if !ok || layerWrapper.Semantic() != tlprofile.SemanticMethodInvokeWithLayer { return rpcRewrapInit{}, false } initWrapper, ok := request.Wrapper(1) - if !ok || initWrapper.Semantic() != tg.LayerSemanticMethodInitConnection { + if !ok || initWrapper.Semantic() != tlprofile.SemanticMethodInitConnection { return rpcRewrapInit{}, false } layer, err := layerRPCWrapperRequired[int](layerWrapper, "layer") @@ -1095,7 +1096,7 @@ func admittedRPCRewrapInit(request tg.LayerRequest) (rpcRewrapInit, bool) { }, true } -func layerRPCWrapperRequired[T any](wrapper tg.LayerRPCWrapper, name string) (T, error) { +func layerRPCWrapperRequired[T any](wrapper tlprofile.Wrapper, name string) (T, error) { var zero T value, present, ok, err := wrapper.Value(name) if err != nil || !ok || !present { diff --git a/internal/mtprotoedge/inbound_layer_rpc_test.go b/internal/mtprotoedge/inbound_layer_rpc_test.go index 1b3a8917..f0f3fe32 100644 --- a/internal/mtprotoedge/inbound_layer_rpc_test.go +++ b/internal/mtprotoedge/inbound_layer_rpc_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strings" "sync" "sync/atomic" "testing" @@ -15,6 +16,7 @@ import ( "github.com/iamxvbaba/td/tg" "go.uber.org/zap/zaptest" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/rpc" "telesrv/internal/store" "telesrv/internal/store/memory" @@ -29,17 +31,17 @@ func exactLayerRPCBody(t *testing.T, request bin.Encoder) []byte { return body.Copy() } -func exactOutboundLayerRPCBody(t *testing.T, profile tg.LayerProfile, request bin.Object) []byte { +func exactOutboundLayerRPCBody(t *testing.T, profile tlprofile.Profile, request bin.Object) []byte { t.Helper() - outbound, err := tg.PrepareLayerOutboundCall(profile, request) - if err != nil { + var body bin.Buffer + if err := tlprofile.EncodeObject(profile, request, &body); err != nil { t.Fatal(err) } - return exactLayerRPCBody(t, outbound) + return body.Copy() } type admissionOnlyLayerRPC struct { - dispatcher *tg.ServerDispatcher + dispatcher *tlprofile.Dispatcher mu sync.Mutex published []publishedLayerEvidence } @@ -128,8 +130,8 @@ func (s unavailableEdgeSessionLayerStore) DeleteExpiredSessionLayers(context.Con type dispatchProfileCaptureRouter struct { *rpc.Router mu sync.Mutex - requestProfile tg.LayerProfile - resultProfile tg.LayerProfile + requestProfile tlprofile.Profile + resultProfile tlprofile.Profile } func (h *dispatchProfileCaptureRouter) DispatchAdmitted( @@ -138,8 +140,8 @@ func (h *dispatchProfileCaptureRouter) DispatchAdmitted( sessionID int64, msgID int64, admissionSeq uint64, - request tg.LayerRequest, -) (tg.LayerRPCResult, string, error) { + request tlprofile.Admission, +) (tlprofile.Result, string, error) { result, method, err := h.Router.DispatchAdmitted(ctx, authKeyID, sessionID, msgID, admissionSeq, request) h.mu.Lock() h.requestProfile = request.Call().Profile() @@ -150,7 +152,7 @@ func (h *dispatchProfileCaptureRouter) DispatchAdmitted( return result, method, err } -func (h *dispatchProfileCaptureRouter) profiles() (tg.LayerProfile, tg.LayerProfile) { +func (h *dispatchProfileCaptureRouter) profiles() (tlprofile.Profile, tlprofile.Profile) { h.mu.Lock() defer h.mu.Unlock() return h.requestProfile, h.resultProfile @@ -189,7 +191,7 @@ func (h *capacityAdmissionOnlyLayerRPC) FreezeNegotiatedSessionLayerAt([8]byte, type replayProfileCaptureLayerRPC struct { *admissionOnlyLayerRPC mu sync.Mutex - profiles []tg.LayerProfile + profiles []tlprofile.Profile known []bool } @@ -199,7 +201,7 @@ func (h *replayProfileCaptureLayerRPC) PrepareAdmittedReplay( _ int64, _ int64, _ uint64, - request tg.LayerRequest, + request tlprofile.Admission, ) (func() error, error) { profile, known := request.EffectiveProfile() h.mu.Lock() @@ -209,14 +211,14 @@ func (h *replayProfileCaptureLayerRPC) PrepareAdmittedReplay( return nil, nil } -func (h *replayProfileCaptureLayerRPC) capturedProfiles() ([]tg.LayerProfile, []bool) { +func (h *replayProfileCaptureLayerRPC) capturedProfiles() ([]tlprofile.Profile, []bool) { h.mu.Lock() defer h.mu.Unlock() - return append([]tg.LayerProfile(nil), h.profiles...), append([]bool(nil), h.known...) + return append([]tlprofile.Profile(nil), h.profiles...), append([]bool(nil), h.known...) } func newAdmissionOnlyLayerRPC() *admissionOnlyLayerRPC { - return &admissionOnlyLayerRPC{dispatcher: tg.NewServerDispatcher(nil)} + return &admissionOnlyLayerRPC{dispatcher: tlprofile.NewDispatcher()} } func newOrderedAdmissionOnlyLayerRPC() *orderedAdmissionOnlyLayerRPC { @@ -259,19 +261,19 @@ func (h *orderedAdmissionOnlyLayerRPC) FreezeNegotiatedSessionLayerAt(authKeyID 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) AdmitLayer(profile tlprofile.Profile, b *bin.Buffer, limits tlprofile.Limits) (tlprofile.Admission, error) { + return h.dispatcher.Admit(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) AdmitDefaultLayer(profile tlprofile.Profile, b *bin.Buffer, limits tlprofile.Limits) (tlprofile.Admission, error) { + return h.dispatcher.AdmitDefault(profile, b, limits) } -func (h *admissionOnlyLayerRPC) AdmitUnprofiled(b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) { - return h.dispatcher.AdmitUnprofiledWithLimits(b, limits) +func (h *admissionOnlyLayerRPC) AdmitUnprofiled(b *bin.Buffer, limits tlprofile.Limits) (tlprofile.Admission, error) { + return h.dispatcher.AdmitUnprofiled(b, limits) } -func (*admissionOnlyLayerRPC) DispatchAdmitted(context.Context, [8]byte, int64, int64, uint64, tg.LayerRequest) (tg.LayerRPCResult, string, error) { +func (*admissionOnlyLayerRPC) DispatchAdmitted(context.Context, [8]byte, int64, int64, uint64, tlprofile.Admission) (tlprofile.Result, string, error) { return nil, "", fmt.Errorf("admission-only handler") } @@ -302,7 +304,7 @@ func (h *admissionOnlyLayerRPC) publications() []publishedLayerEvidence { func TestNestedExplicitLayerAdmissionErrorsAreNotDefaultFailures(t *testing.T) { handler := newAdmissionOnlyLayerRPC() s := New(Options{DC: 2, LayerRPC: handler}) - state := LayerProfileSnapshot{Profile: tg.LayerProfile227, Origin: LayerProfileInherited} + state := LayerProfileSnapshot{Profile: tlprofile.Profile227, Origin: LayerProfileInherited} unsupported := exactLayerRPCBody(t, &tg.InvokeAfterMsgRequest{ MsgID: 1, @@ -334,12 +336,11 @@ func TestNestedExplicitLayerAdmissionErrorsAreNotDefaultFailures(t *testing.T) { malformedSelectedQuery.PutID(tg.MessagesGetHistoryRequestTypeID) for _, test := range []struct { - name string - body []byte - wantSemantic bool + name string + body []byte }{ - {name: "unsupported", body: unsupported, wantSemantic: true}, - {name: "conflict", body: conflict, wantSemantic: true}, + {name: "unsupported", body: unsupported}, + {name: "conflict", body: conflict}, {name: "truncated_selector", body: truncatedSelector.Copy()}, {name: "malformed_selected_query", body: malformedSelectedQuery.Copy()}, } { @@ -351,10 +352,14 @@ func TestNestedExplicitLayerAdmissionErrorsAreNotDefaultFailures(t *testing.T) { 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) + switch test.name { + case "unsupported": + if !strings.Contains(err.Error(), "unsupported exact profile 229") { + t.Fatalf("unsupported selector error = %v", err) + } + case "conflict": + if !errors.Is(err, tlprofile.ErrProfileConflict) { + t.Fatalf("conflicting selector error = %v", err) } } }) @@ -376,7 +381,7 @@ func TestBatchProvisionalCursorKeepsRegistryWatermarkAcrossOldReplay(t *testing. t.Fatal(err) } c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} - if err := c.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + if err := c.SeedInheritedLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) @@ -384,7 +389,7 @@ func TestBatchProvisionalCursorKeepsRegistryWatermarkAcrossOldReplay(t *testing. oldBody := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 225, Query: &tg.HelpGetConfigRequest{}}) oldAdmitted, _, err := s.decodeInboundLayerRPC( - LayerProfileSnapshot{Profile: tg.LayerProfile225, Origin: LayerProfileExplicit}, oldBody, + LayerProfileSnapshot{Profile: tlprofile.Profile225, Origin: LayerProfileExplicit}, oldBody, ) if err != nil { t.Fatal(err) @@ -398,7 +403,7 @@ func TestBatchProvisionalCursorKeepsRegistryWatermarkAcrossOldReplay(t *testing. oldClaim.owner.CompleteExecution(true) s.rpcResults.Put(authKeyID, sessionID, 100, &encodedOutboundMessage{body: []byte{1}, reqMsgID: 100}) - nakedBody := exactOutboundLayerRPCBody(t, tg.LayerProfile227, &tg.MessagesGetHistoryRequest{ + nakedBody := exactOutboundLayerRPCBody(t, tlprofile.Profile227, &tg.MessagesGetHistoryRequest{ Peer: &tg.InputPeerSelf{}, Limit: 1, }) plan := &inboundPlan{items: []inboundItem{ @@ -412,7 +417,7 @@ func TestBatchProvisionalCursorKeepsRegistryWatermarkAcrossOldReplay(t *testing. 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 { + if profile, ok := s.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, 108); !ok || profile != tlprofile.Profile227 { t.Fatalf("following naked admission profile = (%d,%v), want registry Layer 227", profile, ok) } } @@ -423,7 +428,7 @@ func TestBatchProvisionalCursorUsesPendingNewerExplicitEvidence(t *testing.T) { 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 { + if err := c.seedOrderedLayerProfile(tlprofile.Profile225, 100); err != nil { t.Fatal(err) } c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) @@ -431,7 +436,7 @@ func TestBatchProvisionalCursorUsesPendingNewerExplicitEvidence(t *testing.T) { explicitBody := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 227, Query: &tg.HelpGetConfigRequest{}}) explicit, _, err := s.decodeInboundLayerRPC( - LayerProfileSnapshot{Profile: tg.LayerProfile227, Origin: LayerProfileExplicit}, explicitBody, + LayerProfileSnapshot{Profile: tlprofile.Profile227, Origin: LayerProfileExplicit}, explicitBody, ) if err != nil { t.Fatal(err) @@ -444,7 +449,7 @@ func TestBatchProvisionalCursorUsesPendingNewerExplicitEvidence(t *testing.T) { } defer pending.owner.Abort() - nakedBody := exactOutboundLayerRPCBody(t, tg.LayerProfile227, &tg.MessagesGetHistoryRequest{ + nakedBody := exactOutboundLayerRPCBody(t, tlprofile.Profile227, &tg.MessagesGetHistoryRequest{ Peer: &tg.InputPeerSelf{}, Limit: 1, }) plan := &inboundPlan{items: []inboundItem{ @@ -458,10 +463,10 @@ func TestBatchProvisionalCursorUsesPendingNewerExplicitEvidence(t *testing.T) { 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 { + if profile, ok := s.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, 108); !ok || profile != tlprofile.Profile227 { 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 { + if state, msgID := c.layerProfileEvidenceState(); state.Profile != tlprofile.Profile227 || 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 { @@ -500,7 +505,7 @@ func TestFutureExactLayerWatermarkAllowsOnlyNewerSupportedSelfHeal(t *testing.T) t.Fatal(err) } c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} - if err := c.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + if err := c.SeedInheritedLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) @@ -513,7 +518,7 @@ func TestFutureExactLayerWatermarkAllowsOnlyNewerSupportedSelfHeal(t *testing.T) }, { kind: inboundItemRPC, msgID: 104, - body: exactOutboundLayerRPCBody(t, tg.LayerProfile227, &tg.MessagesGetHistoryRequest{ + body: exactOutboundLayerRPCBody(t, tlprofile.Profile227, &tg.MessagesGetHistoryRequest{ Peer: &tg.InputPeerSelf{}, Limit: 1, }), }, @@ -549,7 +554,7 @@ func TestFutureExactLayerWatermarkAllowsOnlyNewerSupportedSelfHeal(t *testing.T) 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 { + if state, rawLayer, msgID := c.layerProfileRawEvidenceState(); state.Profile != tlprofile.Profile227 || 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 { @@ -602,7 +607,7 @@ func TestDurabilityOutageKeepsExplicitLayerConnectionLocal(t *testing.T) { 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 { + if state, msgID := c.layerProfileEvidenceState(); state.Profile != tlprofile.Profile227 || state.Origin != LayerProfileExplicit || msgID != 100 { t.Fatalf("connection-local evidence = %#v msgID:%d", state, msgID) } if _, _, found := handler.NegotiatedSessionLayerEvidence(c.authKeyID, c.sessionID); found { @@ -679,7 +684,7 @@ func TestDurabilityOutageInitializesOnlyCurrentConnection(t *testing.T) { 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 { + if state, evidenceMsgID := c.layerProfileEvidenceState(); state.Profile != tlprofile.Profile227 || state.Origin != LayerProfileExplicit || evidenceMsgID != msgID { t.Fatalf("current connection profile = %#v msg:%d", state, evidenceMsgID) } if _, _, found := router.NegotiatedSessionLayerEvidence(c.authKeyID, c.sessionID); found { @@ -710,7 +715,7 @@ func TestDurabilityOutageInitializesOnlyCurrentConnection(t *testing.T) { t.Fatal(err) } encoded, err := fanout.prepareForConn(ctx, c) - if err != nil || encoded.layer == nil || encoded.layer.profile != tg.LayerProfile227 { + if err != nil || encoded.layer == nil || encoded.layer.profile != tlprofile.Profile227 { t.Fatalf("outage-local push profile = encoded:%#v err:%v", encoded, err) } @@ -723,7 +728,7 @@ func TestDurabilityOutageInitializesOnlyCurrentConnection(t *testing.T) { if state := replacement.LayerProfileState(); state.Origin != LayerProfileUnknown { t.Fatalf("new session inherited outage-local profile: %#v", state) } - naked := exactOutboundLayerRPCBody(t, tg.LayerProfile227, &tg.MessagesGetHistoryRequest{ + naked := exactOutboundLayerRPCBody(t, tlprofile.Profile227, &tg.MessagesGetHistoryRequest{ Peer: &tg.InputPeerSelf{}, Limit: 1, }) if _, _, err := s.admitInboundLayerRPCAt(replacement, msgID+4, naked); err == nil { @@ -782,7 +787,7 @@ func TestInvariantReplayNeverCachesInternalCanonicalProfile(t *testing.T) { } profiled := newConn() defer profiled.Close() - if err := profiled.seedOrderedLayerProfile(tg.LayerProfile225, 104); err != nil { + if err := profiled.seedOrderedLayerProfile(tlprofile.Profile225, 104); err != nil { t.Fatal(err) } completed := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: body}}} @@ -793,7 +798,7 @@ func TestInvariantReplayNeverCachesInternalCanonicalProfile(t *testing.T) { 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 { + if state, msgID := profiled.layerProfileEvidenceState(); state.Profile != tlprofile.Profile225 || state.Origin != LayerProfileExplicit || msgID != 104 { t.Fatalf("invariant replay polluted explicit profile = %#v msgID:%d", state, msgID) } } @@ -804,21 +809,21 @@ func TestSameMsgIDNakedReplayUsesWinnerAdmissionProfile(t *testing.T) { s.rpcResults = newRPCResultCacheWithFlightLimit(time.Now, 8) authKeyID := [8]byte{0x22, 0x99} const sessionID = int64(2299) - body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.MessagesGetHistoryRequest{ + body := exactOutboundLayerRPCBody(t, tlprofile.Profile225, &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, + LayerProfileSnapshot{Profile: tlprofile.Profile225, 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, + LayerProfileSnapshot{Profile: tlprofile.Profile227, Origin: LayerProfileInherited}, body, ) if err != nil { t.Fatal(err) @@ -836,13 +841,13 @@ func TestSameMsgIDNakedReplayUsesWinnerAdmissionProfile(t *testing.T) { 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 { + if got := item227.admitted.Call().Profile(); got != tlprofile.Profile225 { 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, + LayerProfileSnapshot{Profile: tlprofile.Profile225, Origin: LayerProfileInherited}, changed.body, ) if err != nil { t.Fatal(err) @@ -854,7 +859,7 @@ func TestSameMsgIDNakedReplayUsesWinnerAdmissionProfile(t *testing.T) { } func TestInheritedLayerServesRepeatedNakedRPCsWithoutSelectorRefresh(t *testing.T) { - for _, profile := range []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227} { + for _, profile := range []tlprofile.Profile{tlprofile.Profile225, tlprofile.Profile227} { 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{}} @@ -985,7 +990,7 @@ func TestOldCompletedLayerRequestCannotRollBackCorrectedSession(t *testing.T) { if err := s.prepareInboundLayerRPCBatch(context.Background(), c, correctPlan); err != nil { t.Fatal(err) } - if state, msgID := c.layerProfileEvidenceState(); state.Profile != tg.LayerProfile227 || msgID != 104 { + if state, msgID := c.layerProfileEvidenceState(); state.Profile != tlprofile.Profile227 || msgID != 104 { t.Fatalf("corrected Conn = %#v msgID:%d", state, msgID) } @@ -1002,7 +1007,7 @@ func TestOldCompletedLayerRequestCannotRollBackCorrectedSession(t *testing.T) { 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 { + if state, msgID := replacement.layerProfileEvidenceState(); state.Profile != tlprofile.Profile227 || 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 { @@ -1069,11 +1074,11 @@ func TestLogicalSessionLayerWatermarkSurvivesResultExpiryAndOldContainer(t *test 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 { + if state, msgID := replacement.layerProfileEvidenceState(); state.Profile != tlprofile.Profile227 || 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{ + nakedBody := exactOutboundLayerRPCBody(t, tlprofile.Profile227, &tg.MessagesGetHistoryRequest{ Peer: &tg.InputPeerSelf{}, Limit: 1, }) replayPlan := &inboundPlan{items: []inboundItem{ @@ -1090,10 +1095,10 @@ func TestLogicalSessionLayerWatermarkSurvivesResultExpiryAndOldContainer(t *test 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 { + if profile, ok := s.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, freshMsgID); !ok || profile != tlprofile.Profile227 { 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 { + if state, msgID := replacement.layerProfileEvidenceState(); state.Profile != tlprofile.Profile227 || 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 { @@ -1156,14 +1161,14 @@ func TestDurableLayerEvidenceRestoresAcrossEdgeRouterRestart(t *testing.T) { t.Fatal(err) } state, rawLayer, evidenceMsgID := replacement.layerProfileRawEvidenceState() - if state.Profile != tg.LayerProfile225 || state.Origin != LayerProfileExplicit || rawLayer != 225 || evidenceMsgID != selectorMsgID { + if state.Profile != tlprofile.Profile225 || 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{ + body: exactOutboundLayerRPCBody(t, tlprofile.Profile225, &tg.MessagesGetHistoryRequest{ Peer: &tg.InputPeerSelf{}, Limit: 1, }), layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, @@ -1173,7 +1178,7 @@ func TestDurableLayerEvidenceRestoresAcrossEdgeRouterRestart(t *testing.T) { t.Fatal(err) } profile, profiled := restartedEdge.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, nakedMsgID) - if len(nakedPlan.rpcTasks) != 1 || !profiled || profile != tg.LayerProfile225 { + if len(nakedPlan.rpcTasks) != 1 || !profiled || profile != tlprofile.Profile225 { t.Fatalf("restart naked admission = tasks:%d item:%+v", len(nakedPlan.rpcTasks), nakedPlan.items[0]) } } @@ -1207,7 +1212,7 @@ func TestPhysicalConnectionReadsDurableLayerOnceBeforeAdmissionHotPath(t *testin t.Fatalf("connection seed GetSessionLayer calls=%d, want 1", got) } - body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + body := exactOutboundLayerRPCBody(t, tlprofile.Profile225, &tg.HelpGetConfigRequest{}) for i := 0; i < 64; i++ { plan := &inboundPlan{items: []inboundItem{{ kind: inboundItemRPC, msgID: msgIDs.New(proto.MessageFromClient), body: body, @@ -1237,12 +1242,12 @@ func TestDurableExactSeedOutageKeepsFetchedAuthKeyDefaultServing(t *testing.T) { t.Fatal(err) } initial := c.LayerProfileState() - if initial.Profile != tg.LayerProfile225 || initial.Origin != LayerProfileInherited { + if initial.Profile != tlprofile.Profile225 || 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{ + body := exactOutboundLayerRPCBody(t, tlprofile.Profile225, &tg.MessagesGetHistoryRequest{ Peer: &tg.InputPeerSelf{}, Limit: 1, }) for i := 0; i < 64; i++ { @@ -1280,12 +1285,12 @@ func TestBoundTempSeedOutageKeepsRawFetchedLayerServingCurrentConn(t *testing.T) t.Fatal(err) } initial := c.LayerProfileState() - if initial.Profile != tg.LayerProfile225 || initial.Origin != LayerProfileInherited { + if initial.Profile != tlprofile.Profile225 || 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{ + body := exactOutboundLayerRPCBody(t, tlprofile.Profile225, &tg.MessagesGetHistoryRequest{ Peer: &tg.InputPeerSelf{}, Limit: 1, }) for i := 0; i < 64; i++ { @@ -1347,7 +1352,7 @@ func TestLiveConnectionKeepsFrozenLayerUntilItsOwnExplicitCorrection(t *testing. t.Fatal(err) } oldPlan.close() - if state, raw, msgID := connA.layerProfileRawEvidenceState(); state.Profile != tg.LayerProfile225 || raw != 225 || msgID != oldMsgID { + if state, raw, msgID := connA.layerProfileRawEvidenceState(); state.Profile != tlprofile.Profile225 || raw != 225 || msgID != oldMsgID { t.Fatalf("A initial profile = state:%#v raw:%d msg:%d", state, raw, msgID) } @@ -1366,18 +1371,18 @@ func TestLiveConnectionKeepsFrozenLayerUntilItsOwnExplicitCorrection(t *testing. oldNakedMsgID := msgIDs.New(proto.MessageFromClient) oldNakedPlan := &inboundPlan{items: []inboundItem{{ kind: inboundItemRPC, msgID: oldNakedMsgID, - body: exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}), + body: exactOutboundLayerRPCBody(t, tlprofile.Profile225, &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 { + if state, raw, msgID := connA.layerProfileRawEvidenceState(); state.Profile != tlprofile.Profile225 || 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 { + if profile, ok := edgeA.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, oldNakedMsgID); !ok || profile != tlprofile.Profile225 { oldNakedPlan.close() t.Fatalf("old naked admission profile = (%d,%v), want 225", profile, ok) } @@ -1388,7 +1393,7 @@ func TestLiveConnectionKeepsFrozenLayerUntilItsOwnExplicitCorrection(t *testing. mismatchMsgID := msgIDs.New(proto.MessageFromClient) mismatchPlan := &inboundPlan{items: []inboundItem{{ kind: inboundItemRPC, msgID: mismatchMsgID, - body: exactOutboundLayerRPCBody(t, tg.LayerProfile227, &tg.ChannelsJoinChannelRequest{ + body: exactOutboundLayerRPCBody(t, tlprofile.Profile227, &tg.ChannelsJoinChannelRequest{ Channel: &tg.InputChannelEmpty{}, }), layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, @@ -1402,7 +1407,7 @@ func TestLiveConnectionKeepsFrozenLayerUntilItsOwnExplicitCorrection(t *testing. 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 { + if state, raw, msgID := connA.layerProfileRawEvidenceState(); state.Profile != tlprofile.Profile225 || raw != 225 || msgID != oldMsgID { t.Fatalf("failed naked correction mutated A = state:%#v raw:%d msg:%d", state, raw, msgID) } @@ -1418,10 +1423,10 @@ func TestLiveConnectionKeepsFrozenLayerUntilItsOwnExplicitCorrection(t *testing. 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 { + if state, raw, msgID := connA.layerProfileRawEvidenceState(); state.Profile != tlprofile.Profile227 || 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 { + if profile, ok := edgeA.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, correctionMsgID); !ok || profile != tlprofile.Profile227 { t.Fatalf("corrected admission profile = (%d,%v), want 227", profile, ok) } if len(correctionPlan.rpcTasks) != 1 { @@ -1431,7 +1436,7 @@ func TestLiveConnectionKeepsFrozenLayerUntilItsOwnExplicitCorrection(t *testing. t.Fatal(err) } requestProfile, resultProfile := handlerA.profiles() - if requestProfile != tg.LayerProfile227 || resultProfile != tg.LayerProfile227 { + if requestProfile != tlprofile.Profile227 || resultProfile != tlprofile.Profile227 { t.Fatalf("dispatch/result profiles = %d/%d, want 227/227", requestProfile, resultProfile) } } @@ -1488,7 +1493,7 @@ func TestExactSessionProfileSurvivesUnregisterAndSeedsNakedReplay(t *testing.T) if !ok || layer != 225 { t.Fatalf("reconnect seed = (%d,%v), want (225,true)", layer, ok) } - profile, ok := tg.ResolveLayerProfile(layer) + profile, ok := tlprofile.ResolveProfile(layer) if !ok { t.Fatalf("resolve retained profile %d", layer) } @@ -1500,7 +1505,7 @@ func TestExactSessionProfileSurvivesUnregisterAndSeedsNakedReplay(t *testing.T) if err != nil { t.Fatalf("same-session naked replay admission: %v", err) } - if method != "help.getConfig" || admitted.Call().Profile() != tg.LayerProfile225 { + if method != "help.getConfig" || admitted.Call().Profile() != tlprofile.Profile225 { t.Fatalf("naked replay = method:%q profile:%d", method, admitted.Call().Profile()) } } @@ -1523,7 +1528,7 @@ func TestSameAuthKeyNewSessionRequiresOwnLayerEvidence(t *testing.T) { if err != nil { t.Fatalf("Bob session layer 227: %v", err) } - if bobRequest.Call().Profile() != tg.LayerProfile227 { + if bobRequest.Call().Profile() != tlprofile.Profile227 { t.Fatalf("Bob profile = %d, want 227", bobRequest.Call().Profile()) } @@ -1532,7 +1537,7 @@ func TestSameAuthKeyNewSessionRequiresOwnLayerEvidence(t *testing.T) { Peer: &tg.InputPeerSelf{}, Limit: 1, } - naked228 := exactOutboundLayerRPCBody(t, tg.LayerProfile228, profileDependent) + naked228 := exactOutboundLayerRPCBody(t, tlprofile.Profile228, profileDependent) if _, _, err := s.admitInboundLayerRPC(aliceConn, naked228); err == nil { t.Fatal("new session inherited another session's Layer for naked application RPC") } @@ -1551,7 +1556,7 @@ func TestSameAuthKeyNewSessionRequiresOwnLayerEvidence(t *testing.T) { if err != nil { t.Fatalf("Alice session own layer 228 evidence: %v", err) } - if aliceRequest.Call().Profile() != tg.LayerProfile228 { + if aliceRequest.Call().Profile() != tlprofile.Profile228 { t.Fatalf("Alice profile = %d, want 228", aliceRequest.Call().Profile()) } if layer, ok := router.NegotiatedSessionLayer(authKeyID, bobSession); !ok || layer != 227 { @@ -1573,7 +1578,7 @@ func TestExactSessionRegistryAllowsOrderedExplicitCorrection(t *testing.T) { // 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 { + if err := c.SeedLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } wrapped := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{ @@ -1584,10 +1589,10 @@ func TestExactSessionRegistryAllowsOrderedExplicitCorrection(t *testing.T) { if err != nil { t.Fatalf("profile correction: %v", err) } - if request.Call().Profile() != tg.LayerProfile227 { + if request.Call().Profile() != tlprofile.Profile227 { t.Fatalf("corrected request profile = %d", request.Call().Profile()) } - if got := c.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileExplicit || got.Epoch < 2 { + if got := c.LayerProfileState(); got.Profile != tlprofile.Profile227 || got.Origin != LayerProfileExplicit || got.Epoch < 2 { t.Fatalf("corrected Conn profile = %#v", got) } if layer, ok := router.NegotiatedSessionLayer(authKeyID, sessionID); !ok || layer != 227 { @@ -1599,17 +1604,17 @@ 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 { + if err := c.SeedLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } request := &tg.ChannelsJoinChannelRequest{Channel: &tg.InputChannelEmpty{}} - naked227 := exactOutboundLayerRPCBody(t, tg.LayerProfile227, request) + naked227 := exactOutboundLayerRPCBody(t, tlprofile.Profile227, 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 { + if got := c.LayerProfileState(); got.Profile != tlprofile.Profile225 || got.Origin != LayerProfileExplicit { t.Fatalf("failed naked admission changed profile = %#v", got) } @@ -1618,10 +1623,10 @@ func TestRestoredExplicitProfileNakedFailureRequestsLayerCorrection(t *testing.T if err != nil { t.Fatalf("explicit correction retry: %v", err) } - if admitted.Call().Profile() != tg.LayerProfile227 { + if admitted.Call().Profile() != tlprofile.Profile227 { t.Fatalf("corrected call profile = %d", admitted.Call().Profile()) } - if got := c.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileExplicit || got.Epoch < 2 { + if got := c.LayerProfileState(); got.Profile != tlprofile.Profile227 || got.Origin != LayerProfileExplicit || got.Epoch < 2 { t.Fatalf("corrected profile = %#v", got) } } @@ -1675,9 +1680,9 @@ func TestUnprofiledInvariantBindKeepsProfileUnknownAndReturnsExactBool(t *testin if err := envelope.Decode(&bin.Buffer{Buf: encoded.body}); err != nil { t.Fatal(err) } - for _, profile := range []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227} { + for _, profile := range []tlprofile.Profile{tlprofile.Profile225, tlprofile.Profile227} { inner := bin.Buffer{Buf: append([]byte(nil), envelope.Result...)} - decoded, err := tg.DecodeLayer(profile, tg.LayerClassBoolType(), &inner) + decoded, err := tlprofile.DecodeObject(profile, &inner, tlprofile.Limits{}) if err != nil { t.Fatalf("decode invariant Bool at layer %d: %v", profile, err) } @@ -1688,13 +1693,13 @@ func TestUnprofiledInvariantBindKeepsProfileUnknownAndReturnsExactBool(t *testin // 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 { + if err := c.FreezeLayerProfile(tlprofile.Profile225); 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) + profiledBody := exactOutboundLayerRPCBody(t, tlprofile.Profile225, bind) profiled, _, err := s.admitInboundLayerRPC(c, profiledBody) if err != nil { t.Fatal(err) @@ -1714,13 +1719,13 @@ func TestLayerRPCBatchCapacityKeepsExistingPendingReplay(t *testing.T) { metrics: NopMetrics{}, } c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) - if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile225); 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{}) + admitted, err := router.AdmitLayer(tlprofile.Profile225, identityBuffer, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -1768,7 +1773,7 @@ func TestLayerRPCBatchCapacityAbortsRejectedRewrapOwner(t *testing.T) { sessionID = int64(779) msgID = int64(900) ) - identity := rpcFlightExactIdentity(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + identity := rpcFlightExactIdentity(t, tlprofile.Profile225, &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) @@ -1819,7 +1824,7 @@ func TestLayerRPCDependencyGateUsesBusinessOutcome(t *testing.T) { MsgID: test.dependency, Query: &tg.HelpGetConfigRequest{}, }) - admitted, err := router.AdmitLayer(tg.LayerProfile225, &bin.Buffer{Buf: body}, tg.LayerDecodeLimits{}) + admitted, err := router.AdmitLayer(tlprofile.Profile225, &bin.Buffer{Buf: body}, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -1847,7 +1852,7 @@ func TestLayerRPCDependencyGateUsesBusinessOutcome(t *testing.T) { MsgID: 300, Query: &tg.HelpGetConfigRequest{}, }) - missing, err := router.AdmitLayer(tg.LayerProfile225, &bin.Buffer{Buf: missingBody}, tg.LayerDecodeLimits{}) + missing, err := router.AdmitLayer(tlprofile.Profile225, &bin.Buffer{Buf: missingBody}, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -1874,12 +1879,12 @@ func TestLayerRPCTimeoutMessageDistinguishesDependencyWait(t *testing.T) { } func TestLayerRPCAdmissionErrorUsesTypedUnknownClassification(t *testing.T) { - err := &tg.LayerCodecError{ + err := &tlprofile.LayerCodecError{ Operation: "admit RPC request", - Profile: tg.LayerProfile225, + Profile: tlprofile.Profile225, WireID: 0x01020304, Reason: "wording may change", - Cause: tg.ErrLayerUnknownRPCMethod, + Cause: tlprofile.ErrUnknownRPCMethod, } rpcErr := layerRPCAdmissionError(err) if rpcErr.ErrorCode != 501 || rpcErr.ErrorMessage != "NOT_IMPLEMENTED" { @@ -1888,11 +1893,11 @@ func TestLayerRPCAdmissionErrorUsesTypedUnknownClassification(t *testing.T) { } func TestLayerRPCAdmissionErrorDistinguishesUnknownAndInheritedProfiles(t *testing.T) { - profileRequired := &tg.LayerCodecError{Operation: "admit", Cause: tg.ErrLayerProfileRequired} + profileRequired := &tlprofile.LayerCodecError{Operation: "admit", Cause: tlprofile.ErrProfileRequired} 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) + inherited := fmt.Errorf("%w: %w", errDefaultLayerAdmission, tlprofile.ErrUnknownRPCMethod) 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 3fafe7c2..256fa120 100644 --- a/internal/mtprotoedge/inbound_preflight.go +++ b/internal/mtprotoedge/inbound_preflight.go @@ -13,7 +13,7 @@ import ( "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/mt" "github.com/iamxvbaba/td/proto" - "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) type inboundItemKind uint8 @@ -58,7 +58,7 @@ type inboundItem struct { content bool body []byte payload any - admitted tg.LayerRequest + admitted tlprofile.Admission method string replayAfterSuccessfulDelivery func() error layerProfileEvidenceFreshness inboundLayerProfileEvidenceFreshness @@ -108,7 +108,7 @@ func (p *inboundPlan) close() { // 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{} + p.items[i].admitted = tlprofile.Admission{} } for i := range p.rpcTasks { p.rpcTasks[i] = inboundRPC{} diff --git a/internal/mtprotoedge/layer_admission_budget_test.go b/internal/mtprotoedge/layer_admission_budget_test.go index f7483cbb..3202a7c9 100644 --- a/internal/mtprotoedge/layer_admission_budget_test.go +++ b/internal/mtprotoedge/layer_admission_budget_test.go @@ -14,6 +14,7 @@ import ( "github.com/iamxvbaba/td/tg" "go.uber.org/zap/zaptest" + "github.com/iamxvbaba/td/tlprofile" appfiles "telesrv/internal/app/files" "telesrv/internal/rpc" ) @@ -102,17 +103,17 @@ func (h *failingReplayLayerRPC) PrepareAdmittedReplay( int64, int64, uint64, - tg.LayerRequest, + tlprofile.Admission, ) (func() error, error) { return nil, h.err } -func (h *countingLayerRPCAdmission) AdmitLayer(profile tg.LayerProfile, b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) { +func (h *countingLayerRPCAdmission) AdmitLayer(profile tlprofile.Profile, b *bin.Buffer, limits tlprofile.Limits) (tlprofile.Admission, 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) { +func (h *countingLayerRPCAdmission) AdmitUnprofiled(b *bin.Buffer, limits tlprofile.Limits) (tlprofile.Admission, error) { h.decodeCalls.Add(1) return h.LayerRPCHandler.AdmitUnprofiled(b, limits) } @@ -166,13 +167,13 @@ func TestLayerRPCAdmissionTransfersOriginalReservationToFreshOwner(t *testing.T) 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 { + if err := c.FreezeLayerProfile(tlprofile.Profile225); 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{}) + fresh := exactOutboundLayerRPCBody(t, tlprofile.Profile225, &tg.HelpGetConfigRequest{}) plan := &inboundPlan{items: []inboundItem{ {kind: inboundItemRPC, msgID: 100, body: bad}, {kind: inboundItemRPC, msgID: 104, body: fresh}, @@ -211,13 +212,13 @@ func TestLayerRPCAdmissionPendingReplayReleasesProvisionalEntry(t *testing.T) { 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 { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } - pendingBody := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + pendingBody := exactOutboundLayerRPCBody(t, tlprofile.Profile225, &tg.HelpGetConfigRequest{}) identityBuffer := &bin.Buffer{Buf: append([]byte(nil), pendingBody...)} - pendingRequest, err := router.AdmitLayer(tg.LayerProfile225, identityBuffer, tg.LayerDecodeLimits{}) + pendingRequest, err := router.AdmitLayer(tlprofile.Profile225, identityBuffer, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -226,7 +227,7 @@ func TestLayerRPCAdmissionPendingReplayReleasesProvisionalEntry(t *testing.T) { t.Fatalf("pending owner = %v, %v", pending.owner, err) } - freshBody := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetNearestDCRequest{}) + freshBody := exactOutboundLayerRPCBody(t, tlprofile.Profile225, &tg.HelpGetNearestDCRequest{}) plan := &inboundPlan{items: []inboundItem{ {kind: inboundItemRPC, msgID: 100, body: pendingBody}, {kind: inboundItemRPC, msgID: 104, body: freshBody}, @@ -253,12 +254,12 @@ func TestLayerRPCAdmissionCompletedReplayReleasesWholeProvisionalBatch(t *testin 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 { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } - body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + body := exactOutboundLayerRPCBody(t, tlprofile.Profile225, &tg.HelpGetConfigRequest{}) identityBuffer := &bin.Buffer{Buf: append([]byte(nil), body...)} - request, err := router.AdmitLayer(tg.LayerProfile225, identityBuffer, tg.LayerDecodeLimits{}) + request, err := router.AdmitLayer(tlprofile.Profile225, identityBuffer, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -299,12 +300,12 @@ func TestLayerRPCAdmissionReplayPreparationErrorIsNotSilentlyDelivered(t *testin }}) 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 { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } - body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + body := exactOutboundLayerRPCBody(t, tlprofile.Profile225, &tg.HelpGetConfigRequest{}) identityBuffer := &bin.Buffer{Buf: append([]byte(nil), body...)} - request, err := router.AdmitLayer(tg.LayerProfile225, identityBuffer, tg.LayerDecodeLimits{}) + request, err := router.AdmitLayer(tlprofile.Profile225, identityBuffer, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -343,12 +344,12 @@ func TestLayerRPCAdmissionTransferredBatchClosesWithoutLeak(t *testing.T) { 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 { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } plan := &inboundPlan{items: []inboundItem{{ kind: inboundItemRPC, msgID: 100, - body: exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}), + body: exactOutboundLayerRPCBody(t, tlprofile.Profile225, &tg.HelpGetConfigRequest{}), }}} defer plan.close() if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { @@ -378,10 +379,10 @@ func TestLayerRPCAdmissionTransferredBatchCommitsConservativeCharge(t *testing.T 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 { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } - body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + body := exactOutboundLayerRPCBody(t, tlprofile.Profile225, &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 { @@ -418,10 +419,10 @@ func TestLayerRPCAdmissionLocalDuplicateConsumesNoProvisionalEntry(t *testing.T) 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 { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } - body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + body := exactOutboundLayerRPCBody(t, tlprofile.Profile225, &tg.HelpGetConfigRequest{}) plan := &inboundPlan{items: []inboundItem{ {kind: inboundItemDuplicate, msgID: 96, body: body}, {kind: inboundItemRPC, msgID: 100, body: body}, diff --git a/internal/mtprotoedge/layer_downgrade_test.go b/internal/mtprotoedge/layer_downgrade_test.go index 9514fd47..17ed8527 100644 --- a/internal/mtprotoedge/layer_downgrade_test.go +++ b/internal/mtprotoedge/layer_downgrade_test.go @@ -13,13 +13,13 @@ import ( "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "go.uber.org/zap/zaptest" ) type countingLayerRPCResult struct { - inner tg.LayerRPCResult - encodeCalls atomic.Int32 - prepareCalls atomic.Int32 + inner tlprofile.Result + encodeCalls atomic.Int32 } const ( @@ -27,15 +27,15 @@ const ( testChannelWireID228 uint32 = 0xd49f34c6 ) -func testChannelWireID(profile tg.LayerProfile) uint32 { - if profile == tg.LayerProfile228 { +func testChannelWireID(profile tlprofile.Profile) uint32 { + if profile == tlprofile.Profile228 { return testChannelWireID228 } return testChannelWireID227 } -func testOtherChannelWireID(profile tg.LayerProfile) uint32 { - if profile == tg.LayerProfile228 { +func testOtherChannelWireID(profile tlprofile.Profile) uint32 { + if profile == tlprofile.Profile228 { return testChannelWireID227 } return testChannelWireID228 @@ -55,28 +55,21 @@ func (r *countingLayerRPCResult) Encode(b *bin.Buffer) error { return r.inner.Encode(b) } -func (r *countingLayerRPCResult) Prepared() tg.LayerPreparedCall { return r.inner.Prepared() } +func (r *countingLayerRPCResult) Prepared() tlprofile.PreparedCall { 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 (r *countingLayerRPCResult) CanonicalValue() any { return r.inner.CanonicalValue() } func TestExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t *testing.T) { - for _, profile := range []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227, tg.LayerProfile228} { + for _, profile := range []tlprofile.Profile{tlprofile.Profile225, tlprofile.Profile227, tlprofile.Profile228} { t.Run(fmt.Sprintf("layer_%d", profile), func(t *testing.T) { testExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t, profile) }) } } -func testExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t *testing.T, profile tg.LayerProfile) { +func testExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t *testing.T, profile tlprofile.Profile) { t.Helper() diff := &tg.UpdatesDifference{ NewMessages: []tg.MessageClass{ @@ -95,23 +88,21 @@ func testExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t *testing.T, pro State: tg.UpdatesState{Pts: 2, Date: 1}, } - dispatcher := tg.NewServerDispatcher(nil) - dispatcher.OnUpdatesGetDifference(func(context.Context, *tg.UpdatesGetDifferenceRequest) (tg.UpdatesDifferenceClass, error) { + dispatcher := tlprofile.NewDispatcher() + if err := dispatcher.Register(tlprofile.SemanticMethodUpdatesGetDifference, func(context.Context, bin.Object) (any, error) { return diff, nil - }) - outbound, err := tg.PrepareLayerOutboundCall(profile, &tg.UpdatesGetDifferenceRequest{Pts: 1, Date: 1}) - if err != nil { + }); err != nil { t.Fatal(err) } var requestBody bin.Buffer - if err := outbound.Encode(&requestBody); err != nil { + if err := tlprofile.EncodeObject(profile, &tg.UpdatesGetDifferenceRequest{Pts: 1, Date: 1}, &requestBody); err != nil { t.Fatal(err) } - admitted, err := dispatcher.AdmitLayer(profile, &requestBody) + admitted, err := dispatcher.Admit(profile, &requestBody, tlprofile.Limits{}) if err != nil { t.Fatal(err) } - serverResult, err := dispatcher.DispatchAdmitted(context.Background(), admitted) + serverResult, err := dispatcher.Dispatch(context.Background(), admitted) if err != nil { t.Fatal(err) } @@ -124,9 +115,9 @@ func testExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t *testing.T, pro } // 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 + corrected := tlprofile.Profile227 + if profile == tlprofile.Profile227 { + corrected = tlprofile.Profile225 } if err := c.FreezeLayerProfile(corrected); err != nil { t.Fatal(err) @@ -136,14 +127,11 @@ func testExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t *testing.T, pro if err != nil { t.Fatalf("encode rpc_result: %v", err) } - 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 == nil || encoded.layer.profile != profile { + t.Fatalf("result binding = %#v, want profile %d", encoded.layer, profile) } if encoded.layer.kind != outboundLayerBindingRequest { t.Fatalf("exact RPC result binding kind = %d, want request-bound", encoded.layer.kind) @@ -171,7 +159,7 @@ func testExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t *testing.T, pro 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) + decoded, err := tlprofile.DecodeObject(profile, &inner, tlprofile.Limits{}) if err != nil { t.Fatalf("decode exact difference: %v", err) } @@ -199,27 +187,25 @@ func testExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t *testing.T, pro } func TestExactLayerRPCResultUsesHistoricalMethodResultType(t *testing.T) { - const profile = tg.LayerProfile225 - dispatcher := tg.NewServerDispatcher(nil) - dispatcher.OnChannelsJoinChannel(func(context.Context, tg.InputChannelClass) (tg.MessagesChatInviteJoinResultClass, error) { + const profile = tlprofile.Profile225 + dispatcher := tlprofile.NewDispatcher() + if err := dispatcher.Register(tlprofile.SemanticMethodChannelsJoinChannel, func(context.Context, bin.Object) (any, error) { return &tg.MessagesChatInviteJoinResultOk{Updates: &tg.UpdatesTooLong{}}, nil - }) - outbound, err := tg.PrepareLayerOutboundCall(profile, &tg.ChannelsJoinChannelRequest{Channel: &tg.InputChannelEmpty{}}) - if err != nil { + }); err != nil { t.Fatal(err) } var requestBody bin.Buffer - if err := outbound.Encode(&requestBody); err != nil { + if err := tlprofile.EncodeObject(profile, &tg.ChannelsJoinChannelRequest{Channel: &tg.InputChannelEmpty{}}, &requestBody); err != nil { t.Fatal(err) } - admitted, err := dispatcher.AdmitLayer(profile, &requestBody) + admitted, err := dispatcher.Admit(profile, &requestBody, tlprofile.Limits{}) if err != nil { t.Fatal(err) } if admitted.Call().WireID() == tg.ChannelsJoinChannelRequestTypeID { t.Fatal("historical request unexpectedly retained canonical method id") } - serverResult, err := dispatcher.DispatchAdmitted(context.Background(), admitted) + serverResult, err := dispatcher.Dispatch(context.Background(), admitted) if err != nil { t.Fatal(err) } @@ -237,7 +223,7 @@ func TestExactLayerRPCResultUsesHistoricalMethodResultType(t *testing.T) { t.Fatal(err) } inner := bin.Buffer{Buf: rpcEnvelope.Result} - updates, err := tg.DecodeLayer(profile, tg.LayerClassUpdatesType(), &inner) + updates, err := tlprofile.DecodeObject(profile, &inner, tlprofile.Limits{}) if err != nil { t.Fatalf("decode historical channels.joinChannel result: %v", err) } @@ -251,7 +237,7 @@ func TestExactLayerRPCResultUsesHistoricalMethodResultType(t *testing.T) { func TestProductionUnboundApplicationResultFailsClosedForLayer227(t *testing.T) { c := &Conn{metrics: NopMetrics{}} - if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile227); err != nil { t.Fatal(err) } encoded, err := (&Server{log: zaptest.NewLogger(t)}).encodeRPCResult(c, 12345, testLayerChannel()) @@ -265,7 +251,7 @@ func TestProductionUnboundApplicationResultFailsClosedForLayer227(t *testing.T) func TestProductionUnboundApplicationPushFailsClosedForLayer227(t *testing.T) { c := &Conn{metrics: NopMetrics{}} - if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile227); err != nil { t.Fatal(err) } frame, err := c.buildFrame(context.Background(), proto.MessageFromServer, testLayerChannelUpdatesValue(321), nil) diff --git a/internal/mtprotoedge/layer_profile_test.go b/internal/mtprotoedge/layer_profile_test.go index 26be2264..ec2081f5 100644 --- a/internal/mtprotoedge/layer_profile_test.go +++ b/internal/mtprotoedge/layer_profile_test.go @@ -7,7 +7,7 @@ import ( "sync" "testing" - "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) type countingInheritedLayerResolver struct { @@ -40,66 +40,66 @@ func TestConnLayerProfileUnknownFreezeAndIdempotence(t *testing.T) { t.Fatalf("initial LayerProfile = (%d, %v), want (0, false)", profile, ok) } - if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatalf("freeze layer 225: %v", err) } - if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatalf("repeat freeze layer 225: %v", err) } - if profile, ok := c.LayerProfile(); !ok || profile != tg.LayerProfile225 { + if profile, ok := c.LayerProfile(); !ok || profile != tlprofile.Profile225 { 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 { + if err := c.SeedInheritedLayerProfile(tlprofile.Profile225); err != nil { t.Fatalf("seed inherited layer 225: %v", err) } initial := c.LayerProfileState() - if initial.Profile != tg.LayerProfile225 || initial.Origin != LayerProfileInherited || initial.Epoch != 1 { + if initial.Profile != tlprofile.Profile225 || initial.Origin != LayerProfileInherited || initial.Epoch != 1 { t.Fatalf("initial inherited state = %#v", initial) } - if err := c.SeedInheritedLayerProfile(tg.LayerProfile226); err != nil { + if err := c.SeedInheritedLayerProfile(tlprofile.Profile226); 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 { + if err := c.FreezeLayerProfile(tlprofile.Profile225); 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 { + if promoted.Profile != tlprofile.Profile225 || promoted.Origin != LayerProfileExplicit || promoted.Epoch != initial.Epoch+1 { t.Fatalf("promoted explicit state = %#v", promoted) } - if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile227); 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 { + if corrected.Profile != tlprofile.Profile227 || 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 { + if err := c.SeedLayerProfile(tlprofile.Profile226); err != nil { t.Fatalf("seed layer 226: %v", err) } - if err := c.SeedLayerProfile(tg.LayerProfile226); err != nil { + if err := c.SeedLayerProfile(tlprofile.Profile226); err != nil { t.Fatalf("repeat seed layer 226: %v", err) } - if err := c.FreezeLayerProfile(tg.LayerProfile226); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile226); err != nil { t.Fatalf("freeze seeded layer 226: %v", err) } - if profile, ok := c.LayerProfile(); !ok || profile != tg.LayerProfile226 { + if profile, ok := c.LayerProfile(); !ok || profile != tlprofile.Profile226 { t.Fatalf("LayerProfile = (%d, %v), want (226, true)", profile, ok) } } func TestConnLayerProfileRejectsUnsupported(t *testing.T) { - for _, profile := range []tg.LayerProfile{0, 219, 229} { + for _, profile := range []tlprofile.Profile{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) { @@ -120,16 +120,16 @@ func TestConnLayerProfileConcurrentCorrectionsRemainAtomic(t *testing.T) { c := &Conn{} start := make(chan struct{}) errs := make([]error, goroutines) - profiles := make([]tg.LayerProfile, goroutines) + profiles := make([]tlprofile.Profile, goroutines) var wg sync.WaitGroup wg.Add(goroutines) for i := range goroutines { - profile := tg.LayerProfile225 + profile := tlprofile.Profile225 if i%2 != 0 { - profile = tg.LayerProfile227 + profile = tlprofile.Profile227 } profiles[i] = profile - go func(index int, requested tg.LayerProfile) { + go func(index int, requested tlprofile.Profile) { defer wg.Done() <-start errs[index] = c.FreezeLayerProfile(requested) @@ -139,7 +139,7 @@ func TestConnLayerProfileConcurrentCorrectionsRemainAtomic(t *testing.T) { wg.Wait() state := c.LayerProfileState() - if state.Origin != LayerProfileExplicit || (state.Profile != tg.LayerProfile225 && state.Profile != tg.LayerProfile227) { + if state.Origin != LayerProfileExplicit || (state.Profile != tlprofile.Profile225 && state.Profile != tlprofile.Profile227) { t.Fatalf("concurrent final state = %#v, want supported explicit contender", state) } if state.Epoch == 0 || state.Epoch > goroutines { @@ -154,23 +154,23 @@ func TestConnLayerProfileConcurrentCorrectionsRemainAtomic(t *testing.T) { func TestConnLayerProfileEvidenceUsesClientMessageOrder(t *testing.T) { c := &Conn{} - if err := c.seedOrderedLayerProfile(tg.LayerProfile225, 100); err != nil { + if err := c.seedOrderedLayerProfile(tlprofile.Profile225, 100); err != nil { t.Fatal(err) } - if applied, err := c.FreezeLayerProfileAt(tg.LayerProfile227, 104); err != nil || !applied { + if applied, err := c.FreezeLayerProfileAt(tlprofile.Profile227, 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 { + if applied, err := c.FreezeLayerProfileAt(tlprofile.Profile225, 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 { + if applied, err := c.FreezeLayerProfileAt(tlprofile.Profile225, 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 { + if applied, err := c.FreezeLayerProfileAt(tlprofile.Profile227, 108); err != nil || !applied { t.Fatalf("same-layer newer evidence applied=%v err=%v", applied, err) } state, msgID := c.layerProfileEvidenceState() @@ -185,10 +185,10 @@ func TestSessionManagerSeedsOnlyUnknownRawAuthKeyConnections(t *testing.T) { 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 { + if err := explicit.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } - if err := inherited.SeedInheritedLayerProfile(tg.LayerProfile226); err != nil { + if err := inherited.SeedInheritedLayerProfile(tlprofile.Profile226); err != nil { t.Fatal(err) } for _, c := range []*Conn{unknown, explicit, inherited} { @@ -200,13 +200,13 @@ func TestSessionManagerSeedsOnlyUnknownRawAuthKeyConnections(t *testing.T) { 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 { + if got := unknown.LayerProfileState(); got.Profile != tlprofile.Profile227 || got.Origin != LayerProfileInherited { t.Fatalf("unknown connection seed = %#v", got) } - if got := explicit.LayerProfileState(); got.Profile != tg.LayerProfile225 || got.Origin != LayerProfileExplicit { + if got := explicit.LayerProfileState(); got.Profile != tlprofile.Profile225 || got.Origin != LayerProfileExplicit { t.Fatalf("explicit connection was overwritten = %#v", got) } - if got := inherited.LayerProfileState(); got.Profile != tg.LayerProfile226 || got.Origin != LayerProfileInherited { + if got := inherited.LayerProfileState(); got.Profile != tlprofile.Profile226 || got.Origin != LayerProfileInherited { t.Fatalf("existing inherited connection was overwritten = %#v", got) } if seeded := m.SeedInheritedLayerForRawAuthKey(authKeyID, 229); seeded != 0 { @@ -220,10 +220,10 @@ func TestSessionManagerRefreshesInheritedRawKeyShadowAtBind(t *testing.T) { 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 { + if err := inherited.SeedInheritedLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } - if err := explicit.FreezeLayerProfile(tg.LayerProfile225); err != nil { + if err := explicit.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } for _, c := range []*Conn{unknown, inherited, explicit} { @@ -236,11 +236,11 @@ func TestSessionManagerRefreshesInheritedRawKeyShadowAtBind(t *testing.T) { 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 { + if got := c.LayerProfileState(); got.Profile != tlprofile.Profile227 || got.Origin != LayerProfileInherited { t.Fatalf("%s refresh = %#v", name, got) } } - if got := explicit.LayerProfileState(); got.Profile != tg.LayerProfile225 || got.Origin != LayerProfileExplicit { + if got := explicit.LayerProfileState(); got.Profile != tlprofile.Profile225 || got.Origin != LayerProfileExplicit { t.Fatalf("explicit evidence overwritten = %#v", got) } } @@ -251,10 +251,10 @@ func TestSessionManagerClearsOnlyInheritedRawKeyShadowAtBind(t *testing.T) { 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 { + if err := inherited.SeedInheritedLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } - if err := explicit.seedOrderedLayerProfile(tg.LayerProfile227, 104); err != nil { + if err := explicit.seedOrderedLayerProfile(tlprofile.Profile227, 104); err != nil { t.Fatal(err) } for _, c := range []*Conn{inherited, explicit, unknown} { @@ -269,7 +269,7 @@ func TestSessionManagerClearsOnlyInheritedRawKeyShadowAtBind(t *testing.T) { 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 { + if got := explicit.LayerProfileState(); got.Profile != tlprofile.Profile227 || got.Origin != LayerProfileExplicit { t.Fatalf("explicit evidence was cleared = %#v", got) } if state, msgID := explicit.layerProfileEvidenceState(); state.Origin != LayerProfileExplicit || msgID != 104 { @@ -292,10 +292,10 @@ func TestSessionManagerSeedsUnknownSessionsAcrossBusinessAuthKey(t *testing.T) { 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 { + if err := explicit.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } - if err := inherited.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + if err := inherited.SeedInheritedLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } for _, c := range []*Conn{first, second, explicit, inherited} { @@ -308,14 +308,14 @@ func TestSessionManagerSeedsUnknownSessionsAcrossBusinessAuthKey(t *testing.T) { 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 { + if got := c.LayerProfileState(); got.Profile != tlprofile.Profile227 || got.Origin != LayerProfileInherited { t.Fatalf("%s business default = %#v", name, got) } } - if got := explicit.LayerProfileState(); got.Profile != tg.LayerProfile225 || got.Origin != LayerProfileExplicit { + if got := explicit.LayerProfileState(); got.Profile != tlprofile.Profile225 || got.Origin != LayerProfileExplicit { t.Fatalf("business seed overwrote explicit = %#v", got) } - if got := inherited.LayerProfileState(); got.Profile != tg.LayerProfile225 || got.Origin != LayerProfileInherited { + if got := inherited.LayerProfileState(); got.Profile != tlprofile.Profile225 || got.Origin != LayerProfileInherited { t.Fatalf("business seed overwrote inherited = %#v", got) } } @@ -325,7 +325,7 @@ func TestSessionManagerExplicitLayerEvidenceUsesLiveExactSession(t *testing.T) { 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 { + if err := c.seedOrderedLayerProfile(tlprofile.Profile226, 1234); err != nil { t.Fatal(err) } if err := m.Register(c); err != nil { @@ -336,7 +336,7 @@ func TestSessionManagerExplicitLayerEvidenceUsesLiveExactSession(t *testing.T) { } inherited := &Conn{authKeyID: authKeyID, sessionID: sessionID + 1} - if err := inherited.SeedInheritedLayerProfile(tg.LayerProfile227); err != nil { + if err := inherited.SeedInheritedLayerProfile(tlprofile.Profile227); err != nil { t.Fatal(err) } if err := m.Register(inherited); err != nil { @@ -353,10 +353,10 @@ func TestSessionManagerExplicitLayerEvidenceChoosesNewestActiveOrClaim(t *testin 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 { + if err := active.seedOrderedLayerProfile(tlprofile.Profile225, 100); err != nil { t.Fatal(err) } - if err := claim.seedOrderedLayerProfile(tg.LayerProfile227, 104); err != nil { + if err := claim.seedOrderedLayerProfile(tlprofile.Profile227, 104); err != nil { t.Fatal(err) } key := sessionKey{authKeyID: authKeyID, sessionID: sessionID} @@ -384,15 +384,15 @@ func TestOrderedSessionLayerBroadcastConvergesAcrossPhysicalGenerations(t *testi 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 { + if applied, err := m.ApplyOrderedLayerProfileForSession(oldPhysical, authKeyID, sessionID, tlprofile.Profile227, 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 { + if applied, err := m.ApplyOrderedLayerProfileForSession(oldPhysical, authKeyID, sessionID, tlprofile.Profile225, 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 { + if state.Profile != tlprofile.Profile227 || state.Origin != LayerProfileExplicit || msgID != 300 { t.Fatalf("%s physical state = %#v msgID:%d", name, state, msgID) } } @@ -409,7 +409,7 @@ func TestInitialProfileSeedAvoidsPermanentKeyResolverAndPrefersPermForTemp(t *te 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 { + if got := c.LayerProfileState(); got.Profile != tlprofile.Profile227 || got.Origin != LayerProfileInherited { t.Fatalf("permanent seed = %#v", got) } }) @@ -424,7 +424,7 @@ func TestInitialProfileSeedAvoidsPermanentKeyResolverAndPrefersPermForTemp(t *te 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 { + if got := c.LayerProfileState(); got.Profile != tlprofile.Profile227 || got.Origin != LayerProfileInherited { t.Fatalf("temporary canonical seed = %#v", got) } }) @@ -465,7 +465,7 @@ func TestInitialProfileSeedRestoresOrderedExactSessionEvidence(t *testing.T) { t.Fatal(err) } state, msgID := c.layerProfileEvidenceState() - if state.Profile != tg.LayerProfile226 || state.Origin != LayerProfileExplicit || msgID != resolver.msgID { + if state.Profile != tlprofile.Profile226 || state.Origin != LayerProfileExplicit || msgID != resolver.msgID { t.Fatalf("ordered exact seed = state:%#v msgID:%d", state, msgID) } } @@ -487,10 +487,10 @@ func TestInheritedLayerResolverAvailabilityUsesOnlySupportedRawTempShadow(t *tes for _, tt := range []struct { name string fetchedLayer int - wantProfile tg.LayerProfile + wantProfile tlprofile.Profile wantOrigin LayerProfileOrigin }{ - {name: "supported raw shadow", fetchedLayer: 225, wantProfile: tg.LayerProfile225, wantOrigin: LayerProfileInherited}, + {name: "supported raw shadow", fetchedLayer: 225, wantProfile: tlprofile.Profile225, wantOrigin: LayerProfileInherited}, {name: "future raw shadow stays unknown", fetchedLayer: 229, wantOrigin: LayerProfileUnknown}, } { t.Run(tt.name, func(t *testing.T) { @@ -529,7 +529,7 @@ func TestActivationClaimRecheckClosesTempBindLayerRace(t *testing.T) { if err := s.refreshActivatedInheritedLayerProfile(context.Background(), c, 225); err != nil { t.Fatal(err) } - if got := c.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileInherited { + if got := c.LayerProfileState(); got.Profile != tlprofile.Profile227 || got.Origin != LayerProfileInherited { t.Fatalf("post-claim permanent recheck = %#v", got) } }) @@ -537,7 +537,7 @@ func TestActivationClaimRecheckClosesTempBindLayerRace(t *testing.T) { 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 { + if err := c.SeedInheritedLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } if err := m.BeginActivation(c); err != nil { @@ -547,7 +547,7 @@ func TestActivationClaimRecheckClosesTempBindLayerRace(t *testing.T) { 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 { + if got := c.LayerProfileState(); got.Profile != tlprofile.Profile227 || got.Origin != LayerProfileInherited { t.Fatalf("claim-visible bind refresh = %#v", got) } }) @@ -556,7 +556,7 @@ func TestActivationClaimRecheckClosesTempBindLayerRace(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 { + if err := c.SeedInheritedLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } if err := s.refreshActivatedInheritedLayerProfile(context.Background(), c, 225); err != nil { @@ -574,7 +574,7 @@ func TestActivationClaimRecheckClosesTempBindLayerRace(t *testing.T) { if err := s.refreshActivatedInheritedLayerProfile(context.Background(), c, 225); err != nil { t.Fatal(err) } - if got := c.LayerProfileState(); got.Profile != tg.LayerProfile225 || got.Origin != LayerProfileInherited { + if got := c.LayerProfileState(); got.Profile != tlprofile.Profile225 || got.Origin != LayerProfileInherited { t.Fatalf("availability recheck lost raw shadow = %#v", got) } }) @@ -583,7 +583,7 @@ func TestActivationClaimRecheckClosesTempBindLayerRace(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 { + if err := c.SeedInheritedLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } if err := s.refreshActivatedInheritedLayerProfile(context.Background(), c, 225); err != nil { diff --git a/internal/mtprotoedge/layer_rpc_execution.go b/internal/mtprotoedge/layer_rpc_execution.go index 7e075c7d..cd7bb19c 100644 --- a/internal/mtprotoedge/layer_rpc_execution.go +++ b/internal/mtprotoedge/layer_rpc_execution.go @@ -7,10 +7,10 @@ import ( "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/mt" - "github.com/iamxvbaba/td/tg" "github.com/iamxvbaba/td/tgerr" "go.uber.org/zap" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/observability/dbtrace" "telesrv/internal/postresponse" ) @@ -20,8 +20,8 @@ import ( // 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 + call tlprofile.Call + result tlprofile.Result } func (e *layerRPCResultEncoder) Encode(b *bin.Buffer) error { @@ -40,7 +40,6 @@ func (e *layerRPCResultEncoder) exactLayerRPCResultBinding() outboundLayerBindin } return outboundLayerBinding{ profile: e.call.Profile(), - typ: e.call.WireResultType(), wireInvariant: e.call.WireInvariant(), kind: outboundLayerBindingRequest, } @@ -55,7 +54,7 @@ type exactLayerRPCResultEncoder interface { // 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 + call tlprofile.Call result bin.Encoder } @@ -63,7 +62,7 @@ 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) + return e.result.Encode(b) } func (e *legacyTestRPCResultEncoder) exactLayerRPCResultBinding() outboundLayerBinding { @@ -72,7 +71,6 @@ func (e *legacyTestRPCResultEncoder) exactLayerRPCResultBinding() outboundLayerB } return outboundLayerBinding{ profile: e.call.Profile(), - typ: e.call.WireResultType(), wireInvariant: e.call.WireInvariant(), kind: outboundLayerBindingRequest, } @@ -85,7 +83,7 @@ var errLayerRPCResultIdentityMismatch = errors.New("layer RPC result does not ma // 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) { +func bindAdmittedLayerRPCResult(request tlprofile.Admission, result tlprofile.Result) (*layerRPCResultEncoder, error) { if result == nil { return nil, nil } @@ -101,7 +99,7 @@ func (s *Server) newInboundLayerRPCTask( admissionSeq uint64, method string, profileEvidenceFresh bool, - request tg.LayerRequest, + request tlprofile.Admission, dependencies layerRPCDependencySet, owner *rpcResultOwnerLease, ) inboundRPC { @@ -202,7 +200,7 @@ func (s *Server) handleAdmittedLayerRPC( msgID int64, admissionSeq uint64, method string, - request tg.LayerRequest, + request tlprofile.Admission, owner *rpcResultOwnerLease, ) error { if s.layerRPC == nil { diff --git a/internal/mtprotoedge/layer_rpc_execution_test.go b/internal/mtprotoedge/layer_rpc_execution_test.go index 97f31875..8e0ef6a4 100644 --- a/internal/mtprotoedge/layer_rpc_execution_test.go +++ b/internal/mtprotoedge/layer_rpc_execution_test.go @@ -11,24 +11,25 @@ import ( "github.com/iamxvbaba/td/mt" "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) // 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 + tlprofile.Result + prepared tlprofile.PreparedCall } -func (r *preparedOnlyLayerRPCResult) Prepared() tg.LayerPreparedCall { return r.prepared } +func (r *preparedOnlyLayerRPCResult) Prepared() tlprofile.PreparedCall { return r.prepared } func TestBindAdmittedLayerRPCResultRequiresExactRequestIdentity(t *testing.T) { - dispatcher := tg.NewServerDispatcher(nil) - admit := func(request bin.Encoder) tg.LayerRequest { + dispatcher := tlprofile.NewDispatcher() + admit := func(request bin.Encoder) tlprofile.Admission { t.Helper() body := &bin.Buffer{Buf: exactLayerRPCBody(t, request)} - admitted, err := dispatcher.AdmitLayer(tg.LayerProfile227, body) + admitted, err := dispatcher.Admit(tlprofile.Profile227, body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -53,7 +54,7 @@ func TestBindAdmittedLayerRPCResultRequiresExactRequestIdentity(t *testing.T) { type mismatchedProjectionLayerRPC struct { *admissionOnlyLayerRPC - result tg.LayerRPCResult + result tlprofile.Result calls atomic.Int32 } @@ -63,18 +64,18 @@ func (h *mismatchedProjectionLayerRPC) DispatchAdmitted( int64, int64, uint64, - tg.LayerRequest, -) (tg.LayerRPCResult, string, error) { + tlprofile.Admission, +) (tlprofile.Result, 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 { + dispatcher := tlprofile.NewDispatcher() + admit := func(request bin.Encoder) tlprofile.Admission { t.Helper() body := &bin.Buffer{Buf: exactLayerRPCBody(t, request)} - admitted, err := dispatcher.AdmitLayer(tg.LayerProfile227, body) + admitted, err := dispatcher.Admit(tlprofile.Profile227, body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -93,7 +94,7 @@ func TestProjectionFailureCachesInternalWithoutRepeatingBusiness(t *testing.T) { const reqMsgID = int64(410100) claim, err := s.rpcResults.AcquireLayerIdentified( c.authKeyID, c.sessionID, reqMsgID, - tg.LayerProfile227, request.Prepared().Identity(), + tlprofile.Profile227, request.Prepared().Identity(), ) if err != nil || claim.owner == nil { t.Fatalf("owner acquisition err=%v", err) @@ -110,7 +111,7 @@ func TestProjectionFailureCachesInternalWithoutRepeatingBusiness(t *testing.T) { for { completed, err = s.rpcResults.AcquireLayerIdentified( c.authKeyID, c.sessionID, reqMsgID, - tg.LayerProfile227, request.Prepared().Identity(), + tlprofile.Profile227, request.Prepared().Identity(), ) if err == nil && completed.state == rpcResultAcquireCompleted { break @@ -142,7 +143,7 @@ func TestProjectionFailureCachesInternalWithoutRepeatingBusiness(t *testing.T) { // success. replay, err := s.rpcResults.AcquireLayerIdentified( c.authKeyID, c.sessionID, reqMsgID, - tg.LayerProfile227, request.Prepared().Identity(), + tlprofile.Profile227, request.Prepared().Identity(), ) if err != nil || replay.state != rpcResultAcquireCompleted || replay.encoded != completed.encoded { t.Fatalf("projection replay = state:%d err:%v", replay.state, err) diff --git a/internal/mtprotoedge/layer_updates.go b/internal/mtprotoedge/layer_updates.go index f427325a..055efb21 100644 --- a/internal/mtprotoedge/layer_updates.go +++ b/internal/mtprotoedge/layer_updates.go @@ -8,6 +8,7 @@ import ( "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) var ( @@ -36,8 +37,7 @@ const ( ) type outboundLayerBinding struct { - profile tg.LayerProfile - typ *tg.LayerTypeRef + profile tlprofile.Profile wireInvariant bool kind outboundLayerBindingKind // epoch is required for proactive updates. Zero is accepted only for older @@ -52,26 +52,26 @@ type preparedLayerUpdates struct { } // 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 +// request-scoped cache of exact prepared bytes. FreezeObject and +// FrozenObject.Prepare use the same sparse TypeRef execution plans as RPC results // and differences; this type adds only fan-out singleflight and ownership. type layerUpdatesFanout struct { - frozen tg.LayerFrozen[tg.UpdatesClass] + frozen *tlprofile.FrozenObject size int mu sync.Mutex - prepared map[tg.LayerProfile]*preparedLayerUpdates + prepared map[tlprofile.Profile]*preparedLayerUpdates } func newLayerUpdatesFanout(value tg.UpdatesClass) (*layerUpdatesFanout, error) { - frozen, err := tg.FreezeLayer(tg.LayerClassUpdatesType(), value) + frozen, err := tlprofile.FreezeObject(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), + prepared: make(map[tlprofile.Profile]*preparedLayerUpdates), }, nil } @@ -107,7 +107,7 @@ func (u *layerUpdatesFanout) prepareForConn(ctx context.Context, c *Conn) (*enco return &encoded, nil } -func (u *layerUpdatesFanout) prepare(ctx context.Context, profile tg.LayerProfile) (*encodedOutboundMessage, error) { +func (u *layerUpdatesFanout) prepare(ctx context.Context, profile tlprofile.Profile) (*encodedOutboundMessage, error) { if ctx == nil { ctx = context.Background() } @@ -149,7 +149,7 @@ func (u *layerUpdatesFanout) prepare(ctx context.Context, profile tg.LayerProfil return entry.encoded, entry.err } -func (u *layerUpdatesFanout) discardPrepared(profile tg.LayerProfile, encoded *encodedOutboundMessage) { +func (u *layerUpdatesFanout) discardPrepared(profile tlprofile.Profile, encoded *encodedOutboundMessage) { if u == nil || encoded == nil { return } @@ -172,18 +172,13 @@ func (u *layerUpdatesFanout) discardPrepared(profile tg.LayerProfile, encoded *e func prepareFrozenLayerUpdatesContext( ctx context.Context, - profile tg.LayerProfile, - frozen tg.LayerFrozen[tg.UpdatesClass], + profile tlprofile.Profile, + frozen *tlprofile.FrozenObject, ) (*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 { + if err := frozen.Encode(profile, &body); err != nil { return err } id, err := body.PeekID() @@ -192,7 +187,7 @@ func prepareFrozenLayerUpdatesContext( } encoded = &encodedOutboundMessage{ body: body.Copy(), typeID: id, - layer: &outboundLayerBinding{profile: profile, typ: prepared.TypeRef()}, + layer: &outboundLayerBinding{profile: profile}, } return nil }) @@ -206,9 +201,6 @@ func validateOutboundLayerBinding(c *Conn, encoded *encodedOutboundMessage) erro 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 } diff --git a/internal/mtprotoedge/layer_updates_test.go b/internal/mtprotoedge/layer_updates_test.go index 12227cb0..ab4a4367 100644 --- a/internal/mtprotoedge/layer_updates_test.go +++ b/internal/mtprotoedge/layer_updates_test.go @@ -11,6 +11,7 @@ import ( "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) type epochBlockingTransport struct { @@ -65,7 +66,7 @@ func testLayerChannelUpdatesValue(expires int) tg.UpdatesClass { } } -func testConnWithLayerProfile(t *testing.T, profile tg.LayerProfile) *Conn { +func testConnWithLayerProfile(t *testing.T, profile tlprofile.Profile) *Conn { t.Helper() c := &Conn{} if err := c.FreezeLayerProfile(profile); err != nil { @@ -79,7 +80,7 @@ func TestLayerUpdatesFanoutPreparesExactMixedProfiles(t *testing.T) { if err != nil { t.Fatalf("freeze updates: %v", err) } - for _, profile := range []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227, tg.LayerProfile228} { + for _, profile := range []tlprofile.Profile{tlprofile.Profile225, tlprofile.Profile227, tlprofile.Profile228} { t.Run(fmt.Sprintf("layer_%d", profile), func(t *testing.T) { c := testConnWithLayerProfile(t, profile) encoded, err := fanout.prepareForConn(context.Background(), c) @@ -90,7 +91,7 @@ func TestLayerUpdatesFanoutPreparesExactMixedProfiles(t *testing.T) { t.Fatalf("binding = %#v, want profile %d", encoded.layer, profile) } input := bin.Buffer{Buf: encoded.body} - decoded, err := tg.DecodeLayer(profile, tg.LayerClassUpdatesType(), &input) + decoded, err := tlprofile.DecodeObject(profile, &input, tlprofile.Limits{}) if err != nil { t.Fatalf("decode profile %d: %v", profile, err) } @@ -121,7 +122,7 @@ func TestLayerUpdatesFanoutFreezesDefensivelyAndSharesPreparedProfile(t *testing } value.(*tg.UpdateShort).Update.(*tg.UpdateUserStatus).Status.(*tg.UserStatusOnline).Expires = 999 - c := testConnWithLayerProfile(t, tg.LayerProfile225) + c := testConnWithLayerProfile(t, tlprofile.Profile225) const workers = 16 prepared := make([]*encodedOutboundMessage, workers) prepareErrs := make([]error, workers) @@ -149,7 +150,7 @@ func TestLayerUpdatesFanoutFreezesDefensivelyAndSharesPreparedProfile(t *testing } input := bin.Buffer{Buf: prepared[0].body} - decoded, err := tg.DecodeLayer(tg.LayerProfile225, tg.LayerClassUpdatesType(), &input) + decoded, err := tlprofile.DecodeObject(tlprofile.Profile225, &input, tlprofile.Limits{}) if err != nil { t.Fatalf("decode frozen value: %v", err) } @@ -165,7 +166,7 @@ func TestLayerUpdatesEpochBecomesStaleWithoutRetiringProfile(t *testing.T) { t.Fatal(err) } c := &Conn{} - if err := c.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + if err := c.SeedInheritedLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } encoded, err := fanout.prepareForConn(context.Background(), c) @@ -173,14 +174,14 @@ func TestLayerUpdatesEpochBecomesStaleWithoutRetiringProfile(t *testing.T) { t.Fatal(err) } oldEpoch := encoded.layer.epoch - if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile227); 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 { + if state.Profile != tlprofile.Profile227 || state.Origin != LayerProfileExplicit || state.Epoch <= oldEpoch { t.Fatalf("corrected profile state = %#v, old epoch %d", state, oldEpoch) } } @@ -190,13 +191,13 @@ func TestRequestBoundLayerResultSurvivesConnectionCorrection(t *testing.T) { if err != nil { t.Fatal(err) } - c := testConnWithLayerProfile(t, tg.LayerProfile225) - encoded, err := fanout.prepare(context.Background(), tg.LayerProfile225) + c := testConnWithLayerProfile(t, tlprofile.Profile225) + encoded, err := fanout.prepare(context.Background(), tlprofile.Profile225) if err != nil { t.Fatal(err) } encoded.layer.kind = outboundLayerBindingRequest - if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile227); err != nil { t.Fatal(err) } if err := validateOutboundLayerBinding(c, encoded); err != nil { @@ -207,7 +208,7 @@ func TestRequestBoundLayerResultSurvivesConnectionCorrection(t *testing.T) { func TestProfileCorrectionLinearizesAfterStartedPushWrite(t *testing.T) { transport := newEpochBlockingTransport() c := newOutboundTestConn(t, transport, nil) - if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } fanout, err := newLayerUpdatesFanout(testLayerUpdatesValue(123)) @@ -228,7 +229,7 @@ func TestProfileCorrectionLinearizesAfterStartedPushWrite(t *testing.T) { } corrected := make(chan error, 1) - go func() { corrected <- c.FreezeLayerProfile(tg.LayerProfile227) }() + go func() { corrected <- c.FreezeLayerProfile(tlprofile.Profile227) }() select { case err := <-corrected: t.Fatalf("profile correction crossed an old-epoch physical write: %v", err) @@ -252,7 +253,7 @@ func TestProfileCorrectionLinearizesAfterStartedPushWrite(t *testing.T) { func TestStaleLayerPushIsRemovedFromResendTracking(t *testing.T) { c := &Conn{metrics: NopMetrics{}} - if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } fanout, err := newLayerUpdatesFanout(testLayerUpdatesValue(123)) @@ -263,7 +264,7 @@ func TestStaleLayerPushIsRemovedFromResendTracking(t *testing.T) { if err != nil { t.Fatal(err) } - if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile227); err != nil { t.Fatal(err) } frame := &outboundFrame{msgID: 100, body: encoded.body, layer: encoded.layer} @@ -285,14 +286,14 @@ func TestOutboundLayerBindingRejectsUnknownAndMismatchedConnections(t *testing.T if err != nil { t.Fatalf("freeze updates: %v", err) } - encoded, err := fanout.prepare(context.Background(), tg.LayerProfile225) + encoded, err := fanout.prepare(context.Background(), tlprofile.Profile225) 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) + wrong := testConnWithLayerProfile(t, tlprofile.Profile227) if _, err := wrong.buildFrame(context.Background(), 0, nil, encoded); !errors.Is(err, ErrOutboundLayerProfileMismatch) { t.Fatalf("profile mismatch error = %v", err) } @@ -307,13 +308,13 @@ func TestPendingPushReservationAccountsPreparedProfilesOnce(t *testing.T) { reservation.bytes.Store(100) reservation.refs.Store(1) - if !reservation.reservePrepared(tg.LayerProfile225, 80) { + if !reservation.reservePrepared(tlprofile.Profile225, 80) { t.Fatal("reserve first profile") } - if !reservation.reservePrepared(tg.LayerProfile225, 80) { + if !reservation.reservePrepared(tlprofile.Profile225, 80) { t.Fatal("reuse first profile reservation") } - if !reservation.reservePrepared(tg.LayerProfile227, 120) { + if !reservation.reservePrepared(tlprofile.Profile227, 120) { t.Fatal("reserve second profile") } if got := budget.snapshot(); got != 300 { diff --git a/internal/mtprotoedge/outbound_test.go b/internal/mtprotoedge/outbound_test.go index 602ea279..9643cbdf 100644 --- a/internal/mtprotoedge/outbound_test.go +++ b/internal/mtprotoedge/outbound_test.go @@ -16,6 +16,7 @@ import ( "github.com/iamxvbaba/td/mt" "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "github.com/iamxvbaba/td/transport" ) @@ -545,7 +546,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) + freezeActiveTestSessionProfile(t, srv.Conns(), auth.AuthKey.ID, auth.SessionID, tlprofile.ProfileCanonical) srv.Conns().SetReceivesUpdates(auth.SessionID, true) const sends = 64 @@ -1035,7 +1036,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) + freezeActiveTestSessionProfile(t, srv.Conns(), auth.AuthKey.ID, auth.SessionID, tlprofile.ProfileCanonical) srv.Conns().SetReceivesUpdates(auth.SessionID, true) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) diff --git a/internal/mtprotoedge/pending_flush_test.go b/internal/mtprotoedge/pending_flush_test.go index d92077c7..1f0ec671 100644 --- a/internal/mtprotoedge/pending_flush_test.go +++ b/internal/mtprotoedge/pending_flush_test.go @@ -8,6 +8,7 @@ import ( "github.com/iamxvbaba/td/mt" "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) // TestSetReceivesUpdatesFlushesPendingBeforeActivation 验证置位时先排空暂存推送 @@ -23,7 +24,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) + freezeActiveTestSessionProfile(t, srv.Conns(), raw, auth.SessionID, tlprofile.ProfileCanonical) ctx := context.Background() // 完全就绪还要求 membership 路由建立(ReceivesUpdatesForAuthKey 的另一半条件)。 diff --git a/internal/mtprotoedge/production_compat_test.go b/internal/mtprotoedge/production_compat_test.go index 2e32b474..5d235c76 100644 --- a/internal/mtprotoedge/production_compat_test.go +++ b/internal/mtprotoedge/production_compat_test.go @@ -11,6 +11,7 @@ import ( "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) var ErrSessionAmbiguous = errors.New("session id is shared by multiple auth keys") @@ -154,7 +155,7 @@ func (m *SessionManager) SetReceivesUpdates(sessionID int64, receives bool) { } } -func (m *SessionManager) SetLayerProfile(sessionID int64, profile tg.LayerProfile) bool { +func (m *SessionManager) SetLayerProfile(sessionID int64, profile tlprofile.Profile) bool { m.mu.RLock() c, _, ok, ambiguous := m.uniqueSessionForTestLocked(sessionID) m.mu.RUnlock() diff --git a/internal/mtprotoedge/rpc_flight.go b/internal/mtprotoedge/rpc_flight.go index 875710f8..35e4ff91 100644 --- a/internal/mtprotoedge/rpc_flight.go +++ b/internal/mtprotoedge/rpc_flight.go @@ -6,7 +6,7 @@ import ( "sync" "sync/atomic" - "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) const rpcResultFlightDefaultMaxPending = 8192 @@ -26,7 +26,7 @@ var ( // 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 + profile tlprofile.Profile hasProfile bool } @@ -40,11 +40,11 @@ func identityMismatch(identity rpcResultRequestIdentity) error { } type rpcResultRequestIdentity struct { - exact tg.LayerPreparedCallIdentity - // profile is retained separately because LayerPreparedCallIdentity is opaque. + exact tlprofile.PreparedIdentity + // profile is retained separately because PreparedIdentity 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 + profile tlprofile.Profile valid bool } @@ -474,7 +474,7 @@ func (c *rpcResultCache) Acquire(authKeyID [8]byte, sessionID, reqMsgID int64) ( func (c *rpcResultCache) AcquireIdentified( authKeyID [8]byte, sessionID, reqMsgID int64, - identity tg.LayerPreparedCallIdentity, + identity tlprofile.PreparedIdentity, ) (rpcResultAcquire, error) { return c.acquire(authKeyID, sessionID, reqMsgID, rpcResultRequestIdentity{exact: identity, valid: true}) } @@ -485,8 +485,8 @@ func (c *rpcResultCache) AcquireIdentified( func (c *rpcResultCache) AcquireLayerIdentified( authKeyID [8]byte, sessionID, reqMsgID int64, - profile tg.LayerProfile, - identity tg.LayerPreparedCallIdentity, + profile tlprofile.Profile, + identity tlprofile.PreparedIdentity, ) (rpcResultAcquire, error) { return c.acquire(authKeyID, sessionID, reqMsgID, rpcResultRequestIdentity{ exact: identity, profile: profile, valid: true, @@ -497,7 +497,7 @@ func (c *rpcResultCache) AcquireLayerIdentified( // 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) { +func (c *rpcResultCache) ExactAdmissionProfile(authKeyID [8]byte, sessionID, reqMsgID int64) (tlprofile.Profile, bool) { if c == nil || reqMsgID == 0 { return 0, false } diff --git a/internal/mtprotoedge/rpc_flight_test.go b/internal/mtprotoedge/rpc_flight_test.go index 94264746..7879dc73 100644 --- a/internal/mtprotoedge/rpc_flight_test.go +++ b/internal/mtprotoedge/rpc_flight_test.go @@ -9,19 +9,20 @@ import ( "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) 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 { +func rpcFlightExactIdentity(t *testing.T, profile tlprofile.Profile, request bin.Object) tlprofile.PreparedIdentity { t.Helper() var body bin.Buffer - if err := request.Encode(&body); err != nil { + if err := tlprofile.EncodeObject(profile, request, &body); err != nil { t.Fatalf("encode exact request: %v", err) } - admitted, err := tg.NewServerDispatcher(nil).AdmitLayer(profile, &body) + admitted, err := tlprofile.NewDispatcher().Admit(profile, &body, tlprofile.Limits{}) if err != nil { t.Fatalf("admit exact request: %v", err) } @@ -223,8 +224,8 @@ func TestRPCResultFlightRepeatedReplayJoinsStayBoundedAndPutCleansExecution(t *t 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{}) + firstIdentity := rpcFlightExactIdentity(t, tlprofile.Profile225, &tg.HelpGetConfigRequest{}) + otherIdentity := rpcFlightExactIdentity(t, tlprofile.Profile225, &tg.HelpGetNearestDCRequest{}) owner, err := cache.AcquireIdentified(authKeyID, 90, 900, firstIdentity) if err != nil || owner.state != rpcResultAcquireOwner || owner.owner == nil { @@ -255,23 +256,23 @@ func TestRPCResultFlightExactIdentityGuardsPendingAndCompletedReuse(t *testing.T 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) + identity := rpcFlightExactIdentity(t, tlprofile.Profile225, &tg.HelpGetConfigRequest{}) + owner, err := cache.AcquireLayerIdentified(authKeyID, 89, 890, tlprofile.Profile225, 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) + pending, err := cache.AcquireLayerIdentified(authKeyID, 89, 890, tlprofile.Profile225, 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) + completed, err := cache.AcquireLayerIdentified(authKeyID, 89, 890, tlprofile.Profile225, 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) + second, err := cache.AcquireLayerIdentified(authKeyID, 89, 894, tlprofile.Profile225, identity) if err != nil || second.admissionSeq <= owner.admissionSeq { t.Fatalf("second owner seq=%d err=%v, want > %d", second.admissionSeq, err, owner.admissionSeq) } @@ -286,12 +287,12 @@ func TestRPCResultFlightAdmissionSequenceAllocatedOnceAndReplayed(t *testing.T) 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) + identity := rpcFlightExactIdentity(t, tlprofile.Profile225, &tg.HelpGetConfigRequest{}) + first, err := cache.AcquireLayerIdentified(authKeyID, 86, 860, tlprofile.Profile225, identity) if err != nil || first.owner == nil { t.Fatalf("first owner err=%v", err) } - second, err := cache.AcquireLayerIdentified(authKeyID, 86, 864, tg.LayerProfile225, identity) + second, err := cache.AcquireLayerIdentified(authKeyID, 86, 864, tlprofile.Profile225, identity) if err != nil || second.owner == nil { t.Fatalf("second owner err=%v", err) } @@ -315,12 +316,12 @@ 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) + identity := rpcFlightExactIdentity(t, tlprofile.Profile225, &tg.HelpGetConfigRequest{}) + last, err := cache.AcquireLayerIdentified(authKeyID, 85, 850, tlprofile.Profile225, 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) { + if _, err := cache.AcquireLayerIdentified(authKeyID, 85, 854, tlprofile.Profile225, identity); !errors.Is(err, ErrRPCAdmissionSeqExhausted) { t.Fatalf("post-max allocation err=%v, want %v", err, ErrRPCAdmissionSeqExhausted) } if got := cache.nextAdmissionSeq.Load(); got != ^uint64(0) { @@ -333,15 +334,15 @@ 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) + winnerIdentity := rpcFlightExactIdentity(t, tlprofile.Profile225, request) + loserIdentity := rpcFlightExactIdentity(t, tlprofile.Profile227, request) + winner, err := cache.AcquireLayerIdentified(authKeyID, 88, 880, tlprofile.Profile225, winnerIdentity) if err != nil || winner.owner == nil { t.Fatalf("winner owner err=%v", err) } - _, err = cache.AcquireLayerIdentified(authKeyID, 88, 880, tg.LayerProfile227, loserIdentity) + _, err = cache.AcquireLayerIdentified(authKeyID, 88, 880, tlprofile.Profile227, loserIdentity) var mismatch *rpcResultIdentityMismatchError - if !errors.As(err, &mismatch) || !mismatch.hasProfile || mismatch.profile != tg.LayerProfile225 { + if !errors.As(err, &mismatch) || !mismatch.hasProfile || mismatch.profile != tlprofile.Profile225 { t.Fatalf("mismatch = %#v err=%v", mismatch, err) } if !winner.owner.Abort() { @@ -358,17 +359,17 @@ 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{ + identity := rpcFlightExactIdentity(t, tlprofile.Profile225, &tg.MessagesGetHistoryRequest{ Peer: &tg.InputPeerSelf{}, Limit: 1, }) - claim, err := cache.AcquireLayerIdentified(authKeyID, 87, 870, tg.LayerProfile225, identity) + claim, err := cache.AcquireLayerIdentified(authKeyID, 87, 870, tlprofile.Profile225, 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 { + if !ok || profile != tlprofile.Profile225 { t.Fatalf("profile hint = (%d,%v)", profile, ok) } // Admission already copied the hint into its local decoder cursor. Expiry @@ -385,7 +386,7 @@ func TestRPCAdmissionProfileHintSurvivesCompletedEvictionWindow(t *testing.T) { func TestRPCInvariantIdentityDoesNotExposeCanonicalProfileHint(t *testing.T) { cache := newRPCResultCacheWithFlightLimit(time.Now, 2) authKeyID := rpcFlightTestAuthID(84) - identity := rpcFlightExactIdentity(t, tg.LayerProfile227, &tg.AuthBindTempAuthKeyRequest{ + identity := rpcFlightExactIdentity(t, tlprofile.Profile227, &tg.AuthBindTempAuthKeyRequest{ PermAuthKeyID: 1, Nonce: 2, ExpiresAt: 3, EncryptedMessage: []byte("bind"), }) claim, err := cache.AcquireLayerIdentified(authKeyID, 84, 840, 0, identity) diff --git a/internal/mtprotoedge/rpc_result_egress_test.go b/internal/mtprotoedge/rpc_result_egress_test.go index 8e7da6fb..efab4ac4 100644 --- a/internal/mtprotoedge/rpc_result_egress_test.go +++ b/internal/mtprotoedge/rpc_result_egress_test.go @@ -15,6 +15,7 @@ import ( "github.com/iamxvbaba/td/crypto" "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) type opaqueRPCResult struct{ body []byte } @@ -491,8 +492,7 @@ func encodedRPCResultForPriorityTest(reqMsgID int64, payloadBytes int) *encodedO return &encodedOutboundMessage{ typeID: proto.ResultTypeID, reqMsgID: reqMsgID, body: b.Raw(), layer: &outboundLayerBinding{ - profile: tg.LayerProfileCanonical, - typ: tg.LayerClassBoolType().Ref(), + profile: tlprofile.ProfileCanonical, kind: outboundLayerBindingRequest, }, } diff --git a/internal/mtprotoedge/rpc_rewrap.go b/internal/mtprotoedge/rpc_rewrap.go index 4c93e166..18283cb7 100644 --- a/internal/mtprotoedge/rpc_rewrap.go +++ b/internal/mtprotoedge/rpc_rewrap.go @@ -15,6 +15,7 @@ import ( "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) // rpcRewrapRegistry links only an explicit official-client transition: @@ -40,8 +41,8 @@ type rpcRewrapSessionKey struct { type rpcRewrapKey struct { rpcRewrapSessionKey fingerprint [sha256.Size]byte - semantic tg.LayerSemanticRequestIdentity - call tg.LayerCallIdentity + semantic tlprofile.SemanticIdentity + call tlprofile.CallIdentity exact bool } @@ -110,8 +111,8 @@ func (r *rpcRewrapRegistry) register(c *Conn, body []byte, reqMsgID int64, metho func (r *rpcRewrapRegistry) registerSemantic( c *Conn, - identity tg.LayerSemanticRequestIdentity, - call tg.LayerCallIdentity, + identity tlprofile.SemanticIdentity, + call tlprofile.CallIdentity, reqMsgID int64, method string, owner *rpcResultOwnerLease, @@ -183,8 +184,8 @@ func (r *rpcRewrapRegistry) claim(c *Conn, inner []byte) *rpcRewrapCandidate { func (r *rpcRewrapRegistry) claimSemantic( c *Conn, - identity tg.LayerSemanticRequestIdentity, - call tg.LayerCallIdentity, + identity tlprofile.SemanticIdentity, + call tlprofile.CallIdentity, ) *rpcRewrapCandidate { if r == nil || c == nil || identity.Method() == 0 || identity.CanonicalSize() <= 0 { return nil diff --git a/internal/mtprotoedge/rpc_test.go b/internal/mtprotoedge/rpc_test.go index 11c616b7..1d0ba18f 100644 --- a/internal/mtprotoedge/rpc_test.go +++ b/internal/mtprotoedge/rpc_test.go @@ -17,11 +17,12 @@ import ( "github.com/iamxvbaba/td/tgerr" "github.com/iamxvbaba/td/transport" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/rpc" ) // TestRPCGetConfig 验证 M3:握手后 client 加密 help.getConfig, -// server 经 tg.ServerDispatcher 路由并回 rpc_result(含本地 DC),外加 new_session_created + ack。 +// server 经 tlprofile.Dispatcher 路由并回 rpc_result(含本地 DC),外加 new_session_created + ack。 func TestRPCGetConfig(t *testing.T) { const ( dc = 2 @@ -80,7 +81,7 @@ func TestLayerRPCGetConfigUsesExactAdmittedProfile(t *testing.T) { clientMsgID := proto.NewMessageIDGen(time.Now) reqMsgID := clientMsgID.New(proto.MessageFromClient) request := &tg.InvokeWithLayerRequest{ - Layer: int(tg.LayerProfile225), + Layer: int(tlprofile.Profile225), Query: &tg.InitConnectionRequest{ APIID: 123, DeviceModel: "Desktop", @@ -104,10 +105,14 @@ func TestLayerRPCGetConfigUsesExactAdmittedProfile(t *testing.T) { 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) + configObject, err := tlprofile.DecodeObject(tlprofile.Profile225, exact, tlprofile.Limits{}) if err != nil { t.Fatalf("decode layer 225 config: %v", err) } + config, ok := configObject.(*tg.Config) + if !ok { + t.Fatalf("layer 225 config = %T, want *tg.Config", configObject) + } if exact.Len() != 0 || config.ThisDC != dc { t.Fatalf("layer 225 config = dc:%d remaining:%d", config.ThisDC, exact.Len()) } diff --git a/internal/mtprotoedge/server.go b/internal/mtprotoedge/server.go index 4bfde345..d3665d6b 100644 --- a/internal/mtprotoedge/server.go +++ b/internal/mtprotoedge/server.go @@ -25,6 +25,7 @@ import ( "github.com/iamxvbaba/td/tmap" "github.com/iamxvbaba/td/transport" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/store" "telesrv/internal/store/memory" ) @@ -57,25 +58,25 @@ type legacyRPCHandlerWithMethod interface { // 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) + AdmitLayer(profile tlprofile.Profile, b *bin.Buffer, limits tlprofile.Limits) (tlprofile.Admission, error) + AdmitUnprofiled(b *bin.Buffer, limits tlprofile.Limits) (tlprofile.Admission, error) DispatchAdmitted( ctx context.Context, authKeyID [8]byte, sessionID int64, msgID int64, admissionSeq uint64, - request tg.LayerRequest, - ) (tg.LayerRPCResult, string, error) + request tlprofile.Admission, + ) (tlprofile.Result, 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 +// profile. Production handlers should implement it with the same sparse +// tlprofile dispatcher and semantic 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) + AdmitDefaultLayer(profile tlprofile.Profile, b *bin.Buffer, limits tlprofile.Limits) (tlprofile.Admission, error) } // LayerRPCSessionProfileResolver may restore an exact profile only when it was @@ -168,7 +169,7 @@ type LayerRPCReplayPreparer interface { sessionID int64, msgID int64, admissionSeq uint64, - request tg.LayerRequest, + request tlprofile.Admission, ) (afterSuccessfulDelivery func() error, err error) } diff --git a/internal/mtprotoedge/session_manager.go b/internal/mtprotoedge/session_manager.go index e0727231..735a4244 100644 --- a/internal/mtprotoedge/session_manager.go +++ b/internal/mtprotoedge/session_manager.go @@ -14,6 +14,7 @@ import ( "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) // ErrSessionNotFound 表示目标 session 当前无活跃连接。 @@ -82,7 +83,7 @@ type pendingPushReservation struct { refs atomic.Int32 mu sync.Mutex - profiles map[tg.LayerProfile]struct{} + profiles map[tlprofile.Profile]struct{} } func (r *pendingPushReservation) retain() { @@ -110,7 +111,7 @@ func (r *pendingPushReservation) release() { // 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 { +func (r *pendingPushReservation) reservePrepared(profile tlprofile.Profile, bytes int) bool { if r == nil || bytes < 0 { return false } @@ -123,7 +124,7 @@ func (r *pendingPushReservation) reservePrepared(profile tg.LayerProfile, bytes return false } if r.profiles == nil { - r.profiles = make(map[tg.LayerProfile]struct{}) + r.profiles = make(map[tlprofile.Profile]struct{}) } r.profiles[profile] = struct{}{} r.bytes.Add(int64(bytes)) @@ -274,7 +275,7 @@ func (m *SessionManager) SeedInheritedLayerForBusinessAuthKey(businessAuthKeyID if m == nil || businessAuthKeyID == ([8]byte{}) { return 0 } - profile, ok := tg.ResolveLayerProfile(layer) + profile, ok := tlprofile.ResolveProfile(layer) if !ok { return 0 } @@ -313,7 +314,7 @@ func (m *SessionManager) applyInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte, if m == nil { return 0 } - profile, ok := tg.ResolveLayerProfile(layer) + profile, ok := tlprofile.ResolveProfile(layer) if !ok { return 0 } @@ -364,7 +365,7 @@ func (m *SessionManager) ApplyOrderedLayerProfileForSession( primary *Conn, rawAuthKeyID [8]byte, sessionID int64, - profile tg.LayerProfile, + profile tlprofile.Profile, msgID int64, ) (int, error) { if err := validateLayerProfile(profile); err != nil { @@ -452,7 +453,7 @@ func (m *SessionManager) ExplicitLayerEvidenceForAuthKey(rawAuthKeyID [8]byte, s if c.isRetired() || state.Origin != LayerProfileExplicit { continue } - profile, supported := tg.ResolveLayerProfile(int(state.Profile)) + profile, supported := tlprofile.ResolveProfile(int(state.Profile)) if !supported || profile != state.Profile { continue } @@ -477,7 +478,7 @@ func (m *SessionManager) SetClientLayerForAuthKey(rawAuthKeyID [8]byte, sessionI if m == nil { return } - profile, ok := tg.ResolveLayerProfile(layer) + profile, ok := tlprofile.ResolveProfile(layer) if !ok { return } diff --git a/internal/mtprotoedge/session_manager_test.go b/internal/mtprotoedge/session_manager_test.go index e8dc3d37..0caaccf2 100644 --- a/internal/mtprotoedge/session_manager_test.go +++ b/internal/mtprotoedge/session_manager_test.go @@ -15,6 +15,7 @@ import ( "github.com/iamxvbaba/td/mt" "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) type closeCountingTransport struct { @@ -226,7 +227,7 @@ func TestSessionManagerBestEffortFanoutPreparesOncePerProfile(t *testing.T) { c.userID.Store(userID) c.userIDResolved.Store(true) c.receivesUpdates.Store(true) - if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatalf("freeze profile: %v", err) } sm.Register(c) @@ -263,7 +264,7 @@ 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} + profiles := []tlprofile.Profile{tlprofile.Profile225, tlprofile.Profile227, tlprofile.Profile228} conns := make([]*Conn, 0, len(profiles)) for _, profile := range profiles { c := &Conn{ @@ -277,8 +278,8 @@ func TestSessionManagerMixedLayerFanoutUsesProfileBoundBodies(t *testing.T) { c.userID.Store(userID) c.userIDResolved.Store(true) c.receivesUpdates.Store(true) - if profile == tg.LayerProfile228 { - if err := c.SeedInheritedLayerProfile(tg.LayerProfile227); err != nil { + if profile == tlprofile.Profile228 { + if err := c.SeedInheritedLayerProfile(tlprofile.Profile227); err != nil { t.Fatalf("seed Alice inherited profile: %v", err) } } @@ -319,7 +320,7 @@ func TestSessionManagerMixedLayerFanoutUsesProfileBoundBodies(t *testing.T) { 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) + decoded, decodeErr := tlprofile.DecodeObject(profiles[i], &input, tlprofile.Limits{}) if decodeErr != nil || input.Len() != 0 { t.Fatalf("decode profile %d: remaining=%d err=%v", profiles[i], input.Len(), decodeErr) } @@ -397,7 +398,7 @@ func TestSessionManagerBestEffortFanoutUsesOneBudgetAndDropsOnlySlowConsumers(t c.userID.Store(userID) c.userIDResolved.Store(true) c.receivesUpdates.Store(true) - if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile227); err != nil { t.Fatalf("freeze profile: %v", err) } sm.Register(c) @@ -415,7 +416,7 @@ func TestSessionManagerBestEffortFanoutUsesOneBudgetAndDropsOnlySlowConsumers(t healthy.userID.Store(userID) healthy.userIDResolved.Store(true) healthy.receivesUpdates.Store(true) - if err := healthy.FreezeLayerProfile(tg.LayerProfile227); err != nil { + if err := healthy.FreezeLayerProfile(tlprofile.Profile227); err != nil { t.Fatalf("freeze healthy profile: %v", err) } sm.Register(healthy) @@ -747,7 +748,7 @@ func TestPushToUserAuthKeyUsesOneDeadlineAndDropsOnlySlowPFSConnections(t *testi outboundStop: make(chan struct{}), } c.receivesUpdates.Store(true) - if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile227); err != nil { t.Fatalf("freeze profile: %v", err) } if queueFull { @@ -912,7 +913,7 @@ func TestPushToSessionForAuthKeyImmediateBypassesReadinessQueue(t *testing.T) { outboundControl: make(chan outboundOp, 1), outboundStop: make(chan struct{}), } - if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile227); err != nil { t.Fatalf("freeze profile: %v", err) } sm.Register(c) @@ -991,7 +992,7 @@ func TestSessionManagerWithholdsUpdatesReadinessUntilExactProfile(t *testing.T) default: } - if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + if err := c.FreezeLayerProfile(tlprofile.Profile225); err != nil { t.Fatal(err) } c.membershipsSynced.Store(true) @@ -1002,7 +1003,7 @@ func TestSessionManagerWithholdsUpdatesReadinessUntilExactProfile(t *testing.T) 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 { + if op.encoded == nil || op.encoded.layer == nil || op.encoded.layer.profile != tlprofile.Profile225 { t.Fatalf("flushed update layer binding = %#v", op.encoded) } op.releaseReservation(c.outboundTrackedBudget) @@ -1062,7 +1063,7 @@ func TestPendingFlushGlobalBodyPressureDoesNotTerminateHealthyConnection(t *test const userID = int64(606) c.userID.Store(userID) c.userIDResolved.Store(true) - if err := c.FreezeLayerProfile(tg.LayerProfileCanonical); err != nil { + if err := c.FreezeLayerProfile(tlprofile.ProfileCanonical); err != nil { t.Fatal(err) } sm.Register(c) @@ -1160,8 +1161,8 @@ 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) { + if !srv.Conns().SetLayerProfile(auth1.SessionID, tlprofile.Profile227) || + !srv.Conns().SetLayerProfile(auth2.SessionID, tlprofile.Profile227) { t.Fatal("seed exact test profiles") } diff --git a/internal/mtprotoedge/session_membership_gen_test.go b/internal/mtprotoedge/session_membership_gen_test.go index 7798cc46..b4299e18 100644 --- a/internal/mtprotoedge/session_membership_gen_test.go +++ b/internal/mtprotoedge/session_membership_gen_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "go.uber.org/zap/zaptest" ) @@ -67,7 +67,7 @@ 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 { + if err := c.FreezeLayerProfile(tlprofile.Profile227); err != nil { t.Fatal(err) } sm.Register(c) diff --git a/internal/mtprotoedge/session_ready_test.go b/internal/mtprotoedge/session_ready_test.go index 0f6ea06f..dc0a2725 100644 --- a/internal/mtprotoedge/session_ready_test.go +++ b/internal/mtprotoedge/session_ready_test.go @@ -3,7 +3,7 @@ package mtprotoedge import ( "testing" - "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "go.uber.org/zap/zaptest" ) @@ -16,7 +16,7 @@ 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 { + if err := c.FreezeLayerProfile(tlprofile.Profile227); err != nil { t.Fatal(err) } sm.Register(c) diff --git a/internal/rpc/account.go b/internal/rpc/account.go index 0f84c3b1..db2e0b8e 100644 --- a/internal/rpc/account.go +++ b/internal/rpc/account.go @@ -7,99 +7,241 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ioscompat "telesrv/internal/compat/ios" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" ) // registerAccount 注册 account.* RPC handler。 -func (r *Router) registerAccount(d *tg.ServerDispatcher) { - d.OnAccountRegisterDevice(func(ctx context.Context, req *tg.AccountRegisterDeviceRequest) (bool, error) { +func (r *Router) registerAccount(d *tlprofile.Dispatcher) { + registerRPC[*tg.AccountRegisterDeviceRequest](d, tlprofile.SemanticMethodAccountRegisterDevice, func(ctx context.Context, req *tg.AccountRegisterDeviceRequest) (any, error) { return true, nil }) - d.OnAccountUnregisterDevice(func(ctx context.Context, req *tg.AccountUnregisterDeviceRequest) (bool, error) { + registerRPC[*tg.AccountUnregisterDeviceRequest](d, tlprofile.SemanticMethodAccountUnregisterDevice, func(ctx context.Context, req *tg.AccountUnregisterDeviceRequest) (any, error) { return true, nil }) - d.OnAccountUpdateDeviceLocked(func(ctx context.Context, period int) (bool, error) { + registerRPC[*tg.AccountUpdateDeviceLockedRequest](d, tlprofile.SemanticMethodAccountUpdateDeviceLocked, func(ctx context.Context, layerRequest *tg.AccountUpdateDeviceLockedRequest) (any, error) { + period := layerRequest. + Period + _ = period + if _, _, err := r.currentUserID(ctx); err != nil { return false, internalErr() } return ioscompat.DeviceLockedUpdated(), nil }) - d.OnAccountSendChangePhoneCode(r.onAccountSendChangePhoneCode) - d.OnAccountChangePhone(r.onAccountChangePhone) - d.OnAccountCheckUsername(r.onAccountCheckUsername) - d.OnAccountUpdateProfile(r.onAccountUpdateProfile) - d.OnAccountUpdateUsername(r.onAccountUpdateUsername) - d.OnAccountUpdateBirthday(r.onAccountUpdateBirthday) - d.OnAccountUpdatePersonalChannel(r.onAccountUpdatePersonalChannel) - d.OnAccountGetPassword(r.onAccountGetPassword) - d.OnAccountGetNotifySettings(r.onAccountGetNotifySettings) - d.OnAccountUpdateNotifySettings(r.onAccountUpdateNotifySettings) - d.OnAccountResetNotifySettings(r.onAccountResetNotifySettings) - d.OnAccountGetPrivacy(r.onAccountGetPrivacy) - d.OnAccountSetPrivacy(r.onAccountSetPrivacy) - d.OnAccountGetAuthorizations(r.onAccountGetAuthorizations) - d.OnAccountResetAuthorization(r.onAccountResetAuthorization) - d.OnAccountGetPasswordSettings(r.onAccountGetPasswordSettings) - d.OnAccountUpdatePasswordSettings(r.onAccountUpdatePasswordSettings) - d.OnAccountConfirmPasswordEmail(r.onAccountConfirmPasswordEmail) - d.OnAccountResendPasswordEmail(r.onAccountResendPasswordEmail) - d.OnAccountCancelPasswordEmail(r.onAccountCancelPasswordEmail) - d.OnAccountSendVerifyEmailCode(r.onAccountSendVerifyEmailCode) - d.OnAccountVerifyEmail(r.onAccountVerifyEmail) - d.OnAccountGetDefaultEmojiStatuses(r.onAccountGetDefaultEmojiStatuses) - d.OnAccountGetCollectibleEmojiStatuses(func(ctx context.Context, hash int64) (tg.AccountEmojiStatusesClass, error) { + registerRPC[*tg.AccountSendChangePhoneCodeRequest](d, tlprofile.SemanticMethodAccountSendChangePhoneCode, func(ctx context.Context, layerRequest *tg.AccountSendChangePhoneCodeRequest) (any, error) { + return r.onAccountSendChangePhoneCode(ctx, layerRequest) + }) + registerRPC[*tg.AccountChangePhoneRequest](d, tlprofile.SemanticMethodAccountChangePhone, func(ctx context.Context, layerRequest *tg.AccountChangePhoneRequest) (any, error) { + return r.onAccountChangePhone(ctx, layerRequest) + }) + registerRPC[*tg.AccountCheckUsernameRequest](d, tlprofile.SemanticMethodAccountCheckUsername, func(ctx context.Context, layerRequest *tg.AccountCheckUsernameRequest) (any, error) { + return r.onAccountCheckUsername(ctx, layerRequest. + Username) + }) + registerRPC[*tg.AccountUpdateProfileRequest](d, tlprofile.SemanticMethodAccountUpdateProfile, func(ctx context.Context, layerRequest *tg.AccountUpdateProfileRequest) (any, error) { + return r.onAccountUpdateProfile(ctx, layerRequest) + }) + registerRPC[*tg.AccountUpdateUsernameRequest](d, tlprofile.SemanticMethodAccountUpdateUsername, func(ctx context.Context, layerRequest *tg.AccountUpdateUsernameRequest) (any, error) { + return r.onAccountUpdateUsername(ctx, layerRequest. + Username) + }) + registerRPC[*tg.AccountUpdateBirthdayRequest](d, tlprofile.SemanticMethodAccountUpdateBirthday, func(ctx context.Context, layerRequest *tg.AccountUpdateBirthdayRequest) (any, error) { + return r.onAccountUpdateBirthday(ctx, layerRequest) + }) + registerRPC[*tg.AccountUpdatePersonalChannelRequest](d, tlprofile.SemanticMethodAccountUpdatePersonalChannel, func(ctx context.Context, layerRequest *tg.AccountUpdatePersonalChannelRequest) (any, error) { + return r.onAccountUpdatePersonalChannel(ctx, layerRequest. + Channel) + }) + registerRPC[*tg.AccountGetPasswordRequest](d, tlprofile.SemanticMethodAccountGetPassword, func(ctx context.Context, layerRequest *tg.AccountGetPasswordRequest) (any, error) { + return r.onAccountGetPassword(ctx) + }) + registerRPC[*tg.AccountGetNotifySettingsRequest](d, tlprofile.SemanticMethodAccountGetNotifySettings, func(ctx context.Context, layerRequest *tg.AccountGetNotifySettingsRequest) (any, error) { + return r.onAccountGetNotifySettings(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.AccountUpdateNotifySettingsRequest](d, tlprofile.SemanticMethodAccountUpdateNotifySettings, func(ctx context.Context, layerRequest *tg.AccountUpdateNotifySettingsRequest) (any, error) { + return r.onAccountUpdateNotifySettings(ctx, layerRequest) + }) + registerRPC[*tg.AccountResetNotifySettingsRequest](d, tlprofile.SemanticMethodAccountResetNotifySettings, func(ctx context.Context, layerRequest *tg.AccountResetNotifySettingsRequest) (any, error) { + return r.onAccountResetNotifySettings(ctx) + }) + registerRPC[*tg.AccountGetPrivacyRequest](d, tlprofile.SemanticMethodAccountGetPrivacy, func(ctx context.Context, layerRequest *tg.AccountGetPrivacyRequest) (any, error) { + return r.onAccountGetPrivacy(ctx, layerRequest. + Key) + }) + registerRPC[*tg.AccountSetPrivacyRequest](d, tlprofile.SemanticMethodAccountSetPrivacy, func(ctx context.Context, layerRequest *tg.AccountSetPrivacyRequest) (any, error) { + return r.onAccountSetPrivacy(ctx, layerRequest) + }) + registerRPC[*tg.AccountGetAuthorizationsRequest](d, tlprofile.SemanticMethodAccountGetAuthorizations, func(ctx context.Context, layerRequest *tg.AccountGetAuthorizationsRequest) (any, error) { + return r.onAccountGetAuthorizations(ctx) + }) + registerRPC[*tg.AccountResetAuthorizationRequest](d, tlprofile.SemanticMethodAccountResetAuthorization, func(ctx context.Context, layerRequest *tg.AccountResetAuthorizationRequest) (any, error) { + return r.onAccountResetAuthorization(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.AccountGetPasswordSettingsRequest](d, tlprofile.SemanticMethodAccountGetPasswordSettings, func(ctx context.Context, layerRequest *tg.AccountGetPasswordSettingsRequest) (any, error) { + return r.onAccountGetPasswordSettings(ctx, layerRequest. + Password) + }) + registerRPC[*tg.AccountUpdatePasswordSettingsRequest](d, tlprofile.SemanticMethodAccountUpdatePasswordSettings, func(ctx context.Context, layerRequest *tg.AccountUpdatePasswordSettingsRequest) (any, error) { + return r.onAccountUpdatePasswordSettings(ctx, layerRequest) + }) + registerRPC[*tg.AccountConfirmPasswordEmailRequest](d, tlprofile.SemanticMethodAccountConfirmPasswordEmail, func(ctx context.Context, layerRequest *tg.AccountConfirmPasswordEmailRequest) (any, error) { + return r.onAccountConfirmPasswordEmail(ctx, layerRequest. + Code) + }) + registerRPC[*tg.AccountResendPasswordEmailRequest](d, tlprofile.SemanticMethodAccountResendPasswordEmail, func(ctx context.Context, layerRequest *tg.AccountResendPasswordEmailRequest) (any, error) { + return r.onAccountResendPasswordEmail(ctx) + }) + registerRPC[*tg.AccountCancelPasswordEmailRequest](d, tlprofile.SemanticMethodAccountCancelPasswordEmail, func(ctx context.Context, layerRequest *tg.AccountCancelPasswordEmailRequest) (any, error) { + return r.onAccountCancelPasswordEmail(ctx) + }) + registerRPC[*tg.AccountSendVerifyEmailCodeRequest](d, tlprofile.SemanticMethodAccountSendVerifyEmailCode, func(ctx context.Context, layerRequest *tg.AccountSendVerifyEmailCodeRequest) (any, error) { + return r.onAccountSendVerifyEmailCode(ctx, layerRequest) + }) + registerRPC[*tg.AccountVerifyEmailRequest](d, tlprofile.SemanticMethodAccountVerifyEmail, func(ctx context.Context, layerRequest *tg.AccountVerifyEmailRequest) (any, error) { + return r.onAccountVerifyEmail(ctx, layerRequest) + }) + registerRPC[*tg.AccountGetDefaultEmojiStatusesRequest](d, tlprofile.SemanticMethodAccountGetDefaultEmojiStatuses, func(ctx context.Context, layerRequest *tg.AccountGetDefaultEmojiStatusesRequest) (any, error) { + return r.onAccountGetDefaultEmojiStatuses(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.AccountGetCollectibleEmojiStatusesRequest](d, tlprofile.SemanticMethodAccountGetCollectibleEmojiStatuses, func(ctx context.Context, layerRequest *tg.AccountGetCollectibleEmojiStatusesRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return tdesktop.CollectibleEmojiStatuses(), nil }) - d.OnAccountGetDefaultGroupPhotoEmojis(func(ctx context.Context, hash int64) (tg.EmojiListClass, error) { + registerRPC[*tg.AccountGetDefaultGroupPhotoEmojisRequest](d, tlprofile.SemanticMethodAccountGetDefaultGroupPhotoEmojis, func(ctx context.Context, layerRequest *tg.AccountGetDefaultGroupPhotoEmojisRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return tdesktop.DefaultGroupPhotoEmojis(), nil }) - d.OnAccountGetConnectedBots(r.onAccountGetConnectedBots) - d.OnAccountUpdateBusinessWorkHours(r.onAccountUpdateBusinessWorkHours) - d.OnAccountUpdateBusinessLocation(r.onAccountUpdateBusinessLocation) - d.OnAccountUpdateBusinessIntro(r.onAccountUpdateBusinessIntro) - d.OnAccountUpdateBusinessGreetingMessage(r.onAccountUpdateBusinessGreetingMessage) - d.OnAccountUpdateBusinessAwayMessage(r.onAccountUpdateBusinessAwayMessage) - d.OnAccountGetBusinessChatLinks(r.onAccountGetBusinessChatLinks) - d.OnAccountCreateBusinessChatLink(r.onAccountCreateBusinessChatLink) - d.OnAccountEditBusinessChatLink(r.onAccountEditBusinessChatLink) - d.OnAccountDeleteBusinessChatLink(r.onAccountDeleteBusinessChatLink) - d.OnAccountResolveBusinessChatLink(r.onAccountResolveBusinessChatLink) - d.OnAccountUpdateConnectedBot(r.onAccountUpdateConnectedBot) - d.OnAccountGetBotBusinessConnection(func(ctx context.Context, connectionID string) (tg.UpdatesClass, error) { + registerRPC[*tg.AccountGetConnectedBotsRequest](d, tlprofile.SemanticMethodAccountGetConnectedBots, func(ctx context.Context, layerRequest *tg.AccountGetConnectedBotsRequest) (any, error) { + return r.onAccountGetConnectedBots(ctx) + }) + registerRPC[*tg.AccountUpdateBusinessWorkHoursRequest](d, tlprofile.SemanticMethodAccountUpdateBusinessWorkHours, func(ctx context.Context, layerRequest *tg.AccountUpdateBusinessWorkHoursRequest) (any, error) { + return r.onAccountUpdateBusinessWorkHours(ctx, layerRequest) + }) + registerRPC[*tg.AccountUpdateBusinessLocationRequest](d, tlprofile.SemanticMethodAccountUpdateBusinessLocation, func(ctx context.Context, layerRequest *tg.AccountUpdateBusinessLocationRequest) (any, error) { + return r.onAccountUpdateBusinessLocation(ctx, layerRequest) + }) + registerRPC[*tg.AccountUpdateBusinessIntroRequest](d, tlprofile.SemanticMethodAccountUpdateBusinessIntro, func(ctx context.Context, layerRequest *tg.AccountUpdateBusinessIntroRequest) (any, error) { + return r.onAccountUpdateBusinessIntro(ctx, layerRequest) + }) + registerRPC[*tg.AccountUpdateBusinessGreetingMessageRequest](d, tlprofile.SemanticMethodAccountUpdateBusinessGreetingMessage, func(ctx context.Context, layerRequest *tg.AccountUpdateBusinessGreetingMessageRequest) (any, error) { + return r.onAccountUpdateBusinessGreetingMessage(ctx, layerRequest) + }) + registerRPC[*tg.AccountUpdateBusinessAwayMessageRequest](d, tlprofile.SemanticMethodAccountUpdateBusinessAwayMessage, func(ctx context.Context, layerRequest *tg.AccountUpdateBusinessAwayMessageRequest) (any, error) { + return r.onAccountUpdateBusinessAwayMessage(ctx, layerRequest) + }) + registerRPC[*tg.AccountGetBusinessChatLinksRequest](d, tlprofile.SemanticMethodAccountGetBusinessChatLinks, func(ctx context.Context, layerRequest *tg.AccountGetBusinessChatLinksRequest) (any, error) { + return r.onAccountGetBusinessChatLinks(ctx) + }) + registerRPC[*tg.AccountCreateBusinessChatLinkRequest](d, tlprofile.SemanticMethodAccountCreateBusinessChatLink, func(ctx context.Context, layerRequest *tg.AccountCreateBusinessChatLinkRequest) (any, error) { + return r.onAccountCreateBusinessChatLink(ctx, layerRequest. + Link) + }) + registerRPC[*tg.AccountEditBusinessChatLinkRequest](d, tlprofile.SemanticMethodAccountEditBusinessChatLink, func(ctx context.Context, layerRequest *tg.AccountEditBusinessChatLinkRequest) (any, error) { + return r.onAccountEditBusinessChatLink(ctx, layerRequest) + }) + registerRPC[*tg.AccountDeleteBusinessChatLinkRequest](d, tlprofile.SemanticMethodAccountDeleteBusinessChatLink, func(ctx context.Context, layerRequest *tg.AccountDeleteBusinessChatLinkRequest) (any, error) { + return r.onAccountDeleteBusinessChatLink(ctx, layerRequest. + Slug) + }) + registerRPC[*tg.AccountResolveBusinessChatLinkRequest](d, tlprofile.SemanticMethodAccountResolveBusinessChatLink, func(ctx context.Context, layerRequest *tg.AccountResolveBusinessChatLinkRequest) (any, error) { + return r.onAccountResolveBusinessChatLink(ctx, layerRequest. + Slug) + }) + registerRPC[*tg.AccountUpdateConnectedBotRequest](d, tlprofile.SemanticMethodAccountUpdateConnectedBot, func(ctx context.Context, layerRequest *tg.AccountUpdateConnectedBotRequest) (any, error) { + return r.onAccountUpdateConnectedBot(ctx, layerRequest) + }) + registerRPC[*tg.AccountGetBotBusinessConnectionRequest](d, tlprofile.SemanticMethodAccountGetBotBusinessConnection, func(ctx context.Context, layerRequest *tg.AccountGetBotBusinessConnectionRequest) (any, error) { + connectionID := layerRequest. + ConnectionID + _ = connectionID + if _, _, err := r.currentUserID(ctx); err != nil { return nil, internalErr() } return nil, tgerr400("BOT_BUSINESS_MISSING") }) - d.OnAccountToggleConnectedBotPaused(r.onAccountToggleConnectedBotPaused) - d.OnAccountDisablePeerConnectedBot(r.onAccountDisablePeerConnectedBot) - d.OnAccountGetReactionsNotifySettings(r.onAccountGetReactionsNotifySettings) - d.OnAccountSetReactionsNotifySettings(r.onAccountSetReactionsNotifySettings) - d.OnAccountGetContactSignUpNotification(r.onAccountGetContactSignUpNotification) - d.OnAccountSetContactSignUpNotification(r.onAccountSetContactSignUpNotification) - d.OnAccountGetThemes(r.onAccountGetThemes) - d.OnAccountGetChatThemes(func(ctx context.Context, hash int64) (tg.AccountThemesClass, error) { + registerRPC[*tg.AccountToggleConnectedBotPausedRequest](d, tlprofile.SemanticMethodAccountToggleConnectedBotPaused, func(ctx context.Context, layerRequest *tg.AccountToggleConnectedBotPausedRequest) (any, error) { + return r.onAccountToggleConnectedBotPaused(ctx, layerRequest) + }) + registerRPC[*tg.AccountDisablePeerConnectedBotRequest](d, tlprofile.SemanticMethodAccountDisablePeerConnectedBot, func(ctx context.Context, layerRequest *tg.AccountDisablePeerConnectedBotRequest) (any, error) { + return r.onAccountDisablePeerConnectedBot(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.AccountGetReactionsNotifySettingsRequest](d, tlprofile.SemanticMethodAccountGetReactionsNotifySettings, func(ctx context.Context, layerRequest *tg.AccountGetReactionsNotifySettingsRequest) (any, error) { + return r.onAccountGetReactionsNotifySettings(ctx) + }) + registerRPC[*tg.AccountSetReactionsNotifySettingsRequest](d, tlprofile.SemanticMethodAccountSetReactionsNotifySettings, func(ctx context.Context, layerRequest *tg.AccountSetReactionsNotifySettingsRequest) (any, error) { + return r.onAccountSetReactionsNotifySettings(ctx, layerRequest. + Settings) + }) + registerRPC[*tg.AccountGetContactSignUpNotificationRequest](d, tlprofile.SemanticMethodAccountGetContactSignUpNotification, func(ctx context.Context, layerRequest *tg.AccountGetContactSignUpNotificationRequest) (any, error) { + return r.onAccountGetContactSignUpNotification(ctx) + }) + registerRPC[*tg.AccountSetContactSignUpNotificationRequest](d, tlprofile.SemanticMethodAccountSetContactSignUpNotification, func(ctx context.Context, layerRequest *tg.AccountSetContactSignUpNotificationRequest) (any, error) { + return r.onAccountSetContactSignUpNotification(ctx, layerRequest. + Silent) + }) + registerRPC[*tg.AccountGetThemesRequest](d, tlprofile.SemanticMethodAccountGetThemes, func(ctx context.Context, layerRequest *tg.AccountGetThemesRequest) (any, error) { + return r.onAccountGetThemes(ctx, layerRequest) + }) + registerRPC[*tg.AccountGetChatThemesRequest](d, tlprofile.SemanticMethodAccountGetChatThemes, func(ctx context.Context, layerRequest *tg.AccountGetChatThemesRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + if _, _, err := r.currentUserID(ctx); err != nil { return nil, internalErr() } return tdesktop.ChatThemes(hash), nil }) + registerRPC[ + // 自定义云主题(Create a New Theme 全链路):upload→create→update→save→install→get。 - d.OnAccountUploadTheme(r.onAccountUploadTheme) - d.OnAccountCreateTheme(r.onAccountCreateTheme) - d.OnAccountUpdateTheme(r.onAccountUpdateTheme) - d.OnAccountSaveTheme(r.onAccountSaveTheme) - d.OnAccountInstallTheme(r.onAccountInstallTheme) - d.OnAccountGetTheme(r.onAccountGetTheme) - d.OnAccountGetWallPapers(func(ctx context.Context, hash int64) (tg.AccountWallPapersClass, error) { + *tg.AccountUploadThemeRequest](d, tlprofile.SemanticMethodAccountUploadTheme, func(ctx context.Context, layerRequest *tg.AccountUploadThemeRequest) (any, error) { + return r.onAccountUploadTheme(ctx, layerRequest) + }) + registerRPC[*tg.AccountCreateThemeRequest](d, tlprofile.SemanticMethodAccountCreateTheme, func(ctx context.Context, layerRequest *tg.AccountCreateThemeRequest) (any, error) { + return r.onAccountCreateTheme(ctx, layerRequest) + }) + registerRPC[*tg.AccountUpdateThemeRequest](d, tlprofile.SemanticMethodAccountUpdateTheme, func(ctx context.Context, layerRequest *tg.AccountUpdateThemeRequest) (any, error) { + return r.onAccountUpdateTheme(ctx, layerRequest) + }) + registerRPC[*tg.AccountSaveThemeRequest](d, tlprofile.SemanticMethodAccountSaveTheme, func(ctx context.Context, layerRequest *tg.AccountSaveThemeRequest) (any, error) { + return r.onAccountSaveTheme(ctx, layerRequest) + }) + registerRPC[*tg.AccountInstallThemeRequest](d, tlprofile.SemanticMethodAccountInstallTheme, func(ctx context.Context, layerRequest *tg.AccountInstallThemeRequest) (any, error) { + return r.onAccountInstallTheme(ctx, layerRequest) + }) + registerRPC[*tg.AccountGetThemeRequest](d, tlprofile.SemanticMethodAccountGetTheme, func(ctx context.Context, layerRequest *tg.AccountGetThemeRequest) (any, error) { + return r.onAccountGetTheme(ctx, layerRequest) + }) + registerRPC[*tg.AccountGetWallPapersRequest](d, tlprofile.SemanticMethodAccountGetWallPapers, func(ctx context.Context, layerRequest *tg.AccountGetWallPapersRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + if _, _, err := r.currentUserID(ctx); err != nil { return nil, internalErr() } return tdesktop.WallPapers(hash), nil }) - d.OnAccountGetWallPaper(func(ctx context.Context, wallpaper tg.InputWallPaperClass) (tg.WallPaperClass, error) { + registerRPC[*tg.AccountGetWallPaperRequest](d, tlprofile.SemanticMethodAccountGetWallPaper, func(ctx context.Context, layerRequest *tg.AccountGetWallPaperRequest) (any, error) { + wallpaper := layerRequest. + Wallpaper + _ = wallpaper + if _, _, err := r.currentUserID(ctx); err != nil { return nil, internalErr() } @@ -109,7 +251,11 @@ func (r *Router) registerAccount(d *tg.ServerDispatcher) { } return found, nil }) - d.OnAccountGetMultiWallPapers(func(ctx context.Context, wallpapers []tg.InputWallPaperClass) ([]tg.WallPaperClass, error) { + registerRPC[*tg.AccountGetMultiWallPapersRequest](d, tlprofile.SemanticMethodAccountGetMultiWallPapers, func(ctx context.Context, layerRequest *tg.AccountGetMultiWallPapersRequest) (any, error) { + wallpapers := layerRequest. + Wallpapers + _ = wallpapers + if _, _, err := r.currentUserID(ctx); err != nil { return nil, internalErr() } @@ -122,7 +268,7 @@ func (r *Router) registerAccount(d *tg.ServerDispatcher) { } return found, nil }) - d.OnAccountSaveWallPaper(func(ctx context.Context, req *tg.AccountSaveWallPaperRequest) (bool, error) { + registerRPC[*tg.AccountSaveWallPaperRequest](d, tlprofile.SemanticMethodAccountSaveWallPaper, func(ctx context.Context, req *tg.AccountSaveWallPaperRequest) (any, error) { if _, _, err := r.currentUserID(ctx); err != nil { return false, internalErr() } @@ -134,7 +280,7 @@ func (r *Router) registerAccount(d *tg.ServerDispatcher) { } return true, nil }) - d.OnAccountInstallWallPaper(func(ctx context.Context, req *tg.AccountInstallWallPaperRequest) (bool, error) { + registerRPC[*tg.AccountInstallWallPaperRequest](d, tlprofile.SemanticMethodAccountInstallWallPaper, func(ctx context.Context, req *tg.AccountInstallWallPaperRequest) (any, error) { if _, _, err := r.currentUserID(ctx); err != nil { return false, internalErr() } @@ -146,13 +292,13 @@ func (r *Router) registerAccount(d *tg.ServerDispatcher) { } return true, nil }) - d.OnAccountResetWallPapers(func(ctx context.Context) (bool, error) { + registerRPC[*tg.AccountResetWallPapersRequest](d, tlprofile.SemanticMethodAccountResetWallPapers, func(ctx context.Context, layerRequest *tg.AccountResetWallPapersRequest) (any, error) { if _, _, err := r.currentUserID(ctx); err != nil { return false, internalErr() } return true, nil }) - d.OnAccountGetUniqueGiftChatThemes(func(ctx context.Context, req *tg.AccountGetUniqueGiftChatThemesRequest) (tg.AccountChatThemesClass, error) { + registerRPC[*tg.AccountGetUniqueGiftChatThemesRequest](d, tlprofile.SemanticMethodAccountGetUniqueGiftChatThemes, func(ctx context.Context, req *tg.AccountGetUniqueGiftChatThemesRequest) (any, error) { if _, _, err := r.currentUserID(ctx); err != nil { return nil, internalErr() } @@ -161,71 +307,151 @@ func (r *Router) registerAccount(d *tg.ServerDispatcher) { } return tdesktop.UniqueGiftChatThemes(req.Hash), nil }) - d.OnAccountGetRecentEmojiStatuses(func(ctx context.Context, hash int64) (tg.AccountEmojiStatusesClass, error) { + registerRPC[*tg.AccountGetRecentEmojiStatusesRequest](d, tlprofile.SemanticMethodAccountGetRecentEmojiStatuses, func(ctx context.Context, layerRequest *tg.AccountGetRecentEmojiStatusesRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return &tg.AccountEmojiStatuses{Hash: 0, Statuses: []tg.EmojiStatusClass{}}, nil }) - d.OnAccountClearRecentEmojiStatuses(func(ctx context.Context) (bool, error) { + registerRPC[*tg.AccountClearRecentEmojiStatusesRequest](d, tlprofile.SemanticMethodAccountClearRecentEmojiStatuses, func(ctx context.Context, layerRequest *tg.AccountClearRecentEmojiStatusesRequest) (any, error) { return true, nil }) - d.OnAccountUpdateEmojiStatus(r.onAccountUpdateEmojiStatus) - d.OnAccountUpdateColor(r.onAccountUpdateColor) - d.OnAccountGetDefaultProfilePhotoEmojis(r.onAccountGetDefaultProfilePhotoEmojis) - d.OnAccountGetDefaultBackgroundEmojis(r.onAccountGetDefaultBackgroundEmojis) - d.OnAccountGetChannelDefaultEmojiStatuses(func(ctx context.Context, hash int64) (tg.AccountEmojiStatusesClass, error) { + registerRPC[*tg.AccountUpdateEmojiStatusRequest](d, tlprofile.SemanticMethodAccountUpdateEmojiStatus, func(ctx context.Context, layerRequest *tg.AccountUpdateEmojiStatusRequest) (any, error) { + return r.onAccountUpdateEmojiStatus(ctx, layerRequest. + EmojiStatus) + }) + registerRPC[*tg.AccountUpdateColorRequest](d, tlprofile.SemanticMethodAccountUpdateColor, func(ctx context.Context, layerRequest *tg.AccountUpdateColorRequest) (any, error) { + return r.onAccountUpdateColor(ctx, layerRequest) + }) + registerRPC[*tg.AccountGetDefaultProfilePhotoEmojisRequest](d, tlprofile.SemanticMethodAccountGetDefaultProfilePhotoEmojis, func(ctx context.Context, layerRequest *tg.AccountGetDefaultProfilePhotoEmojisRequest) (any, error) { + return r.onAccountGetDefaultProfilePhotoEmojis(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.AccountGetDefaultBackgroundEmojisRequest](d, tlprofile.SemanticMethodAccountGetDefaultBackgroundEmojis, func(ctx context.Context, layerRequest *tg.AccountGetDefaultBackgroundEmojisRequest) (any, error) { + return r.onAccountGetDefaultBackgroundEmojis(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.AccountGetChannelDefaultEmojiStatusesRequest](d, tlprofile.SemanticMethodAccountGetChannelDefaultEmojiStatuses, func(ctx context.Context, layerRequest *tg.AccountGetChannelDefaultEmojiStatusesRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return &tg.AccountEmojiStatuses{Hash: 0, Statuses: []tg.EmojiStatusClass{}}, nil }) - d.OnAccountGetChannelRestrictedStatusEmojis(func(ctx context.Context, hash int64) (tg.EmojiListClass, error) { + registerRPC[*tg.AccountGetChannelRestrictedStatusEmojisRequest](d, tlprofile.SemanticMethodAccountGetChannelRestrictedStatusEmojis, func(ctx context.Context, layerRequest *tg.AccountGetChannelRestrictedStatusEmojisRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return tdesktop.DefaultGroupPhotoEmojis(), nil }) - d.OnAccountSetContentSettings(r.onAccountSetContentSettings) - d.OnAccountGetContentSettings(r.onAccountGetContentSettings) - d.OnAccountGetGlobalPrivacySettings(r.onAccountGetGlobalPrivacySettings) - d.OnAccountSetGlobalPrivacySettings(r.onAccountSetGlobalPrivacySettings) - d.OnAccountGetPasskeys(r.onAccountGetPasskeys) - d.OnAccountInitPasskeyRegistration(r.onAccountInitPasskeyRegistration) - d.OnAccountRegisterPasskey(r.onAccountRegisterPasskey) - d.OnAccountDeletePasskey(r.onAccountDeletePasskey) - d.OnAccountGetWebAuthorizations(func(ctx context.Context) (*tg.AccountWebAuthorizations, error) { + registerRPC[*tg.AccountSetContentSettingsRequest](d, tlprofile.SemanticMethodAccountSetContentSettings, func(ctx context.Context, layerRequest *tg.AccountSetContentSettingsRequest) (any, error) { + return r.onAccountSetContentSettings(ctx, layerRequest) + }) + registerRPC[*tg.AccountGetContentSettingsRequest](d, tlprofile.SemanticMethodAccountGetContentSettings, func(ctx context.Context, layerRequest *tg.AccountGetContentSettingsRequest) (any, error) { + return r.onAccountGetContentSettings(ctx) + }) + registerRPC[*tg.AccountGetGlobalPrivacySettingsRequest](d, tlprofile.SemanticMethodAccountGetGlobalPrivacySettings, func(ctx context.Context, layerRequest *tg.AccountGetGlobalPrivacySettingsRequest) (any, error) { + return r.onAccountGetGlobalPrivacySettings(ctx) + }) + registerRPC[*tg.AccountSetGlobalPrivacySettingsRequest](d, tlprofile.SemanticMethodAccountSetGlobalPrivacySettings, func(ctx context.Context, layerRequest *tg.AccountSetGlobalPrivacySettingsRequest) (any, error) { + return r.onAccountSetGlobalPrivacySettings(ctx, layerRequest. + Settings) + }) + registerRPC[*tg.AccountGetPasskeysRequest](d, tlprofile.SemanticMethodAccountGetPasskeys, func(ctx context.Context, layerRequest *tg.AccountGetPasskeysRequest) (any, error) { + return r.onAccountGetPasskeys(ctx) + }) + registerRPC[*tg.AccountInitPasskeyRegistrationRequest](d, tlprofile.SemanticMethodAccountInitPasskeyRegistration, func(ctx context.Context, layerRequest *tg.AccountInitPasskeyRegistrationRequest) (any, error) { + return r.onAccountInitPasskeyRegistration(ctx) + }) + registerRPC[*tg.AccountRegisterPasskeyRequest](d, tlprofile.SemanticMethodAccountRegisterPasskey, func(ctx context.Context, layerRequest *tg.AccountRegisterPasskeyRequest) (any, error) { + return r.onAccountRegisterPasskey(ctx, layerRequest. + Credential) + }) + registerRPC[*tg.AccountDeletePasskeyRequest](d, tlprofile.SemanticMethodAccountDeletePasskey, func(ctx context.Context, layerRequest *tg.AccountDeletePasskeyRequest) (any, error) { + return r.onAccountDeletePasskey(ctx, layerRequest. + ID) + }) + registerRPC[*tg.AccountGetWebAuthorizationsRequest](d, tlprofile.SemanticMethodAccountGetWebAuthorizations, func(ctx context.Context, layerRequest *tg.AccountGetWebAuthorizationsRequest) (any, error) { return tdesktop.WebAuthorizations(), nil }) - d.OnAccountResetWebAuthorization(func(ctx context.Context, hash int64) (bool, error) { + registerRPC[*tg.AccountResetWebAuthorizationRequest](d, tlprofile.SemanticMethodAccountResetWebAuthorization, func(ctx context.Context, layerRequest *tg.AccountResetWebAuthorizationRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return true, nil }) - d.OnAccountResetWebAuthorizations(func(ctx context.Context) (bool, error) { + registerRPC[*tg.AccountResetWebAuthorizationsRequest](d, tlprofile.SemanticMethodAccountResetWebAuthorizations, func(ctx context.Context, layerRequest *tg.AccountResetWebAuthorizationsRequest) ( + + // account.getWebBrowserSettings:telesrv 不接入网页浏览器(web bot)集成,返回空设置 + // (无内置浏览器例外、不强制外部浏览器)。Android 启动时会拉取,缺它会反复 500 + // NOT_IMPLEMENTED。空结构 Hash=0,客户端按默认(内置浏览器、无例外)渲染。 + any, error) { return true, nil }) - // account.getWebBrowserSettings:telesrv 不接入网页浏览器(web bot)集成,返回空设置 - // (无内置浏览器例外、不强制外部浏览器)。Android 启动时会拉取,缺它会反复 500 - // NOT_IMPLEMENTED。空结构 Hash=0,客户端按默认(内置浏览器、无例外)渲染。 - d.OnAccountGetWebBrowserSettings(func(ctx context.Context, hash int64) (tg.AccountWebBrowserSettingsClass, error) { + registerRPC[*tg.AccountGetWebBrowserSettingsRequest](d, tlprofile.SemanticMethodAccountGetWebBrowserSettings, func(ctx context.Context, layerRequest *tg.AccountGetWebBrowserSettingsRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return &tg.AccountWebBrowserSettings{}, nil }) - d.OnAccountGetNotifyExceptions(r.onAccountGetNotifyExceptions) - d.OnAccountGetAutoDownloadSettings(func(ctx context.Context) (*tg.AccountAutoDownloadSettings, error) { + registerRPC[*tg.AccountGetNotifyExceptionsRequest](d, tlprofile.SemanticMethodAccountGetNotifyExceptions, func(ctx context.Context, layerRequest *tg.AccountGetNotifyExceptionsRequest) (any, error) { + return r.onAccountGetNotifyExceptions(ctx, layerRequest) + }) + registerRPC[*tg.AccountGetAutoDownloadSettingsRequest](d, tlprofile.SemanticMethodAccountGetAutoDownloadSettings, func(ctx context.Context, layerRequest *tg.AccountGetAutoDownloadSettingsRequest) (any, error) { return tdesktop.AutoDownloadSettings(), nil }) - d.OnAccountSaveAutoDownloadSettings(func(ctx context.Context, req *tg.AccountSaveAutoDownloadSettingsRequest) (bool, error) { + registerRPC[*tg.AccountSaveAutoDownloadSettingsRequest](d, tlprofile.SemanticMethodAccountSaveAutoDownloadSettings, func(ctx context.Context, req *tg.AccountSaveAutoDownloadSettingsRequest) (any, error) { return true, nil }) - d.OnAccountSaveMusic(r.onAccountSaveMusic) - d.OnAccountGetSavedMusicIDs(r.onAccountGetSavedMusicIDs) - d.OnAccountGetSavedRingtones(func(ctx context.Context, hash int64) (tg.AccountSavedRingtonesClass, error) { + registerRPC[*tg.AccountSaveMusicRequest](d, tlprofile.SemanticMethodAccountSaveMusic, func(ctx context.Context, layerRequest *tg.AccountSaveMusicRequest) (any, error) { + return r.onAccountSaveMusic(ctx, layerRequest) + }) + registerRPC[*tg.AccountGetSavedMusicIDsRequest](d, tlprofile.SemanticMethodAccountGetSavedMusicIDs, func(ctx context.Context, layerRequest *tg.AccountGetSavedMusicIDsRequest) (any, error) { + return r.onAccountGetSavedMusicIDs(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.AccountGetSavedRingtonesRequest](d, tlprofile.SemanticMethodAccountGetSavedRingtones, func(ctx context.Context, layerRequest *tg.AccountGetSavedRingtonesRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + if _, _, err := r.currentUserID(ctx); err != nil { return nil, internalErr() } return &tg.AccountSavedRingtones{Hash: 0, Ringtones: []tg.DocumentClass{}}, nil }) - d.OnAccountGetAccountTTL(r.onAccountGetAccountTTL) - d.OnAccountSetAccountTTL(r.onAccountSetAccountTTL) - d.OnAccountSetAuthorizationTTL(func(ctx context.Context, authorizationttldays int) (bool, error) { + registerRPC[*tg.AccountGetAccountTTLRequest](d, tlprofile.SemanticMethodAccountGetAccountTTL, func(ctx context.Context, layerRequest *tg.AccountGetAccountTTLRequest) (any, error) { + return r.onAccountGetAccountTTL(ctx) + }) + registerRPC[*tg.AccountSetAccountTTLRequest](d, tlprofile.SemanticMethodAccountSetAccountTTL, func(ctx context.Context, layerRequest *tg.AccountSetAccountTTLRequest) (any, error) { + return r.onAccountSetAccountTTL(ctx, layerRequest. + TTL) + }) + registerRPC[*tg.AccountSetAuthorizationTTLRequest](d, tlprofile.SemanticMethodAccountSetAuthorizationTTL, func(ctx context.Context, layerRequest *tg.AccountSetAuthorizationTTLRequest) (any, error) { + authorizationttldays := layerRequest. + AuthorizationTTLDays + _ = authorizationttldays + return true, nil }) - d.OnAccountChangeAuthorizationSettings(func(ctx context.Context, req *tg.AccountChangeAuthorizationSettingsRequest) (bool, error) { + registerRPC[*tg.AccountChangeAuthorizationSettingsRequest](d, tlprofile.SemanticMethodAccountChangeAuthorizationSettings, func(ctx context.Context, req *tg.AccountChangeAuthorizationSettingsRequest) (any, error) { return true, nil }) - d.OnAccountResetPassword(r.onAccountResetPassword) - d.OnAccountDeclinePasswordReset(r.onAccountDeclinePasswordReset) - d.OnAccountUpdateStatus(r.onAccountUpdateStatus) + registerRPC[*tg.AccountResetPasswordRequest](d, tlprofile.SemanticMethodAccountResetPassword, func(ctx context.Context, layerRequest *tg.AccountResetPasswordRequest) (any, error) { + return r.onAccountResetPassword(ctx) + }) + registerRPC[*tg.AccountDeclinePasswordResetRequest](d, tlprofile.SemanticMethodAccountDeclinePasswordReset, func(ctx context.Context, layerRequest *tg.AccountDeclinePasswordResetRequest) (any, error) { + return r.onAccountDeclinePasswordReset(ctx) + }) + registerRPC[*tg.AccountUpdateStatusRequest](d, tlprofile.SemanticMethodAccountUpdateStatus, func(ctx context.Context, layerRequest *tg.AccountUpdateStatusRequest) (any, error) { + return r.onAccountUpdateStatus(ctx, layerRequest. + Offline) + }) + } func (r *Router) onAccountGetPassword(ctx context.Context) (*tg.AccountPassword, error) { diff --git a/internal/rpc/aicompose.go b/internal/rpc/aicompose.go index e445202c..523d3efb 100644 --- a/internal/rpc/aicompose.go +++ b/internal/rpc/aicompose.go @@ -8,17 +8,35 @@ import ( "github.com/iamxvbaba/td/tg" "github.com/iamxvbaba/td/tgerr" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) -func (r *Router) registerAiCompose(d *tg.ServerDispatcher) { - d.OnAicomposeGetTones(r.onAicomposeGetTones) - d.OnAicomposeCreateTone(r.onAicomposeCreateTone) - d.OnAicomposeUpdateTone(r.onAicomposeUpdateTone) - d.OnAicomposeSaveTone(r.onAicomposeSaveTone) - d.OnAicomposeDeleteTone(r.onAicomposeDeleteTone) - d.OnAicomposeGetTone(r.onAicomposeGetTone) - d.OnAicomposeGetToneExample(r.onAicomposeGetToneExample) +func (r *Router) registerAiCompose(d *tlprofile.Dispatcher) { + registerRPC[*tg.AicomposeGetTonesRequest](d, tlprofile.SemanticMethodAicomposeGetTones, func(ctx context.Context, layerRequest *tg.AicomposeGetTonesRequest) (any, error) { + return r.onAicomposeGetTones(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.AicomposeCreateToneRequest](d, tlprofile.SemanticMethodAicomposeCreateTone, func(ctx context.Context, layerRequest *tg.AicomposeCreateToneRequest) (any, error) { + return r.onAicomposeCreateTone(ctx, layerRequest) + }) + registerRPC[*tg.AicomposeUpdateToneRequest](d, tlprofile.SemanticMethodAicomposeUpdateTone, func(ctx context.Context, layerRequest *tg.AicomposeUpdateToneRequest) (any, error) { + return r.onAicomposeUpdateTone(ctx, layerRequest) + }) + registerRPC[*tg.AicomposeSaveToneRequest](d, tlprofile.SemanticMethodAicomposeSaveTone, func(ctx context.Context, layerRequest *tg.AicomposeSaveToneRequest) (any, error) { + return r.onAicomposeSaveTone(ctx, layerRequest) + }) + registerRPC[*tg.AicomposeDeleteToneRequest](d, tlprofile.SemanticMethodAicomposeDeleteTone, func(ctx context.Context, layerRequest *tg.AicomposeDeleteToneRequest) (any, error) { + return r.onAicomposeDeleteTone(ctx, layerRequest. + Tone) + }) + registerRPC[*tg.AicomposeGetToneRequest](d, tlprofile.SemanticMethodAicomposeGetTone, func(ctx context.Context, layerRequest *tg.AicomposeGetToneRequest) (any, error) { + return r.onAicomposeGetTone(ctx, layerRequest. + Tone) + }) + registerRPC[*tg.AicomposeGetToneExampleRequest](d, tlprofile.SemanticMethodAicomposeGetToneExample, func(ctx context.Context, layerRequest *tg.AicomposeGetToneExampleRequest) (any, error) { + return r.onAicomposeGetToneExample(ctx, layerRequest) + }) } func (r *Router) onAicomposeGetTones(ctx context.Context, hash int64) (tg.AicomposeTonesClass, error) { diff --git a/internal/rpc/android_compat_test.go b/internal/rpc/android_compat_test.go index 1f4c901c..dd2b3258 100644 --- a/internal/rpc/android_compat_test.go +++ b/internal/rpc/android_compat_test.go @@ -105,15 +105,11 @@ func TestLegacyAndroidAuthSignUpAllowedBeforeAuthorization(t *testing.T) { if err != nil { t.Fatalf("dispatch legacy auth.signUp: %v", err) } - // 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) + // Routed through the generated static client overlay and sparse semantic + // dispatcher, which exposes the canonical concrete result at this test seam. + authorization, ok := enc.(*tg.AuthAuthorization) if !ok { - t.Fatalf("response = %T, want *tg.AuthAuthorizationBox", enc) - } - authorization, ok := box.Authorization.(*tg.AuthAuthorization) - if !ok { - t.Fatalf("authorization = %T, want auth.authorization", box.Authorization) + t.Fatalf("response = %T, want *tg.AuthAuthorization", enc) } user, ok := authorization.User.(*tg.User) if !ok || user.ID != auth.signUpUser.ID { diff --git a/internal/rpc/android_private_layer_gate_test.go b/internal/rpc/android_private_layer_gate_test.go index 4d13eb8a..92859cbb 100644 --- a/internal/rpc/android_private_layer_gate_test.go +++ b/internal/rpc/android_private_layer_gate_test.go @@ -10,13 +10,14 @@ import ( "github.com/iamxvbaba/td/tg" "go.uber.org/zap/zaptest" + "github.com/iamxvbaba/td/tlprofile" compatandroid "telesrv/internal/compat/android" ) type androidPrivateLayerFixture struct { name string privateID uint32 - semantic tg.LayerSemanticID + semantic tlprofile.SemanticID method string wire func(*testing.T) []byte } @@ -46,14 +47,14 @@ func TestAndroidPrivateLayerRPCsAdaptAcrossCanonicalBoundary(t *testing.T) { } private := bin.Buffer{Buf: append([]byte(nil), raw...)} - canonical, handled, err := compatandroid.UpgradePrivateLayerRPC(tg.LayerProfileCanonical, &private, tg.LayerDecodeLimits{}) + canonical, handled, err := compatandroid.UpgradePrivateLayerRPC(tlprofile.ProfileCanonical, &private, tlprofile.Limits{}) if err != nil || !handled || canonical == nil { t.Fatalf("canonical upgrade = value:%v handled:%v err:%v", canonical != nil, handled, err) } if private.Len() != 0 { t.Fatalf("canonical upgrade left %d private bytes", private.Len()) } - canonicalID, ok := tg.LayerWireID(tg.LayerProfileCanonical, fixture.semantic) + canonicalID, ok := tlprofile.WireID(tlprofile.ProfileCanonical, fixture.semantic) if !ok { t.Fatalf("canonical profile has no wire id for %s", fixture.method) } @@ -61,11 +62,11 @@ func TestAndroidPrivateLayerRPCsAdaptAcrossCanonicalBoundary(t *testing.T) { t.Fatalf("canonical upgrade id = %#x err=%v, want %#x", got, peekErr, canonicalID) } - for _, profile := range []tg.LayerProfile{tg.LayerProfile227, tg.LayerProfile228} { + for _, profile := range []tlprofile.Profile{tlprofile.Profile227, tlprofile.Profile228} { profile := profile t.Run(fmt.Sprintf("layer_%d", profile), func(t *testing.T) { body := bin.Buffer{Buf: append([]byte(nil), raw...)} - admitted, err := r.AdmitLayer(profile, &body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitLayer(profile, &body, tlprofile.Limits{}) if err != nil { t.Fatalf("production exact admission: %v", err) } @@ -77,11 +78,11 @@ func TestAndroidPrivateLayerRPCsAdaptAcrossCanonicalBoundary(t *testing.T) { 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()) + category, method, ok := tlprofile.SemanticName(call.Method()) if !ok || category != "function" || method != fixture.method { t.Fatalf("admitted semantic name = (%q,%q,%v), want (function,%q,true)", category, method, ok, fixture.method) } - wantWireID, ok := tg.LayerWireID(profile, fixture.semantic) + wantWireID, ok := tlprofile.WireID(profile, fixture.semantic) if !ok || call.WireID() != wantWireID { t.Fatalf("admitted exact id = %#x, want %#x (ok=%v)", call.WireID(), wantWireID, ok) } @@ -95,12 +96,12 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { return []androidPrivateLayerFixture{ { name: "messages.forwardMessages_alias", privateID: 0x41d41ade, - semantic: tg.LayerSemanticMethodMessagesForwardMessages, method: "messages.forwardMessages", + semantic: tlprofile.SemanticMethodMessagesForwardMessages, method: "messages.forwardMessages", wire: func(*testing.T) []byte { return androidPrivateForwardMessagesWire() }, }, { name: "channels.inviteToChannel_alias", privateID: 0x199f3a6c, - semantic: tg.LayerSemanticMethodChannelsInviteToChannel, method: "channels.inviteToChannel", + semantic: tlprofile.SemanticMethodChannelsInviteToChannel, method: "channels.inviteToChannel", wire: func(t *testing.T) []byte { return androidPrivateAliasWire(t, 0x199f3a6c, &tg.ChannelsInviteToChannelRequest{ Channel: &tg.InputChannel{ChannelID: 41, AccessHash: 42}, @@ -110,14 +111,14 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { }, { name: "updates.getDifference_alias", privateID: 0x25939651, - semantic: tg.LayerSemanticMethodUpdatesGetDifference, method: "updates.getDifference", + semantic: tlprofile.SemanticMethodUpdatesGetDifference, method: "updates.getDifference", wire: func(t *testing.T) []byte { return androidPrivateAliasWire(t, 0x25939651, &tg.UpdatesGetDifferenceRequest{Pts: 100, Date: 200, Qts: 3}) }, }, { name: "messages.createChat_alias", privateID: 0x0034a818, - semantic: tg.LayerSemanticMethodMessagesCreateChat, method: "messages.createChat", + semantic: tlprofile.SemanticMethodMessagesCreateChat, method: "messages.createChat", wire: func(t *testing.T) []byte { return androidPrivateAliasWire(t, 0x0034a818, &tg.MessagesCreateChatRequest{ Users: []tg.InputUserClass{&tg.InputUser{UserID: 51, AccessHash: 52}}, @@ -127,7 +128,7 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { }, { name: "messages.uploadMedia_transform", privateID: 0x519bc2b1, - semantic: tg.LayerSemanticMethodMessagesUploadMedia, method: "messages.uploadMedia", + semantic: tlprofile.SemanticMethodMessagesUploadMedia, method: "messages.uploadMedia", wire: func(t *testing.T) []byte { return androidPrivateRawWire(t, 0x519bc2b1, func(body *bin.Buffer) error { if err := (&tg.InputPeerSelf{}).Encode(body); err != nil { @@ -139,7 +140,7 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { }, { name: "auth.signUp_transform", privateID: 0x80eee427, - semantic: tg.LayerSemanticMethodAuthSignUp, method: "auth.signUp", + semantic: tlprofile.SemanticMethodAuthSignUp, method: "auth.signUp", wire: func(t *testing.T) []byte { return androidPrivateRawWire(t, 0x80eee427, func(body *bin.Buffer) error { body.PutString("+15550000228") @@ -152,7 +153,7 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { }, { name: "messages.getMessages_transform", privateID: 0x4222fa74, - semantic: tg.LayerSemanticMethodMessagesGetMessages, method: "messages.getMessages", + semantic: tlprofile.SemanticMethodMessagesGetMessages, method: "messages.getMessages", wire: func(t *testing.T) []byte { return androidPrivateRawWire(t, 0x4222fa74, func(body *bin.Buffer) error { body.PutVectorHeader(2) @@ -164,7 +165,7 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { }, { name: "channels.getMessages_transform", privateID: 0x93d7b347, - semantic: tg.LayerSemanticMethodChannelsGetMessages, method: "channels.getMessages", + semantic: tlprofile.SemanticMethodChannelsGetMessages, method: "channels.getMessages", wire: func(t *testing.T) []byte { return androidPrivateRawWire(t, 0x93d7b347, func(body *bin.Buffer) error { if err := (&tg.InputChannel{ChannelID: 81, AccessHash: 82}).Encode(body); err != nil { @@ -179,7 +180,7 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { }, { name: "bots.exportBotToken_transform", privateID: 0x0063b089, - semantic: tg.LayerSemanticMethodBotsExportBotToken, method: "bots.exportBotToken", + semantic: tlprofile.SemanticMethodBotsExportBotToken, method: "bots.exportBotToken", wire: func(t *testing.T) []byte { return androidPrivateRawWire(t, 0x0063b089, func(body *bin.Buffer) error { body.PutLong(91) @@ -190,7 +191,7 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { }, { name: "account.registerDevice_transform", privateID: 0x637ea878, - semantic: tg.LayerSemanticMethodAccountRegisterDevice, method: "account.registerDevice", + semantic: tlprofile.SemanticMethodAccountRegisterDevice, method: "account.registerDevice", wire: func(t *testing.T) []byte { return androidPrivateRawWire(t, 0x637ea878, func(body *bin.Buffer) error { body.PutInt(2) @@ -201,7 +202,7 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { }, { name: "contacts.search_transform", privateID: 0x11f812d8, - semantic: tg.LayerSemanticMethodContactsSearch, method: "contacts.search", + semantic: tlprofile.SemanticMethodContactsSearch, method: "contacts.search", wire: func(t *testing.T) []byte { return androidPrivateRawWire(t, 0x11f812d8, func(body *bin.Buffer) error { body.PutString("private-query") @@ -212,7 +213,7 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { }, { name: "langpack.getLangPack_transform", privateID: 0x9ab5c58e, - semantic: tg.LayerSemanticMethodLangpackGetLangPack, method: "langpack.getLangPack", + semantic: tlprofile.SemanticMethodLangpackGetLangPack, method: "langpack.getLangPack", wire: func(t *testing.T) []byte { return androidPrivateRawWire(t, 0x9ab5c58e, func(body *bin.Buffer) error { body.PutString("en") @@ -222,7 +223,7 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { }, { name: "langpack.getStrings_transform", privateID: 0x2e1ee318, - semantic: tg.LayerSemanticMethodLangpackGetStrings, method: "langpack.getStrings", + semantic: tlprofile.SemanticMethodLangpackGetStrings, method: "langpack.getStrings", wire: func(t *testing.T) []byte { return androidPrivateRawWire(t, 0x2e1ee318, func(body *bin.Buffer) error { body.PutString("en") @@ -235,14 +236,14 @@ func androidPrivateLayerFixtures() []androidPrivateLayerFixture { }, { name: "langpack.getLanguages_transform", privateID: 0x800fd57d, - semantic: tg.LayerSemanticMethodLangpackGetLanguages, method: "langpack.getLanguages", + semantic: tlprofile.SemanticMethodLangpackGetLanguages, method: "langpack.getLanguages", wire: func(t *testing.T) []byte { return androidPrivateRawWire(t, 0x800fd57d, func(*bin.Buffer) error { return nil }) }, }, { name: "messages.editChatCreator_transform", privateID: 0x8f38cd1f, - semantic: tg.LayerSemanticMethodMessagesEditChatCreator, method: "messages.editChatCreator", + semantic: tlprofile.SemanticMethodMessagesEditChatCreator, method: "messages.editChatCreator", wire: func(t *testing.T) []byte { return androidPrivateRawWire(t, 0x8f38cd1f, func(body *bin.Buffer) error { if err := (&tg.InputChannel{ChannelID: 101, AccessHash: 102}).Encode(body); err != nil { diff --git a/internal/rpc/auth.go b/internal/rpc/auth.go index 0eb4f8e9..41675b06 100644 --- a/internal/rpc/auth.go +++ b/internal/rpc/auth.go @@ -13,6 +13,7 @@ import ( "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/app/auth" "telesrv/internal/domain" ) @@ -21,38 +22,90 @@ import ( const devCodeLength = 5 // registerAuth 注册 auth.* RPC handler。 -func (r *Router) registerAuth(d *tg.ServerDispatcher) { - d.OnAuthBindTempAuthKey(r.onAuthBindTempAuthKey) - d.OnAuthExportLoginToken(r.onAuthExportLoginToken) - d.OnAuthImportLoginToken(r.onAuthImportLoginToken) - d.OnAuthAcceptLoginToken(r.onAuthAcceptLoginToken) - d.OnAuthExportAuthorization(func(ctx context.Context, dcid int) (*tg.AuthExportedAuthorization, error) { +func (r *Router) registerAuth(d *tlprofile.Dispatcher) { + registerRPC[*tg.AuthBindTempAuthKeyRequest](d, tlprofile.SemanticMethodAuthBindTempAuthKey, func(ctx context.Context, layerRequest *tg.AuthBindTempAuthKeyRequest) (any, error) { + return r.onAuthBindTempAuthKey(ctx, layerRequest) + }) + registerRPC[*tg.AuthExportLoginTokenRequest](d, tlprofile.SemanticMethodAuthExportLoginToken, func(ctx context.Context, layerRequest *tg.AuthExportLoginTokenRequest) (any, error) { + return r.onAuthExportLoginToken(ctx, layerRequest) + }) + registerRPC[*tg.AuthImportLoginTokenRequest](d, tlprofile.SemanticMethodAuthImportLoginToken, func(ctx context.Context, layerRequest *tg.AuthImportLoginTokenRequest) (any, error) { + return r.onAuthImportLoginToken(ctx, layerRequest. + Token) + }) + registerRPC[*tg.AuthAcceptLoginTokenRequest](d, tlprofile.SemanticMethodAuthAcceptLoginToken, func(ctx context.Context, layerRequest *tg.AuthAcceptLoginTokenRequest) (any, error) { + return r.onAuthAcceptLoginToken(ctx, layerRequest. + Token) + }) + registerRPC[*tg.AuthExportAuthorizationRequest](d, tlprofile.SemanticMethodAuthExportAuthorization, func(ctx context.Context, layerRequest *tg.AuthExportAuthorizationRequest) (any, error) { + dcid := layerRequest. + DCID + _ = dcid + return nil, dcIDInvalidErr() }) - d.OnAuthImportAuthorization(func(ctx context.Context, req *tg.AuthImportAuthorizationRequest) (tg.AuthAuthorizationClass, error) { + registerRPC[*tg.AuthImportAuthorizationRequest](d, tlprofile.SemanticMethodAuthImportAuthorization, func(ctx context.Context, req *tg.AuthImportAuthorizationRequest) (any, error) { return nil, dcIDInvalidErr() }) - d.OnAuthDropTempAuthKeys(func(ctx context.Context, exceptauthkeys []int64) (bool, error) { + registerRPC[*tg.AuthDropTempAuthKeysRequest](d, tlprofile.SemanticMethodAuthDropTempAuthKeys, func(ctx context.Context, layerRequest *tg.AuthDropTempAuthKeysRequest) (any, error) { + exceptauthkeys := layerRequest. + ExceptAuthKeys + _ = exceptauthkeys + return true, nil }) - d.OnAuthInitPasskeyLogin(r.onAuthInitPasskeyLogin) - d.OnAuthFinishPasskeyLogin(r.onAuthFinishPasskeyLogin) - d.OnAuthSendCode(r.onAuthSendCode) - d.OnAuthResendCode(r.onAuthResendCode) - d.OnAuthCancelCode(r.onAuthCancelCode) - d.OnAuthSignIn(r.onAuthSignIn) - d.OnAuthSignUp(r.onAuthSignUp) - d.OnAuthImportBotAuthorization(r.onAuthImportBotAuthorization) - d.OnAuthLogOut(r.onAuthLogOut) - d.OnAuthResetAuthorizations(r.onAuthResetAuthorizations) - d.OnAuthCheckPassword(r.onAuthCheckPassword) - d.OnAuthRequestPasswordRecovery(r.onAuthRequestPasswordRecovery) - d.OnAuthRecoverPassword(r.onAuthRecoverPassword) - d.OnAuthCheckRecoveryPassword(r.onAuthCheckRecoveryPassword) - d.OnAuthResetLoginEmail(r.onAuthResetLoginEmail) + registerRPC[*tg.AuthInitPasskeyLoginRequest](d, tlprofile.SemanticMethodAuthInitPasskeyLogin, func(ctx context.Context, layerRequest *tg.AuthInitPasskeyLoginRequest) (any, error) { + return r.onAuthInitPasskeyLogin(ctx, layerRequest) + }) + registerRPC[*tg.AuthFinishPasskeyLoginRequest](d, tlprofile.SemanticMethodAuthFinishPasskeyLogin, func(ctx context.Context, layerRequest *tg.AuthFinishPasskeyLoginRequest) (any, error) { + return r.onAuthFinishPasskeyLogin(ctx, layerRequest) + }) + registerRPC[*tg.AuthSendCodeRequest](d, tlprofile.SemanticMethodAuthSendCode, func(ctx context.Context, layerRequest *tg.AuthSendCodeRequest) (any, error) { + return r.onAuthSendCode(ctx, layerRequest) + }) + registerRPC[*tg.AuthResendCodeRequest](d, tlprofile.SemanticMethodAuthResendCode, func(ctx context.Context, layerRequest *tg.AuthResendCodeRequest) (any, error) { + return r.onAuthResendCode(ctx, layerRequest) + }) + registerRPC[*tg.AuthCancelCodeRequest](d, tlprofile.SemanticMethodAuthCancelCode, func(ctx context.Context, layerRequest *tg.AuthCancelCodeRequest) (any, error) { + return r.onAuthCancelCode(ctx, layerRequest) + }) + registerRPC[*tg.AuthSignInRequest](d, tlprofile.SemanticMethodAuthSignIn, func(ctx context.Context, layerRequest *tg.AuthSignInRequest) (any, error) { + return r.onAuthSignIn(ctx, layerRequest) + }) + registerRPC[*tg.AuthSignUpRequest](d, tlprofile.SemanticMethodAuthSignUp, func(ctx context.Context, layerRequest *tg.AuthSignUpRequest) (any, error) { + return r.onAuthSignUp(ctx, layerRequest) + }) + registerRPC[*tg.AuthImportBotAuthorizationRequest](d, tlprofile.SemanticMethodAuthImportBotAuthorization, func(ctx context.Context, layerRequest *tg.AuthImportBotAuthorizationRequest) (any, error) { + return r.onAuthImportBotAuthorization(ctx, layerRequest) + }) + registerRPC[*tg.AuthLogOutRequest](d, tlprofile.SemanticMethodAuthLogOut, func(ctx context.Context, layerRequest *tg.AuthLogOutRequest) (any, error) { + return r.onAuthLogOut(ctx) + }) + registerRPC[*tg.AuthResetAuthorizationsRequest](d, tlprofile.SemanticMethodAuthResetAuthorizations, func(ctx context.Context, layerRequest *tg.AuthResetAuthorizationsRequest) (any, error) { + return r.onAuthResetAuthorizations(ctx) + }) + registerRPC[*tg.AuthCheckPasswordRequest](d, tlprofile.SemanticMethodAuthCheckPassword, func(ctx context.Context, layerRequest *tg.AuthCheckPasswordRequest) (any, error) { + return r.onAuthCheckPassword(ctx, layerRequest. + Password) + }) + registerRPC[*tg.AuthRequestPasswordRecoveryRequest](d, tlprofile.SemanticMethodAuthRequestPasswordRecovery, func(ctx context.Context, layerRequest *tg.AuthRequestPasswordRecoveryRequest) (any, error) { + return r.onAuthRequestPasswordRecovery(ctx) + }) + registerRPC[*tg.AuthRecoverPasswordRequest](d, tlprofile.SemanticMethodAuthRecoverPassword, func(ctx context.Context, layerRequest *tg.AuthRecoverPasswordRequest) (any, error) { + return r.onAuthRecoverPassword(ctx, layerRequest) + }) + registerRPC[*tg.AuthCheckRecoveryPasswordRequest](d, tlprofile.SemanticMethodAuthCheckRecoveryPassword, func(ctx context.Context, layerRequest *tg.AuthCheckRecoveryPasswordRequest) ( + + // onAuthBindTempAuthKey 记录 TDesktop 的 PFS temp→perm auth key 绑定。 + any, error) { + return r.onAuthCheckRecoveryPassword(ctx, layerRequest. + Code) + }) + registerRPC[*tg.AuthResetLoginEmailRequest](d, tlprofile.SemanticMethodAuthResetLoginEmail, func(ctx context.Context, layerRequest *tg.AuthResetLoginEmailRequest) (any, error) { + return r.onAuthResetLoginEmail(ctx, layerRequest) + }) } -// onAuthBindTempAuthKey 记录 TDesktop 的 PFS temp→perm auth key 绑定。 func (r *Router) onAuthBindTempAuthKey(ctx context.Context, req *tg.AuthBindTempAuthKeyRequest) (bool, error) { if !layerRPCProfileEvidenceFresh(ctx) { // The inner request is outside MTProto's mutable msg_id window. It may be diff --git a/internal/rpc/bots.go b/internal/rpc/bots.go index 63bb3357..5d714f18 100644 --- a/internal/rpc/bots.go +++ b/internal/rpc/bots.go @@ -6,6 +6,7 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) @@ -22,58 +23,165 @@ import ( // bump bot_info_version;命令变更后 bots_hooks.PushBotCommandsChanged 给在线相关用户 // 推 updateBotCommands(扇出封顶 100,无 pts),离线/超界用户靠 version bump 在下次 // getFullUser 重拉兜底。 -func (r *Router) registerBots(d *tg.ServerDispatcher) { - d.OnBotsSendCustomRequest(r.onBotsSendCustomRequest) - d.OnBotsAnswerWebhookJSONQuery(r.onBotsAnswerWebhookJSONQuery) - d.OnBotsSetBotBroadcastDefaultAdminRights(r.onBotsSetBotBroadcastDefaultAdminRights) - d.OnBotsSetBotGroupDefaultAdminRights(r.onBotsSetBotGroupDefaultAdminRights) - d.OnBotsSetBotCommands(r.onBotsSetBotCommands) - d.OnBotsResetBotCommands(r.onBotsResetBotCommands) - d.OnBotsGetBotCommands(r.onBotsGetBotCommands) - d.OnBotsSetBotInfo(r.onBotsSetBotInfo) - d.OnBotsGetBotInfo(r.onBotsGetBotInfo) - d.OnBotsSetBotMenuButton(r.onBotsSetBotMenuButton) - d.OnBotsGetBotMenuButton(r.onBotsGetBotMenuButton) - d.OnBotsReorderUsernames(r.onBotsReorderUsernames) - d.OnBotsToggleUsername(r.onBotsToggleUsername) - d.OnBotsCanSendMessage(r.onBotsCanSendMessage) - d.OnBotsAllowSendMessage(r.onBotsAllowSendMessage) - d.OnBotsInvokeWebViewCustomMethod(r.onBotsInvokeWebViewCustomMethod) - d.OnBotsGetPopularAppBots(r.onBotsGetPopularAppBots) - d.OnBotsAddPreviewMedia(r.onBotsAddPreviewMedia) - d.OnBotsEditPreviewMedia(r.onBotsEditPreviewMedia) - d.OnBotsDeletePreviewMedia(r.onBotsDeletePreviewMedia) - d.OnBotsReorderPreviewMedias(r.onBotsReorderPreviewMedias) - d.OnBotsGetPreviewInfo(r.onBotsGetPreviewInfo) - d.OnBotsGetPreviewMedias(r.onBotsGetPreviewMedias) - d.OnBotsUpdateUserEmojiStatus(r.onBotsUpdateUserEmojiStatus) - d.OnBotsToggleUserEmojiStatusPermission(r.onBotsToggleUserEmojiStatusPermission) - d.OnBotsCheckDownloadFileParams(r.onBotsCheckDownloadFileParams) - d.OnBotsGetAdminedBots(r.onBotsGetAdminedBots) - d.OnBotsUpdateStarRefProgram(r.onBotsUpdateStarRefProgram) - d.OnBotsSetCustomVerification(r.onBotsSetCustomVerification) - d.OnBotsGetBotRecommendations(r.onBotsGetBotRecommendations) - d.OnBotsCheckUsername(r.onBotsCheckUsername) - d.OnBotsCreateBot(r.onBotsCreateBot) - d.OnBotsExportBotToken(r.onBotsExportBotToken) - d.OnBotsRequestWebViewButton(r.onBotsRequestWebViewButton) - d.OnBotsGetRequestedWebViewButton(r.onBotsGetRequestedWebViewButton) - d.OnBotsGetAccessSettings(r.onBotsGetAccessSettings) - d.OnBotsEditAccessSettings(r.onBotsEditAccessSettings) - // P3:startBot 深链 + inline callback 闭环。 - d.OnMessagesStartBot(r.onMessagesStartBot) - d.OnMessagesGetBotCallbackAnswer(r.onMessagesGetBotCallbackAnswer) - d.OnMessagesSetBotCallbackAnswer(r.onMessagesSetBotCallbackAnswer) - d.OnMessagesGetInlineBotResults(r.onMessagesGetInlineBotResults) - d.OnMessagesSetInlineBotResults(r.onMessagesSetInlineBotResults) - d.OnMessagesSendInlineBotResult(r.onMessagesSendInlineBotResult) - d.OnMessagesSavePreparedInlineMessage(r.onMessagesSavePreparedInlineMessage) - d.OnMessagesEditInlineBotMessage(r.onMessagesEditInlineBotMessage) - d.OnMessagesSetBotShippingResults(r.onMessagesSetBotShippingResults) - d.OnMessagesSetBotPrecheckoutResults(r.onMessagesSetBotPrecheckoutResults) +func (r *Router) registerBots(d *tlprofile.Dispatcher) { + registerRPC[*tg.BotsSendCustomRequestRequest](d, tlprofile.SemanticMethodBotsSendCustomRequest, func(ctx context.Context, layerRequest *tg.BotsSendCustomRequestRequest) (any, error) { + return r.onBotsSendCustomRequest(ctx, layerRequest) + }) + registerRPC[*tg.BotsAnswerWebhookJSONQueryRequest](d, tlprofile.SemanticMethodBotsAnswerWebhookJSONQuery, func(ctx context.Context, layerRequest *tg.BotsAnswerWebhookJSONQueryRequest) (any, error) { + return r.onBotsAnswerWebhookJSONQuery(ctx, layerRequest) + }) + registerRPC[*tg.BotsSetBotBroadcastDefaultAdminRightsRequest](d, tlprofile.SemanticMethodBotsSetBotBroadcastDefaultAdminRights, func(ctx context.Context, layerRequest *tg.BotsSetBotBroadcastDefaultAdminRightsRequest) (any, error) { + return r.onBotsSetBotBroadcastDefaultAdminRights(ctx, layerRequest. + AdminRights) + }) + registerRPC[*tg.BotsSetBotGroupDefaultAdminRightsRequest](d, tlprofile.SemanticMethodBotsSetBotGroupDefaultAdminRights, func(ctx context.Context, layerRequest *tg.BotsSetBotGroupDefaultAdminRightsRequest) (any, error) { + return r.onBotsSetBotGroupDefaultAdminRights(ctx, layerRequest. + AdminRights) + }) + registerRPC[*tg.BotsSetBotCommandsRequest](d, tlprofile.SemanticMethodBotsSetBotCommands, func(ctx context.Context, layerRequest *tg.BotsSetBotCommandsRequest) (any, error) { + return r.onBotsSetBotCommands(ctx, layerRequest) + }) + registerRPC[*tg.BotsResetBotCommandsRequest](d, tlprofile.SemanticMethodBotsResetBotCommands, func(ctx context.Context, layerRequest *tg.BotsResetBotCommandsRequest) (any, error) { + return r.onBotsResetBotCommands(ctx, layerRequest) + }) + registerRPC[*tg.BotsGetBotCommandsRequest](d, tlprofile.SemanticMethodBotsGetBotCommands, func(ctx context.Context, layerRequest *tg.BotsGetBotCommandsRequest) (any, error) { + return r.onBotsGetBotCommands(ctx, layerRequest) + }) + registerRPC[*tg.BotsSetBotInfoRequest](d, tlprofile.SemanticMethodBotsSetBotInfo, func(ctx context.Context, layerRequest *tg.BotsSetBotInfoRequest) (any, error) { + return r.onBotsSetBotInfo(ctx, layerRequest) + }) + registerRPC[*tg.BotsGetBotInfoRequest](d, tlprofile.SemanticMethodBotsGetBotInfo, func(ctx context.Context, layerRequest *tg.BotsGetBotInfoRequest) (any, error) { + return r.onBotsGetBotInfo(ctx, layerRequest) + }) + registerRPC[*tg.BotsSetBotMenuButtonRequest](d, tlprofile.SemanticMethodBotsSetBotMenuButton, func(ctx context.Context, layerRequest *tg.BotsSetBotMenuButtonRequest) (any, error) { + return r.onBotsSetBotMenuButton(ctx, layerRequest) + }) + registerRPC[*tg.BotsGetBotMenuButtonRequest](d, tlprofile.SemanticMethodBotsGetBotMenuButton, func(ctx context.Context, layerRequest *tg.BotsGetBotMenuButtonRequest) (any, error) { + return r.onBotsGetBotMenuButton(ctx, layerRequest. + UserID) + }) + registerRPC[*tg.BotsReorderUsernamesRequest](d, tlprofile.SemanticMethodBotsReorderUsernames, func(ctx context.Context, layerRequest *tg.BotsReorderUsernamesRequest) (any, error) { + return r.onBotsReorderUsernames(ctx, layerRequest) + }) + registerRPC[*tg.BotsToggleUsernameRequest](d, tlprofile.SemanticMethodBotsToggleUsername, func(ctx context.Context, layerRequest *tg.BotsToggleUsernameRequest) (any, error) { + return r.onBotsToggleUsername(ctx, layerRequest) + }) + registerRPC[*tg.BotsCanSendMessageRequest](d, tlprofile.SemanticMethodBotsCanSendMessage, func(ctx context.Context, layerRequest *tg.BotsCanSendMessageRequest) (any, error) { + return r.onBotsCanSendMessage(ctx, layerRequest. + Bot) + }) + registerRPC[*tg.BotsAllowSendMessageRequest](d, tlprofile.SemanticMethodBotsAllowSendMessage, func(ctx context.Context, layerRequest *tg.BotsAllowSendMessageRequest) (any, error) { + return r.onBotsAllowSendMessage(ctx, layerRequest. + Bot) + }) + registerRPC[*tg.BotsInvokeWebViewCustomMethodRequest](d, tlprofile.SemanticMethodBotsInvokeWebViewCustomMethod, func(ctx context.Context, layerRequest *tg.BotsInvokeWebViewCustomMethodRequest) (any, error) { + return r.onBotsInvokeWebViewCustomMethod(ctx, layerRequest) + }) + registerRPC[*tg.BotsGetPopularAppBotsRequest](d, tlprofile.SemanticMethodBotsGetPopularAppBots, func(ctx context.Context, layerRequest *tg.BotsGetPopularAppBotsRequest) (any, error) { + return r.onBotsGetPopularAppBots(ctx, layerRequest) + }) + registerRPC[*tg.BotsAddPreviewMediaRequest](d, tlprofile.SemanticMethodBotsAddPreviewMedia, func(ctx context.Context, layerRequest *tg.BotsAddPreviewMediaRequest) (any, error) { + return r.onBotsAddPreviewMedia(ctx, layerRequest) + }) + registerRPC[*tg.BotsEditPreviewMediaRequest](d, tlprofile.SemanticMethodBotsEditPreviewMedia, func(ctx context.Context, layerRequest *tg.BotsEditPreviewMediaRequest) (any, error) { + return r.onBotsEditPreviewMedia(ctx, layerRequest) + }) + registerRPC[*tg.BotsDeletePreviewMediaRequest](d, tlprofile.SemanticMethodBotsDeletePreviewMedia, func(ctx context.Context, layerRequest *tg.BotsDeletePreviewMediaRequest) (any, error) { + return r.onBotsDeletePreviewMedia(ctx, layerRequest) + }) + registerRPC[*tg.BotsReorderPreviewMediasRequest](d, tlprofile.SemanticMethodBotsReorderPreviewMedias, func(ctx context.Context, layerRequest *tg.BotsReorderPreviewMediasRequest) (any, error) { + return r.onBotsReorderPreviewMedias(ctx, layerRequest) + }) + registerRPC[*tg.BotsGetPreviewInfoRequest](d, tlprofile.SemanticMethodBotsGetPreviewInfo, func(ctx context.Context, layerRequest *tg.BotsGetPreviewInfoRequest) (any, error) { + return r.onBotsGetPreviewInfo(ctx, layerRequest) + }) + registerRPC[*tg.BotsGetPreviewMediasRequest](d, tlprofile.SemanticMethodBotsGetPreviewMedias, func(ctx context.Context, layerRequest *tg.BotsGetPreviewMediasRequest) (any, error) { + return r.onBotsGetPreviewMedias(ctx, layerRequest. + Bot) + }) + registerRPC[*tg.BotsUpdateUserEmojiStatusRequest](d, tlprofile.SemanticMethodBotsUpdateUserEmojiStatus, func(ctx context.Context, layerRequest *tg.BotsUpdateUserEmojiStatusRequest) (any, error) { + return r.onBotsUpdateUserEmojiStatus(ctx, layerRequest) + }) + registerRPC[*tg.BotsToggleUserEmojiStatusPermissionRequest](d, tlprofile.SemanticMethodBotsToggleUserEmojiStatusPermission, func(ctx context.Context, layerRequest *tg.BotsToggleUserEmojiStatusPermissionRequest) (any, error) { + return r.onBotsToggleUserEmojiStatusPermission(ctx, layerRequest) + }) + registerRPC[*tg.BotsCheckDownloadFileParamsRequest](d, tlprofile.SemanticMethodBotsCheckDownloadFileParams, func(ctx context.Context, layerRequest *tg.BotsCheckDownloadFileParamsRequest) (any, error) { + return r.onBotsCheckDownloadFileParams(ctx, layerRequest) + }) + registerRPC[*tg.BotsGetAdminedBotsRequest](d, tlprofile.SemanticMethodBotsGetAdminedBots, func(ctx context.Context, layerRequest *tg.BotsGetAdminedBotsRequest) (any, error) { + return r.onBotsGetAdminedBots(ctx) + }) + registerRPC[*tg.BotsUpdateStarRefProgramRequest](d, tlprofile.SemanticMethodBotsUpdateStarRefProgram, func(ctx context.Context, layerRequest *tg.BotsUpdateStarRefProgramRequest) (any, error) { + return r.onBotsUpdateStarRefProgram(ctx, layerRequest) + }) + registerRPC[*tg.BotsSetCustomVerificationRequest](d, tlprofile.SemanticMethodBotsSetCustomVerification, func(ctx context.Context, layerRequest *tg.BotsSetCustomVerificationRequest) (any, error) { + return r.onBotsSetCustomVerification(ctx, layerRequest) + }) + registerRPC[*tg.BotsGetBotRecommendationsRequest](d, tlprofile.SemanticMethodBotsGetBotRecommendations, func(ctx context.Context, layerRequest *tg.BotsGetBotRecommendationsRequest) (any, error) { + return r.onBotsGetBotRecommendations(ctx, layerRequest. + Bot) + }) + registerRPC[*tg.BotsCheckUsernameRequest](d, tlprofile.SemanticMethodBotsCheckUsername, func(ctx context.Context, layerRequest *tg.BotsCheckUsernameRequest) (any, error) { + return r.onBotsCheckUsername(ctx, layerRequest. + Username) + }) + registerRPC[*tg.BotsCreateBotRequest](d, tlprofile.SemanticMethodBotsCreateBot, func(ctx context.Context, layerRequest *tg.BotsCreateBotRequest) (any, error) { + return r.onBotsCreateBot(ctx, layerRequest) + }) + registerRPC[*tg.BotsExportBotTokenRequest](d, tlprofile.SemanticMethodBotsExportBotToken, func(ctx context.Context, layerRequest *tg.BotsExportBotTokenRequest) (any, error) { + return r.onBotsExportBotToken(ctx, layerRequest) + }) + registerRPC[*tg.BotsRequestWebViewButtonRequest](d, tlprofile.SemanticMethodBotsRequestWebViewButton, func(ctx context.Context, layerRequest *tg.BotsRequestWebViewButtonRequest) (any, error) { + return r.onBotsRequestWebViewButton(ctx, layerRequest) + }) + registerRPC[*tg.BotsGetRequestedWebViewButtonRequest](d, tlprofile.SemanticMethodBotsGetRequestedWebViewButton, func(ctx context.Context, layerRequest *tg.BotsGetRequestedWebViewButtonRequest) (any, error) { + return r.onBotsGetRequestedWebViewButton(ctx, layerRequest) + }) + registerRPC[*tg.BotsGetAccessSettingsRequest](d, tlprofile.SemanticMethodBotsGetAccessSettings, func(ctx context.Context, layerRequest *tg.BotsGetAccessSettingsRequest) ( + + // P3:startBot 深链 + inline callback 闭环。 + any, error) { + return r.onBotsGetAccessSettings(ctx, layerRequest. + Bot) + }) + registerRPC[*tg.BotsEditAccessSettingsRequest](d, tlprofile.SemanticMethodBotsEditAccessSettings, func(ctx context.Context, layerRequest *tg.BotsEditAccessSettingsRequest) (any, error) { + return r.onBotsEditAccessSettings(ctx, layerRequest) + }) + registerRPC[*tg.MessagesStartBotRequest](d, tlprofile.SemanticMethodMessagesStartBot, func(ctx context.Context, layerRequest *tg.MessagesStartBotRequest) (any, error) { + return r.onMessagesStartBot(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetBotCallbackAnswerRequest](d, tlprofile.SemanticMethodMessagesGetBotCallbackAnswer, func(ctx context.Context, layerRequest *tg.MessagesGetBotCallbackAnswerRequest) (any, error) { + return r.onMessagesGetBotCallbackAnswer(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetBotCallbackAnswerRequest](d, tlprofile.SemanticMethodMessagesSetBotCallbackAnswer, func(ctx context.Context, layerRequest *tg.MessagesSetBotCallbackAnswerRequest) (any, error) { + return r.onMessagesSetBotCallbackAnswer(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetInlineBotResultsRequest](d, tlprofile.SemanticMethodMessagesGetInlineBotResults, func(ctx context.Context, layerRequest *tg.MessagesGetInlineBotResultsRequest) (any, error) { + return r.onMessagesGetInlineBotResults(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetInlineBotResultsRequest](d, tlprofile.SemanticMethodMessagesSetInlineBotResults, func(ctx context.Context, layerRequest *tg.MessagesSetInlineBotResultsRequest) (any, error) { + return r.onMessagesSetInlineBotResults(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendInlineBotResultRequest](d, tlprofile.SemanticMethodMessagesSendInlineBotResult, func(ctx context.Context, layerRequest *tg.MessagesSendInlineBotResultRequest) (any, error) { + return r.onMessagesSendInlineBotResult(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSavePreparedInlineMessageRequest](d, tlprofile.SemanticMethodMessagesSavePreparedInlineMessage, func(ctx context.Context, layerRequest *tg.MessagesSavePreparedInlineMessageRequest) (any, error) { + return r.onMessagesSavePreparedInlineMessage(ctx, layerRequest) + }) + registerRPC[*tg.MessagesEditInlineBotMessageRequest](d, tlprofile.SemanticMethodMessagesEditInlineBotMessage, func(ctx context.Context, layerRequest *tg.MessagesEditInlineBotMessageRequest) (any, error) { + return r.onMessagesEditInlineBotMessage(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetBotShippingResultsRequest](d, tlprofile.SemanticMethodMessagesSetBotShippingResults, func(ctx context.Context, layerRequest *tg.MessagesSetBotShippingResultsRequest) (any, error) { + return r.onMessagesSetBotShippingResults(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetBotPrecheckoutResultsRequest](d, tlprofile.SemanticMethodMessagesSetBotPrecheckoutResults, func(ctx context.Context, + + // callerBotID 校验调用者本身是 bot 账号,返回其 user_id(bot-only RPC 用)。 + layerRequest *tg.MessagesSetBotPrecheckoutResultsRequest) (any, error) { + return r.onMessagesSetBotPrecheckoutResults(ctx, layerRequest) + }) } -// callerBotID 校验调用者本身是 bot 账号,返回其 user_id(bot-only RPC 用)。 func (r *Router) callerBotID(ctx context.Context) (int64, error) { userID, _, err := r.currentUserID(ctx) if err != nil { diff --git a/internal/rpc/channels_delete_monoforum_test.go b/internal/rpc/channels_delete_monoforum_test.go index 9d21acf1..d4fb12b9 100644 --- a/internal/rpc/channels_delete_monoforum_test.go +++ b/internal/rpc/channels_delete_monoforum_test.go @@ -64,12 +64,8 @@ func TestChannelsDeleteChannelCascadesMonoforumForbiddenRPC(t *testing.T) { if err != nil { t.Fatalf("dispatch get dialogs: %v", err) } - box, ok := enc.(*tg.MessagesDialogsBox) - if !ok { - t.Fatalf("dialogs response = %T, want box", enc) - } ids := map[int64]struct{}{} - switch d := box.Dialogs.(type) { + switch d := enc.(type) { case *tg.MessagesDialogs: for _, ch := range d.Chats { if c, ok := ch.(*tg.Channel); ok { @@ -83,7 +79,7 @@ func TestChannelsDeleteChannelCascadesMonoforumForbiddenRPC(t *testing.T) { } } default: - t.Fatalf("dialogs = %T, want messages.dialogs(Slice)", box.Dialogs) + t.Fatalf("dialogs = %T, want messages.dialogs(Slice)", enc) } return ids } diff --git a/internal/rpc/channels_dialogs_rpc_test.go b/internal/rpc/channels_dialogs_rpc_test.go index 07871390..409b2fdc 100644 --- a/internal/rpc/channels_dialogs_rpc_test.go +++ b/internal/rpc/channels_dialogs_rpc_test.go @@ -347,13 +347,12 @@ func TestChannelDialogCarriesChannelPts(t *testing.T) { } got := dispatch(&tg.MessagesGetDialogsRequest{OffsetPeer: &tg.InputPeerEmpty{}, Limit: 20}) - box, ok := got.(*tg.MessagesDialogsBox) + dialogs, ok := got.(*tg.MessagesDialogs) if !ok { - t.Fatalf("dialogs response = %T, want box", got) + t.Fatalf("dialogs response = %T, want *tg.MessagesDialogs", got) } - dialogs, ok := box.Dialogs.(*tg.MessagesDialogs) - if !ok || len(dialogs.Dialogs) != 1 { - t.Fatalf("dialogs = %T %+v, want one channel dialog", box.Dialogs, box.Dialogs) + if len(dialogs.Dialogs) != 1 { + t.Fatalf("dialogs = %+v, want one channel dialog", dialogs) } dialog, ok := dialogs.Dialogs[0].(*tg.Dialog) if !ok { diff --git a/internal/rpc/channels_messages_rpc_test.go b/internal/rpc/channels_messages_rpc_test.go index fb06e9cd..9eb3e394 100644 --- a/internal/rpc/channels_messages_rpc_test.go +++ b/internal/rpc/channels_messages_rpc_test.go @@ -58,13 +58,9 @@ func TestChannelsDeleteChannelReturnsForbiddenChatAndHidesDialogRPC(t *testing.T if err != nil { t.Fatalf("dispatch get dialogs: %v", err) } - box, ok := enc.(*tg.MessagesDialogsBox) + dialogs, ok := enc.(*tg.MessagesDialogs) if !ok { - t.Fatalf("dialogs response = %T, want box", enc) - } - dialogs, ok := box.Dialogs.(*tg.MessagesDialogs) - if !ok { - t.Fatalf("dialogs = %T %+v, want messages.dialogs", box.Dialogs, box.Dialogs) + t.Fatalf("dialogs response = %T, want *tg.MessagesDialogs", enc) } return dialogs } @@ -380,7 +376,7 @@ func TestChannelsDeleteHistoryForEveryoneDrainsBatchesAndKeepsDialogVisible(t *t if err != nil { t.Fatalf("dispatch get dialogs: %v", err) } - dialogs, ok := enc.(*tg.MessagesDialogsBox).Dialogs.(*tg.MessagesDialogs) + dialogs, ok := enc.(*tg.MessagesDialogs) if !ok { t.Fatalf("dialogs response = %T, want messages.dialogs", enc) } diff --git a/internal/rpc/channels_multi_pin_android_rpc_test.go b/internal/rpc/channels_multi_pin_android_rpc_test.go index 2d62092b..4ec6efa4 100644 --- a/internal/rpc/channels_multi_pin_android_rpc_test.go +++ b/internal/rpc/channels_multi_pin_android_rpc_test.go @@ -103,9 +103,6 @@ func TestChannelMultiPinAndroidOpenAndJump(t *testing.T) { Filter: &tg.InputMessagesFilterPinned{}, Limit: 40, }) - if box, ok := searchEnc.(*tg.MessagesMessagesBox); ok { - searchEnc = box.Messages - } channelMessages, ok := searchEnc.(*tg.MessagesChannelMessages) if !ok { t.Fatalf("pinned search response = %T, want messages.channelMessages", searchEnc) diff --git a/internal/rpc/channels_public_preview_rpc_test.go b/internal/rpc/channels_public_preview_rpc_test.go index cce1cd24..fe40fdbf 100644 --- a/internal/rpc/channels_public_preview_rpc_test.go +++ b/internal/rpc/channels_public_preview_rpc_test.go @@ -102,13 +102,9 @@ func TestPublicChannelPreviewRPCsAllowNonMember(t *testing.T) { if err != nil { t.Fatalf("dispatch getHistory public preview: %v", err) } - box, ok := enc.(*tg.MessagesMessagesBox) + history, ok := enc.(*tg.MessagesChannelMessages) if !ok { - t.Fatalf("getHistory response = %T, want boxed messages", enc) - } - history, ok := box.Messages.(*tg.MessagesChannelMessages) - if !ok { - t.Fatalf("boxed getHistory = %T, want channel messages", box.Messages) + t.Fatalf("getHistory response = %T, want *tg.MessagesChannelMessages", enc) } foundPost := false for _, item := range history.Messages { diff --git a/internal/rpc/channels_register.go b/internal/rpc/channels_register.go index 6be28641..0d977dde 100644 --- a/internal/rpc/channels_register.go +++ b/internal/rpc/channels_register.go @@ -1,101 +1,301 @@ package rpc import ( + "context" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) // registerChannels 注册超级群/频道相关 RPC。messages.createChat 在这里注册, // 因为 telesrv 将普通群创建直接实现为 megagroup。 -func (r *Router) registerChannels(d *tg.ServerDispatcher) { - d.OnMessagesCreateChat(r.onMessagesCreateChat) - d.OnMessagesMigrateChat(r.onMessagesMigrateChat) - d.OnMessagesGetChats(r.onMessagesGetChats) - d.OnMessagesGetFullChat(r.onMessagesGetFullChat) - d.OnMessagesAddChatUser(r.onMessagesAddChatUser) - d.OnMessagesDeleteChatUser(r.onMessagesDeleteChatUser) - d.OnMessagesEditChatTitle(r.onMessagesEditChatTitle) - d.OnMessagesEditChatPhoto(r.onMessagesEditChatPhoto) - d.OnMessagesEditChatAdmin(r.onMessagesEditChatAdmin) - d.OnMessagesEditChatAbout(r.onMessagesEditChatAbout) - d.OnMessagesEditChatDefaultBannedRights(r.onMessagesEditChatDefaultBannedRights) - d.OnMessagesEditChatCreator(r.onMessagesEditChatCreator) - d.OnMessagesGetFutureChatCreatorAfterLeave(r.onMessagesGetFutureChatCreatorAfterLeave) - d.OnMessagesEditChatParticipantRank(r.onMessagesEditChatParticipantRank) - d.OnMessagesSetChatTheme(r.onMessagesSetChatTheme) - d.OnMessagesSetChatWallPaper(r.onMessagesSetChatWallPaper) - d.OnMessagesToggleNoForwards(r.onMessagesToggleNoForwards) - d.OnMessagesSetChatAvailableReactions(r.onMessagesSetChatAvailableReactions) - d.OnChannelsCreateChannel(r.onChannelsCreateChannel) - d.OnChannelsGetChannels(r.onChannelsGetChannels) - d.OnChannelsGetFullChannel(r.onChannelsGetFullChannel) - d.OnChannelsGetParticipants(r.onChannelsGetParticipants) - d.OnChannelsGetParticipant(r.onChannelsGetParticipant) - d.OnChannelsGetSendAs(r.onChannelsGetSendAs) - d.OnChannelsCheckUsername(r.onChannelsCheckUsername) - d.OnChannelsUpdateUsername(r.onChannelsUpdateUsername) - d.OnChannelsGetAdminedPublicChannels(r.onChannelsGetAdminedPublicChannels) - d.OnChannelsExportMessageLink(r.onChannelsExportMessageLink) - d.OnChannelsToggleSignatures(r.onChannelsToggleSignatures) - d.OnChannelsTogglePreHistoryHidden(r.onChannelsTogglePreHistoryHidden) - d.OnChannelsToggleSlowMode(r.onChannelsToggleSlowMode) - d.OnChannelsSetStickers(r.onChannelsSetStickers) - d.OnChannelsSetEmojiStickers(r.onChannelsSetEmojiStickers) - d.OnChannelsReorderUsernames(r.onChannelsReorderUsernames) - d.OnChannelsToggleUsername(r.onChannelsToggleUsername) - d.OnChannelsDeactivateAllUsernames(r.onChannelsDeactivateAllUsernames) - d.OnChannelsUpdateColor(r.onChannelsUpdateColor) - d.OnChannelsUpdateEmojiStatus(r.onChannelsUpdateEmojiStatus) - d.OnChannelsReadMessageContents(r.onChannelsReadMessageContents) - d.OnChannelsReportSpam(r.onChannelsReportSpam) - d.OnChannelsGetLeftChannels(r.onChannelsGetLeftChannels) - d.OnChannelsGetInactiveChannels(r.onChannelsGetInactiveChannels) - d.OnChannelsGetGroupsForDiscussion(r.onChannelsGetGroupsForDiscussion) - d.OnChannelsSetDiscussionGroup(r.onChannelsSetDiscussionGroup) - d.OnChannelsEditLocation(r.onChannelsEditLocation) - d.OnChannelsConvertToGigagroup(r.onChannelsConvertToGigagroup) - d.OnChannelsDeleteParticipantHistory(r.onChannelsDeleteParticipantHistory) - d.OnChannelsToggleJoinToSend(r.onChannelsToggleJoinToSend) - d.OnChannelsToggleJoinRequest(r.onChannelsToggleJoinRequest) - d.OnChannelsToggleForum(r.onChannelsToggleForum) - d.OnChannelsToggleAntiSpam(r.onChannelsToggleAntiSpam) - d.OnChannelsReportAntiSpamFalsePositive(r.onChannelsReportAntiSpamFalsePositive) - d.OnChannelsToggleParticipantsHidden(r.onChannelsToggleParticipantsHidden) - d.OnChannelsToggleViewForumAsMessages(r.onChannelsToggleViewForumAsMessages) - d.OnChannelsGetChannelRecommendations(r.onChannelsGetChannelRecommendations) - d.OnChannelsSetBoostsToUnblockRestrictions(r.onChannelsSetBoostsToUnblockRestrictions) - d.OnChannelsRestrictSponsoredMessages(r.onChannelsRestrictSponsoredMessages) - d.OnChannelsSearchPosts(r.onChannelsSearchPosts) - d.OnChannelsUpdatePaidMessagesPrice(r.onChannelsUpdatePaidMessagesPrice) - d.OnChannelsToggleAutotranslation(r.onChannelsToggleAutotranslation) - d.OnChannelsGetMessageAuthor(r.onChannelsGetMessageAuthor) - d.OnChannelsCheckSearchPostsFlood(r.onChannelsCheckSearchPostsFlood) - d.OnChannelsSetMainProfileTab(r.onChannelsSetMainProfileTab) - d.OnChannelsInviteToChannel(r.onChannelsInviteToChannel) - d.OnChannelsJoinChannel(r.onChannelsJoinChannel) - d.OnChannelsLeaveChannel(r.onChannelsLeaveChannel) - d.OnChannelsEditAdmin(r.onChannelsEditAdmin) - d.OnChannelsEditBanned(r.onChannelsEditBanned) - d.OnChannelsEditTitle(r.onChannelsEditTitle) - d.OnChannelsEditPhoto(r.onChannelsEditPhoto) - d.OnChannelsDeleteChannel(r.onChannelsDeleteChannel) - d.OnChannelsGetAdminLog(r.onChannelsGetAdminLog) - d.OnChannelsReadHistory(r.onChannelsReadHistory) - d.OnChannelsGetMessages(r.onChannelsGetMessages) - d.OnChannelsDeleteMessages(r.onChannelsDeleteMessages) - d.OnChannelsDeleteHistory(r.onChannelsDeleteHistory) - d.OnMessagesUpdatePinnedMessage(r.onMessagesUpdatePinnedMessage) - d.OnMessagesUnpinAllMessages(r.onMessagesUnpinAllMessages) - d.OnMessagesExportChatInvite(r.onMessagesExportChatInvite) - d.OnMessagesCheckChatInvite(r.onMessagesCheckChatInvite) - d.OnMessagesImportChatInvite(r.onMessagesImportChatInvite) - d.OnMessagesGetExportedChatInvites(r.onMessagesGetExportedChatInvites) - d.OnMessagesGetExportedChatInvite(r.onMessagesGetExportedChatInvite) - d.OnMessagesEditExportedChatInvite(r.onMessagesEditExportedChatInvite) - d.OnMessagesDeleteRevokedExportedChatInvites(r.onMessagesDeleteRevokedExportedChatInvites) - d.OnMessagesDeleteExportedChatInvite(r.onMessagesDeleteExportedChatInvite) - d.OnMessagesGetAdminsWithInvites(r.onMessagesGetAdminsWithInvites) - d.OnMessagesGetChatInviteImporters(r.onMessagesGetChatInviteImporters) - d.OnMessagesHideChatJoinRequest(r.onMessagesHideChatJoinRequest) - d.OnMessagesHideAllChatJoinRequests(r.onMessagesHideAllChatJoinRequests) - d.OnUpdatesGetChannelDifference(r.onUpdatesGetChannelDifference) +func (r *Router) registerChannels(d *tlprofile.Dispatcher) { + registerRPC[*tg.MessagesCreateChatRequest](d, tlprofile.SemanticMethodMessagesCreateChat, func(ctx context.Context, layerRequest *tg.MessagesCreateChatRequest) (any, error) { + return r.onMessagesCreateChat(ctx, layerRequest) + }) + registerRPC[*tg.MessagesMigrateChatRequest](d, tlprofile.SemanticMethodMessagesMigrateChat, func(ctx context.Context, layerRequest *tg.MessagesMigrateChatRequest) (any, error) { + return r.onMessagesMigrateChat(ctx, layerRequest. + ChatID) + }) + registerRPC[*tg.MessagesGetChatsRequest](d, tlprofile.SemanticMethodMessagesGetChats, func(ctx context.Context, layerRequest *tg.MessagesGetChatsRequest) (any, error) { + return r.onMessagesGetChats(ctx, layerRequest. + ID) + }) + registerRPC[*tg.MessagesGetFullChatRequest](d, tlprofile.SemanticMethodMessagesGetFullChat, func(ctx context.Context, layerRequest *tg.MessagesGetFullChatRequest) (any, error) { + return r.onMessagesGetFullChat(ctx, layerRequest. + ChatID) + }) + registerRPC[*tg.MessagesAddChatUserRequest](d, tlprofile.SemanticMethodMessagesAddChatUser, func(ctx context.Context, layerRequest *tg.MessagesAddChatUserRequest) (any, error) { + return r.onMessagesAddChatUser(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteChatUserRequest](d, tlprofile.SemanticMethodMessagesDeleteChatUser, func(ctx context.Context, layerRequest *tg.MessagesDeleteChatUserRequest) (any, error) { + return r.onMessagesDeleteChatUser(ctx, layerRequest) + }) + registerRPC[*tg.MessagesEditChatTitleRequest](d, tlprofile.SemanticMethodMessagesEditChatTitle, func(ctx context.Context, layerRequest *tg.MessagesEditChatTitleRequest) (any, error) { + return r.onMessagesEditChatTitle(ctx, layerRequest) + }) + registerRPC[*tg.MessagesEditChatPhotoRequest](d, tlprofile.SemanticMethodMessagesEditChatPhoto, func(ctx context.Context, layerRequest *tg.MessagesEditChatPhotoRequest) (any, error) { + return r.onMessagesEditChatPhoto(ctx, layerRequest) + }) + registerRPC[*tg.MessagesEditChatAdminRequest](d, tlprofile.SemanticMethodMessagesEditChatAdmin, func(ctx context.Context, layerRequest *tg.MessagesEditChatAdminRequest) (any, error) { + return r.onMessagesEditChatAdmin(ctx, layerRequest) + }) + registerRPC[*tg.MessagesEditChatAboutRequest](d, tlprofile.SemanticMethodMessagesEditChatAbout, func(ctx context.Context, layerRequest *tg.MessagesEditChatAboutRequest) (any, error) { + return r.onMessagesEditChatAbout(ctx, layerRequest) + }) + registerRPC[*tg.MessagesEditChatDefaultBannedRightsRequest](d, tlprofile.SemanticMethodMessagesEditChatDefaultBannedRights, func(ctx context.Context, layerRequest *tg.MessagesEditChatDefaultBannedRightsRequest) (any, error) { + return r.onMessagesEditChatDefaultBannedRights(ctx, layerRequest) + }) + registerRPC[*tg.MessagesEditChatCreatorRequest](d, tlprofile.SemanticMethodMessagesEditChatCreator, func(ctx context.Context, layerRequest *tg.MessagesEditChatCreatorRequest) (any, error) { + return r.onMessagesEditChatCreator(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetFutureChatCreatorAfterLeaveRequest](d, tlprofile.SemanticMethodMessagesGetFutureChatCreatorAfterLeave, func(ctx context.Context, layerRequest *tg.MessagesGetFutureChatCreatorAfterLeaveRequest) (any, error) { + return r.onMessagesGetFutureChatCreatorAfterLeave(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.MessagesEditChatParticipantRankRequest](d, tlprofile.SemanticMethodMessagesEditChatParticipantRank, func(ctx context.Context, layerRequest *tg.MessagesEditChatParticipantRankRequest) (any, error) { + return r.onMessagesEditChatParticipantRank(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetChatThemeRequest](d, tlprofile.SemanticMethodMessagesSetChatTheme, func(ctx context.Context, layerRequest *tg.MessagesSetChatThemeRequest) (any, error) { + return r.onMessagesSetChatTheme(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetChatWallPaperRequest](d, tlprofile.SemanticMethodMessagesSetChatWallPaper, func(ctx context.Context, layerRequest *tg.MessagesSetChatWallPaperRequest) (any, error) { + return r.onMessagesSetChatWallPaper(ctx, layerRequest) + }) + registerRPC[*tg.MessagesToggleNoForwardsRequest](d, tlprofile.SemanticMethodMessagesToggleNoForwards, func(ctx context.Context, layerRequest *tg.MessagesToggleNoForwardsRequest) (any, error) { + return r.onMessagesToggleNoForwards(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetChatAvailableReactionsRequest](d, tlprofile.SemanticMethodMessagesSetChatAvailableReactions, func(ctx context.Context, layerRequest *tg.MessagesSetChatAvailableReactionsRequest) (any, error) { + return r.onMessagesSetChatAvailableReactions(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsCreateChannelRequest](d, tlprofile.SemanticMethodChannelsCreateChannel, func(ctx context.Context, layerRequest *tg.ChannelsCreateChannelRequest) (any, error) { + return r.onChannelsCreateChannel(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsGetChannelsRequest](d, tlprofile.SemanticMethodChannelsGetChannels, func(ctx context.Context, layerRequest *tg.ChannelsGetChannelsRequest) (any, error) { + return r.onChannelsGetChannels(ctx, layerRequest. + ID) + }) + registerRPC[*tg.ChannelsGetFullChannelRequest](d, tlprofile.SemanticMethodChannelsGetFullChannel, func(ctx context.Context, layerRequest *tg.ChannelsGetFullChannelRequest) (any, error) { + return r.onChannelsGetFullChannel(ctx, layerRequest. + Channel) + }) + registerRPC[*tg.ChannelsGetParticipantsRequest](d, tlprofile.SemanticMethodChannelsGetParticipants, func(ctx context.Context, layerRequest *tg.ChannelsGetParticipantsRequest) (any, error) { + return r.onChannelsGetParticipants(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsGetParticipantRequest](d, tlprofile.SemanticMethodChannelsGetParticipant, func(ctx context.Context, layerRequest *tg.ChannelsGetParticipantRequest) (any, error) { + return r.onChannelsGetParticipant(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsGetSendAsRequest](d, tlprofile.SemanticMethodChannelsGetSendAs, func(ctx context.Context, layerRequest *tg.ChannelsGetSendAsRequest) (any, error) { + return r.onChannelsGetSendAs(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsCheckUsernameRequest](d, tlprofile.SemanticMethodChannelsCheckUsername, func(ctx context.Context, layerRequest *tg.ChannelsCheckUsernameRequest) (any, error) { + return r.onChannelsCheckUsername(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsUpdateUsernameRequest](d, tlprofile.SemanticMethodChannelsUpdateUsername, func(ctx context.Context, layerRequest *tg.ChannelsUpdateUsernameRequest) (any, error) { + return r.onChannelsUpdateUsername(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsGetAdminedPublicChannelsRequest](d, tlprofile.SemanticMethodChannelsGetAdminedPublicChannels, func(ctx context.Context, layerRequest *tg.ChannelsGetAdminedPublicChannelsRequest) (any, error) { + return r.onChannelsGetAdminedPublicChannels(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsExportMessageLinkRequest](d, tlprofile.SemanticMethodChannelsExportMessageLink, func(ctx context.Context, layerRequest *tg.ChannelsExportMessageLinkRequest) (any, error) { + return r.onChannelsExportMessageLink(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsToggleSignaturesRequest](d, tlprofile.SemanticMethodChannelsToggleSignatures, func(ctx context.Context, layerRequest *tg.ChannelsToggleSignaturesRequest) (any, error) { + return r.onChannelsToggleSignatures(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsTogglePreHistoryHiddenRequest](d, tlprofile.SemanticMethodChannelsTogglePreHistoryHidden, func(ctx context.Context, layerRequest *tg.ChannelsTogglePreHistoryHiddenRequest) (any, error) { + return r.onChannelsTogglePreHistoryHidden(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsToggleSlowModeRequest](d, tlprofile.SemanticMethodChannelsToggleSlowMode, func(ctx context.Context, layerRequest *tg.ChannelsToggleSlowModeRequest) (any, error) { + return r.onChannelsToggleSlowMode(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsSetStickersRequest](d, tlprofile.SemanticMethodChannelsSetStickers, func(ctx context.Context, layerRequest *tg.ChannelsSetStickersRequest) (any, error) { + return r.onChannelsSetStickers(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsSetEmojiStickersRequest](d, tlprofile.SemanticMethodChannelsSetEmojiStickers, func(ctx context.Context, layerRequest *tg.ChannelsSetEmojiStickersRequest) (any, error) { + return r.onChannelsSetEmojiStickers(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsReorderUsernamesRequest](d, tlprofile.SemanticMethodChannelsReorderUsernames, func(ctx context.Context, layerRequest *tg.ChannelsReorderUsernamesRequest) (any, error) { + return r.onChannelsReorderUsernames(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsToggleUsernameRequest](d, tlprofile.SemanticMethodChannelsToggleUsername, func(ctx context.Context, layerRequest *tg.ChannelsToggleUsernameRequest) (any, error) { + return r.onChannelsToggleUsername(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsDeactivateAllUsernamesRequest](d, tlprofile.SemanticMethodChannelsDeactivateAllUsernames, func(ctx context.Context, layerRequest *tg.ChannelsDeactivateAllUsernamesRequest) (any, error) { + return r.onChannelsDeactivateAllUsernames(ctx, layerRequest. + Channel) + }) + registerRPC[*tg.ChannelsUpdateColorRequest](d, tlprofile.SemanticMethodChannelsUpdateColor, func(ctx context.Context, layerRequest *tg.ChannelsUpdateColorRequest) (any, error) { + return r.onChannelsUpdateColor(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsUpdateEmojiStatusRequest](d, tlprofile.SemanticMethodChannelsUpdateEmojiStatus, func(ctx context.Context, layerRequest *tg.ChannelsUpdateEmojiStatusRequest) (any, error) { + return r.onChannelsUpdateEmojiStatus(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsReadMessageContentsRequest](d, tlprofile.SemanticMethodChannelsReadMessageContents, func(ctx context.Context, layerRequest *tg.ChannelsReadMessageContentsRequest) (any, error) { + return r.onChannelsReadMessageContents(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsReportSpamRequest](d, tlprofile.SemanticMethodChannelsReportSpam, func(ctx context.Context, layerRequest *tg.ChannelsReportSpamRequest) (any, error) { + return r.onChannelsReportSpam(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsGetLeftChannelsRequest](d, tlprofile.SemanticMethodChannelsGetLeftChannels, func(ctx context.Context, layerRequest *tg.ChannelsGetLeftChannelsRequest) (any, error) { + return r.onChannelsGetLeftChannels(ctx, layerRequest. + Offset) + }) + registerRPC[*tg.ChannelsGetInactiveChannelsRequest](d, tlprofile.SemanticMethodChannelsGetInactiveChannels, func(ctx context.Context, layerRequest *tg.ChannelsGetInactiveChannelsRequest) (any, error) { + return r.onChannelsGetInactiveChannels(ctx) + }) + registerRPC[*tg.ChannelsGetGroupsForDiscussionRequest](d, tlprofile.SemanticMethodChannelsGetGroupsForDiscussion, func(ctx context.Context, layerRequest *tg.ChannelsGetGroupsForDiscussionRequest) (any, error) { + return r.onChannelsGetGroupsForDiscussion(ctx) + }) + registerRPC[*tg.ChannelsSetDiscussionGroupRequest](d, tlprofile.SemanticMethodChannelsSetDiscussionGroup, func(ctx context.Context, layerRequest *tg.ChannelsSetDiscussionGroupRequest) (any, error) { + return r.onChannelsSetDiscussionGroup(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsEditLocationRequest](d, tlprofile.SemanticMethodChannelsEditLocation, func(ctx context.Context, layerRequest *tg.ChannelsEditLocationRequest) (any, error) { + return r.onChannelsEditLocation(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsConvertToGigagroupRequest](d, tlprofile.SemanticMethodChannelsConvertToGigagroup, func(ctx context.Context, layerRequest *tg.ChannelsConvertToGigagroupRequest) (any, error) { + return r.onChannelsConvertToGigagroup(ctx, layerRequest. + Channel) + }) + registerRPC[*tg.ChannelsDeleteParticipantHistoryRequest](d, tlprofile.SemanticMethodChannelsDeleteParticipantHistory, func(ctx context.Context, layerRequest *tg.ChannelsDeleteParticipantHistoryRequest) (any, error) { + return r.onChannelsDeleteParticipantHistory(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsToggleJoinToSendRequest](d, tlprofile.SemanticMethodChannelsToggleJoinToSend, func(ctx context.Context, layerRequest *tg.ChannelsToggleJoinToSendRequest) (any, error) { + return r.onChannelsToggleJoinToSend(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsToggleJoinRequestRequest](d, tlprofile.SemanticMethodChannelsToggleJoinRequest, func(ctx context.Context, layerRequest *tg.ChannelsToggleJoinRequestRequest) (any, error) { + return r.onChannelsToggleJoinRequest(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsToggleForumRequest](d, tlprofile.SemanticMethodChannelsToggleForum, func(ctx context.Context, layerRequest *tg.ChannelsToggleForumRequest) (any, error) { + return r.onChannelsToggleForum(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsToggleAntiSpamRequest](d, tlprofile.SemanticMethodChannelsToggleAntiSpam, func(ctx context.Context, layerRequest *tg.ChannelsToggleAntiSpamRequest) (any, error) { + return r.onChannelsToggleAntiSpam(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsReportAntiSpamFalsePositiveRequest](d, tlprofile.SemanticMethodChannelsReportAntiSpamFalsePositive, func(ctx context.Context, layerRequest *tg.ChannelsReportAntiSpamFalsePositiveRequest) (any, error) { + return r.onChannelsReportAntiSpamFalsePositive(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsToggleParticipantsHiddenRequest](d, tlprofile.SemanticMethodChannelsToggleParticipantsHidden, func(ctx context.Context, layerRequest *tg.ChannelsToggleParticipantsHiddenRequest) (any, error) { + return r.onChannelsToggleParticipantsHidden(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsToggleViewForumAsMessagesRequest](d, tlprofile.SemanticMethodChannelsToggleViewForumAsMessages, func(ctx context.Context, layerRequest *tg.ChannelsToggleViewForumAsMessagesRequest) (any, error) { + return r.onChannelsToggleViewForumAsMessages(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsGetChannelRecommendationsRequest](d, tlprofile.SemanticMethodChannelsGetChannelRecommendations, func(ctx context.Context, layerRequest *tg.ChannelsGetChannelRecommendationsRequest) (any, error) { + return r.onChannelsGetChannelRecommendations(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsSetBoostsToUnblockRestrictionsRequest](d, tlprofile.SemanticMethodChannelsSetBoostsToUnblockRestrictions, func(ctx context.Context, layerRequest *tg.ChannelsSetBoostsToUnblockRestrictionsRequest) (any, error) { + return r.onChannelsSetBoostsToUnblockRestrictions(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsRestrictSponsoredMessagesRequest](d, tlprofile.SemanticMethodChannelsRestrictSponsoredMessages, func(ctx context.Context, layerRequest *tg.ChannelsRestrictSponsoredMessagesRequest) (any, error) { + return r.onChannelsRestrictSponsoredMessages(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsSearchPostsRequest](d, tlprofile.SemanticMethodChannelsSearchPosts, func(ctx context.Context, layerRequest *tg.ChannelsSearchPostsRequest) (any, error) { + return r.onChannelsSearchPosts(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsUpdatePaidMessagesPriceRequest](d, tlprofile.SemanticMethodChannelsUpdatePaidMessagesPrice, func(ctx context.Context, layerRequest *tg.ChannelsUpdatePaidMessagesPriceRequest) (any, error) { + return r.onChannelsUpdatePaidMessagesPrice(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsToggleAutotranslationRequest](d, tlprofile.SemanticMethodChannelsToggleAutotranslation, func(ctx context.Context, layerRequest *tg.ChannelsToggleAutotranslationRequest) (any, error) { + return r.onChannelsToggleAutotranslation(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsGetMessageAuthorRequest](d, tlprofile.SemanticMethodChannelsGetMessageAuthor, func(ctx context.Context, layerRequest *tg.ChannelsGetMessageAuthorRequest) (any, error) { + return r.onChannelsGetMessageAuthor(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsCheckSearchPostsFloodRequest](d, tlprofile.SemanticMethodChannelsCheckSearchPostsFlood, func(ctx context.Context, layerRequest *tg.ChannelsCheckSearchPostsFloodRequest) (any, error) { + return r.onChannelsCheckSearchPostsFlood(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsSetMainProfileTabRequest](d, tlprofile.SemanticMethodChannelsSetMainProfileTab, func(ctx context.Context, layerRequest *tg.ChannelsSetMainProfileTabRequest) (any, error) { + return r.onChannelsSetMainProfileTab(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsInviteToChannelRequest](d, tlprofile.SemanticMethodChannelsInviteToChannel, func(ctx context.Context, layerRequest *tg.ChannelsInviteToChannelRequest) (any, error) { + return r.onChannelsInviteToChannel(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsJoinChannelRequest](d, tlprofile.SemanticMethodChannelsJoinChannel, func(ctx context.Context, layerRequest *tg.ChannelsJoinChannelRequest) (any, error) { + return r.onChannelsJoinChannel(ctx, layerRequest. + Channel) + }) + registerRPC[*tg.ChannelsLeaveChannelRequest](d, tlprofile.SemanticMethodChannelsLeaveChannel, func(ctx context.Context, layerRequest *tg.ChannelsLeaveChannelRequest) (any, error) { + return r.onChannelsLeaveChannel(ctx, layerRequest. + Channel) + }) + registerRPC[*tg.ChannelsEditAdminRequest](d, tlprofile.SemanticMethodChannelsEditAdmin, func(ctx context.Context, layerRequest *tg.ChannelsEditAdminRequest) (any, error) { + return r.onChannelsEditAdmin(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsEditBannedRequest](d, tlprofile.SemanticMethodChannelsEditBanned, func(ctx context.Context, layerRequest *tg.ChannelsEditBannedRequest) (any, error) { + return r.onChannelsEditBanned(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsEditTitleRequest](d, tlprofile.SemanticMethodChannelsEditTitle, func(ctx context.Context, layerRequest *tg.ChannelsEditTitleRequest) (any, error) { + return r.onChannelsEditTitle(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsEditPhotoRequest](d, tlprofile.SemanticMethodChannelsEditPhoto, func(ctx context.Context, layerRequest *tg.ChannelsEditPhotoRequest) (any, error) { + return r.onChannelsEditPhoto(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsDeleteChannelRequest](d, tlprofile.SemanticMethodChannelsDeleteChannel, func(ctx context.Context, layerRequest *tg.ChannelsDeleteChannelRequest) (any, error) { + return r.onChannelsDeleteChannel(ctx, layerRequest. + Channel) + }) + registerRPC[*tg.ChannelsGetAdminLogRequest](d, tlprofile.SemanticMethodChannelsGetAdminLog, func(ctx context.Context, layerRequest *tg.ChannelsGetAdminLogRequest) (any, error) { + return r.onChannelsGetAdminLog(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsReadHistoryRequest](d, tlprofile.SemanticMethodChannelsReadHistory, func(ctx context.Context, layerRequest *tg.ChannelsReadHistoryRequest) (any, error) { + return r.onChannelsReadHistory(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsGetMessagesRequest](d, tlprofile.SemanticMethodChannelsGetMessages, func(ctx context.Context, layerRequest *tg.ChannelsGetMessagesRequest) (any, error) { + return r.onChannelsGetMessages(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsDeleteMessagesRequest](d, tlprofile.SemanticMethodChannelsDeleteMessages, func(ctx context.Context, layerRequest *tg.ChannelsDeleteMessagesRequest) (any, error) { + return r.onChannelsDeleteMessages(ctx, layerRequest) + }) + registerRPC[*tg.ChannelsDeleteHistoryRequest](d, tlprofile.SemanticMethodChannelsDeleteHistory, func(ctx context.Context, layerRequest *tg.ChannelsDeleteHistoryRequest) (any, error) { + return r.onChannelsDeleteHistory(ctx, layerRequest) + }) + registerRPC[*tg.MessagesUpdatePinnedMessageRequest](d, tlprofile.SemanticMethodMessagesUpdatePinnedMessage, func(ctx context.Context, layerRequest *tg.MessagesUpdatePinnedMessageRequest) (any, error) { + return r.onMessagesUpdatePinnedMessage(ctx, layerRequest) + }) + registerRPC[*tg.MessagesUnpinAllMessagesRequest](d, tlprofile.SemanticMethodMessagesUnpinAllMessages, func(ctx context.Context, layerRequest *tg.MessagesUnpinAllMessagesRequest) (any, error) { + return r.onMessagesUnpinAllMessages(ctx, layerRequest) + }) + registerRPC[*tg.MessagesExportChatInviteRequest](d, tlprofile.SemanticMethodMessagesExportChatInvite, func(ctx context.Context, layerRequest *tg.MessagesExportChatInviteRequest) (any, error) { + return r.onMessagesExportChatInvite(ctx, layerRequest) + }) + registerRPC[*tg.MessagesCheckChatInviteRequest](d, tlprofile.SemanticMethodMessagesCheckChatInvite, func(ctx context.Context, layerRequest *tg.MessagesCheckChatInviteRequest) (any, error) { + return r.onMessagesCheckChatInvite(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesImportChatInviteRequest](d, tlprofile.SemanticMethodMessagesImportChatInvite, func(ctx context.Context, layerRequest *tg.MessagesImportChatInviteRequest) (any, error) { + return r.onMessagesImportChatInvite(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesGetExportedChatInvitesRequest](d, tlprofile.SemanticMethodMessagesGetExportedChatInvites, func(ctx context.Context, layerRequest *tg.MessagesGetExportedChatInvitesRequest) (any, error) { + return r.onMessagesGetExportedChatInvites(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetExportedChatInviteRequest](d, tlprofile.SemanticMethodMessagesGetExportedChatInvite, func(ctx context.Context, layerRequest *tg.MessagesGetExportedChatInviteRequest) (any, error) { + return r.onMessagesGetExportedChatInvite(ctx, layerRequest) + }) + registerRPC[*tg.MessagesEditExportedChatInviteRequest](d, tlprofile.SemanticMethodMessagesEditExportedChatInvite, func(ctx context.Context, layerRequest *tg.MessagesEditExportedChatInviteRequest) (any, error) { + return r.onMessagesEditExportedChatInvite(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteRevokedExportedChatInvitesRequest](d, tlprofile.SemanticMethodMessagesDeleteRevokedExportedChatInvites, func(ctx context.Context, layerRequest *tg.MessagesDeleteRevokedExportedChatInvitesRequest) (any, error) { + return r.onMessagesDeleteRevokedExportedChatInvites(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteExportedChatInviteRequest](d, tlprofile.SemanticMethodMessagesDeleteExportedChatInvite, func(ctx context.Context, layerRequest *tg.MessagesDeleteExportedChatInviteRequest) (any, error) { + return r.onMessagesDeleteExportedChatInvite(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetAdminsWithInvitesRequest](d, tlprofile.SemanticMethodMessagesGetAdminsWithInvites, func(ctx context.Context, layerRequest *tg.MessagesGetAdminsWithInvitesRequest) (any, error) { + return r.onMessagesGetAdminsWithInvites(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.MessagesGetChatInviteImportersRequest](d, tlprofile.SemanticMethodMessagesGetChatInviteImporters, func(ctx context.Context, layerRequest *tg.MessagesGetChatInviteImportersRequest) (any, error) { + return r.onMessagesGetChatInviteImporters(ctx, layerRequest) + }) + registerRPC[*tg.MessagesHideChatJoinRequestRequest](d, tlprofile.SemanticMethodMessagesHideChatJoinRequest, func(ctx context.Context, layerRequest *tg.MessagesHideChatJoinRequestRequest) (any, error) { + return r.onMessagesHideChatJoinRequest(ctx, layerRequest) + }) + registerRPC[*tg.MessagesHideAllChatJoinRequestsRequest](d, tlprofile.SemanticMethodMessagesHideAllChatJoinRequests, func(ctx context.Context, layerRequest *tg.MessagesHideAllChatJoinRequestsRequest) (any, error) { + return r.onMessagesHideAllChatJoinRequests(ctx, layerRequest) + }) + registerRPC[*tg.UpdatesGetChannelDifferenceRequest](d, tlprofile.SemanticMethodUpdatesGetChannelDifference, func(ctx context.Context, layerRequest *tg.UpdatesGetChannelDifferenceRequest) (any, error) { + return r.onUpdatesGetChannelDifference(ctx, layerRequest) + }) } diff --git a/internal/rpc/chatlists.go b/internal/rpc/chatlists.go index 628b1fa5..435bb463 100644 --- a/internal/rpc/chatlists.go +++ b/internal/rpc/chatlists.go @@ -6,21 +6,49 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) -func (r *Router) registerChatlists(d *tg.ServerDispatcher) { - d.OnChatlistsExportChatlistInvite(r.onChatlistsExportChatlistInvite) - d.OnChatlistsDeleteExportedInvite(r.onChatlistsDeleteExportedInvite) - d.OnChatlistsEditExportedInvite(r.onChatlistsEditExportedInvite) - d.OnChatlistsGetExportedInvites(r.onChatlistsGetExportedInvites) - d.OnChatlistsCheckChatlistInvite(r.onChatlistsCheckChatlistInvite) - d.OnChatlistsJoinChatlistInvite(r.onChatlistsJoinChatlistInvite) - d.OnChatlistsGetChatlistUpdates(r.onChatlistsGetChatlistUpdates) - d.OnChatlistsJoinChatlistUpdates(r.onChatlistsJoinChatlistUpdates) - d.OnChatlistsHideChatlistUpdates(r.onChatlistsHideChatlistUpdates) - d.OnChatlistsGetLeaveChatlistSuggestions(r.onChatlistsGetLeaveChatlistSuggestions) - d.OnChatlistsLeaveChatlist(r.onChatlistsLeaveChatlist) +func (r *Router) registerChatlists(d *tlprofile.Dispatcher) { + registerRPC[*tg.ChatlistsExportChatlistInviteRequest](d, tlprofile.SemanticMethodChatlistsExportChatlistInvite, func(ctx context.Context, layerRequest *tg.ChatlistsExportChatlistInviteRequest) (any, error) { + return r.onChatlistsExportChatlistInvite(ctx, layerRequest) + }) + registerRPC[*tg.ChatlistsDeleteExportedInviteRequest](d, tlprofile.SemanticMethodChatlistsDeleteExportedInvite, func(ctx context.Context, layerRequest *tg.ChatlistsDeleteExportedInviteRequest) (any, error) { + return r.onChatlistsDeleteExportedInvite(ctx, layerRequest) + }) + registerRPC[*tg.ChatlistsEditExportedInviteRequest](d, tlprofile.SemanticMethodChatlistsEditExportedInvite, func(ctx context.Context, layerRequest *tg.ChatlistsEditExportedInviteRequest) (any, error) { + return r.onChatlistsEditExportedInvite(ctx, layerRequest) + }) + registerRPC[*tg.ChatlistsGetExportedInvitesRequest](d, tlprofile.SemanticMethodChatlistsGetExportedInvites, func(ctx context.Context, layerRequest *tg.ChatlistsGetExportedInvitesRequest) (any, error) { + return r.onChatlistsGetExportedInvites(ctx, layerRequest. + Chatlist) + }) + registerRPC[*tg.ChatlistsCheckChatlistInviteRequest](d, tlprofile.SemanticMethodChatlistsCheckChatlistInvite, func(ctx context.Context, layerRequest *tg.ChatlistsCheckChatlistInviteRequest) (any, error) { + return r.onChatlistsCheckChatlistInvite(ctx, layerRequest. + Slug) + }) + registerRPC[*tg.ChatlistsJoinChatlistInviteRequest](d, tlprofile.SemanticMethodChatlistsJoinChatlistInvite, func(ctx context.Context, layerRequest *tg.ChatlistsJoinChatlistInviteRequest) (any, error) { + return r.onChatlistsJoinChatlistInvite(ctx, layerRequest) + }) + registerRPC[*tg.ChatlistsGetChatlistUpdatesRequest](d, tlprofile.SemanticMethodChatlistsGetChatlistUpdates, func(ctx context.Context, layerRequest *tg.ChatlistsGetChatlistUpdatesRequest) (any, error) { + return r.onChatlistsGetChatlistUpdates(ctx, layerRequest. + Chatlist) + }) + registerRPC[*tg.ChatlistsJoinChatlistUpdatesRequest](d, tlprofile.SemanticMethodChatlistsJoinChatlistUpdates, func(ctx context.Context, layerRequest *tg.ChatlistsJoinChatlistUpdatesRequest) (any, error) { + return r.onChatlistsJoinChatlistUpdates(ctx, layerRequest) + }) + registerRPC[*tg.ChatlistsHideChatlistUpdatesRequest](d, tlprofile.SemanticMethodChatlistsHideChatlistUpdates, func(ctx context.Context, layerRequest *tg.ChatlistsHideChatlistUpdatesRequest) (any, error) { + return r.onChatlistsHideChatlistUpdates(ctx, layerRequest. + Chatlist) + }) + registerRPC[*tg.ChatlistsGetLeaveChatlistSuggestionsRequest](d, tlprofile.SemanticMethodChatlistsGetLeaveChatlistSuggestions, func(ctx context.Context, layerRequest *tg.ChatlistsGetLeaveChatlistSuggestionsRequest) (any, error) { + return r.onChatlistsGetLeaveChatlistSuggestions(ctx, layerRequest. + Chatlist) + }) + registerRPC[*tg.ChatlistsLeaveChatlistRequest](d, tlprofile.SemanticMethodChatlistsLeaveChatlist, func(ctx context.Context, layerRequest *tg.ChatlistsLeaveChatlistRequest) (any, error) { + return r.onChatlistsLeaveChatlist(ctx, layerRequest) + }) } func (r *Router) onChatlistsExportChatlistInvite(ctx context.Context, req *tg.ChatlistsExportChatlistInviteRequest) (*tg.ChatlistsExportedChatlistInvite, error) { diff --git a/internal/rpc/contacts.go b/internal/rpc/contacts.go index 2ba5f792..e77940b5 100644 --- a/internal/rpc/contacts.go +++ b/internal/rpc/contacts.go @@ -10,6 +10,7 @@ import ( "github.com/iamxvbaba/td/tg" "go.uber.org/zap" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/app/contacts" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" @@ -28,38 +29,82 @@ const ( ) // registerContacts 注册 contacts.* RPC handler。 -func (r *Router) registerContacts(d *tg.ServerDispatcher) { - d.OnContactsGetContacts(r.onContactsGetContacts) - d.OnContactsGetContactIDs(r.onContactsGetContactIDs) - d.OnContactsGetStatuses(r.onContactsGetStatuses) - d.OnContactsImportContacts(r.onContactsImportContacts) - d.OnContactsAddContact(r.onContactsAddContact) - d.OnContactsAcceptContact(r.onContactsAcceptContact) - d.OnContactsDeleteContacts(r.onContactsDeleteContacts) - d.OnContactsEditCloseFriends(r.onContactsEditCloseFriends) - d.OnContactsBlock(r.onContactsBlock) - d.OnContactsUnblock(r.onContactsUnblock) - d.OnContactsSetBlocked(r.onContactsSetBlocked) - d.OnContactsUpdateContactNote(r.onContactsUpdateContactNote) - d.OnContactsSearch(r.onContactsSearch) - d.OnContactsResolveUsername(r.onContactsResolveUsername) - d.OnContactsResolvePhone(r.onContactsResolvePhone) - d.OnContactsGetTopPeers(func(ctx context.Context, req *tg.ContactsGetTopPeersRequest) (tg.ContactsTopPeersClass, error) { +func (r *Router) registerContacts(d *tlprofile.Dispatcher) { + registerRPC[*tg.ContactsGetContactsRequest](d, tlprofile.SemanticMethodContactsGetContacts, func(ctx context.Context, layerRequest *tg.ContactsGetContactsRequest) (any, error) { + return r.onContactsGetContacts(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.ContactsGetContactIDsRequest](d, tlprofile.SemanticMethodContactsGetContactIDs, func(ctx context.Context, layerRequest *tg.ContactsGetContactIDsRequest) (any, error) { + return r.onContactsGetContactIDs(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.ContactsGetStatusesRequest](d, tlprofile.SemanticMethodContactsGetStatuses, func(ctx context.Context, layerRequest *tg.ContactsGetStatusesRequest) (any, error) { + return r.onContactsGetStatuses(ctx) + }) + registerRPC[*tg.ContactsImportContactsRequest](d, tlprofile.SemanticMethodContactsImportContacts, func(ctx context.Context, layerRequest *tg.ContactsImportContactsRequest) (any, error) { + return r.onContactsImportContacts(ctx, layerRequest. + Contacts) + }) + registerRPC[*tg.ContactsAddContactRequest](d, tlprofile.SemanticMethodContactsAddContact, func(ctx context.Context, layerRequest *tg.ContactsAddContactRequest) (any, error) { + return r.onContactsAddContact(ctx, layerRequest) + }) + registerRPC[*tg.ContactsAcceptContactRequest](d, tlprofile.SemanticMethodContactsAcceptContact, func(ctx context.Context, layerRequest *tg.ContactsAcceptContactRequest) (any, error) { + return r.onContactsAcceptContact(ctx, layerRequest. + ID) + }) + registerRPC[*tg.ContactsDeleteContactsRequest](d, tlprofile.SemanticMethodContactsDeleteContacts, func(ctx context.Context, layerRequest *tg.ContactsDeleteContactsRequest) (any, error) { + return r.onContactsDeleteContacts(ctx, layerRequest. + ID) + }) + registerRPC[*tg.ContactsEditCloseFriendsRequest](d, tlprofile.SemanticMethodContactsEditCloseFriends, func(ctx context.Context, layerRequest *tg.ContactsEditCloseFriendsRequest) (any, error) { + return r.onContactsEditCloseFriends(ctx, layerRequest. + ID) + }) + registerRPC[*tg.ContactsBlockRequest](d, tlprofile.SemanticMethodContactsBlock, func(ctx context.Context, layerRequest *tg.ContactsBlockRequest) (any, error) { + return r.onContactsBlock(ctx, layerRequest) + }) + registerRPC[*tg.ContactsUnblockRequest](d, tlprofile.SemanticMethodContactsUnblock, func(ctx context.Context, layerRequest *tg.ContactsUnblockRequest) (any, error) { + return r.onContactsUnblock(ctx, layerRequest) + }) + registerRPC[*tg.ContactsSetBlockedRequest](d, tlprofile.SemanticMethodContactsSetBlocked, func(ctx context.Context, layerRequest *tg.ContactsSetBlockedRequest) (any, error) { + return r.onContactsSetBlocked(ctx, layerRequest) + }) + registerRPC[*tg.ContactsUpdateContactNoteRequest](d, tlprofile.SemanticMethodContactsUpdateContactNote, func(ctx context.Context, layerRequest *tg.ContactsUpdateContactNoteRequest) (any, error) { + return r.onContactsUpdateContactNote(ctx, layerRequest) + }) + registerRPC[*tg.ContactsSearchRequest](d, tlprofile.SemanticMethodContactsSearch, func(ctx context.Context, layerRequest *tg.ContactsSearchRequest) (any, error) { + return r.onContactsSearch(ctx, layerRequest) + }) + registerRPC[*tg.ContactsResolveUsernameRequest](d, tlprofile.SemanticMethodContactsResolveUsername, func(ctx context.Context, layerRequest *tg.ContactsResolveUsernameRequest) (any, error) { + return r.onContactsResolveUsername(ctx, layerRequest) + }) + registerRPC[*tg.ContactsResolvePhoneRequest](d, tlprofile.SemanticMethodContactsResolvePhone, func(ctx context.Context, layerRequest *tg.ContactsResolvePhoneRequest) (any, error) { + return r.onContactsResolvePhone(ctx, layerRequest. + Phone) + }) + registerRPC[*tg.ContactsGetTopPeersRequest](d, tlprofile.SemanticMethodContactsGetTopPeers, func(ctx context.Context, req *tg.ContactsGetTopPeersRequest) (any, error) { return tdesktop.TopPeers(), nil }) - d.OnContactsGetBlocked(r.onContactsGetBlocked) - d.OnContactsGetBirthdays(func(ctx context.Context) (*tg.ContactsContactBirthdays, error) { + registerRPC[*tg.ContactsGetBlockedRequest](d, tlprofile.SemanticMethodContactsGetBlocked, func(ctx context.Context, layerRequest *tg.ContactsGetBlockedRequest) (any, error) { + return r.onContactsGetBlocked(ctx, layerRequest) + }) + registerRPC[*tg.ContactsGetBirthdaysRequest](d, tlprofile.SemanticMethodContactsGetBirthdays, func(ctx context.Context, layerRequest *tg.ContactsGetBirthdaysRequest) (any, error) { if _, _, err := r.currentUserID(ctx); err != nil { return nil, internalErr() } return &tg.ContactsContactBirthdays{Contacts: []tg.ContactBirthday{}, Users: []tg.UserClass{}}, nil }) - d.OnContactsGetSponsoredPeers(func(ctx context.Context, q string) (tg.ContactsSponsoredPeersClass, error) { + registerRPC[*tg.ContactsGetSponsoredPeersRequest](d, tlprofile.SemanticMethodContactsGetSponsoredPeers, func(ctx context.Context, layerRequest *tg.ContactsGetSponsoredPeersRequest) (any, error) { + q := layerRequest. + Q + _ = q + if utf8.RuneCountInString(q) > maxContactSearchQLen { return nil, limitInvalidErr() } return &tg.ContactsSponsoredPeersEmpty{}, nil }) + } func (r *Router) onContactsEditCloseFriends(ctx context.Context, id []int64) (bool, error) { diff --git a/internal/rpc/contacts_users_rpc_test.go b/internal/rpc/contacts_users_rpc_test.go index f7630e3c..16095d7b 100644 --- a/internal/rpc/contacts_users_rpc_test.go +++ b/internal/rpc/contacts_users_rpc_test.go @@ -83,12 +83,8 @@ func TestContactsEditCloseFriendsProjectsUserFlag(t *testing.T) { if err != nil { t.Fatalf("dispatch edit close friends: %v", err) } - box, ok := enc.(*tg.BoolBox) - if !ok { - t.Fatalf("edit close friends result = %T, want BoolBox", enc) - } - if _, ok := box.Bool.(*tg.BoolTrue); !ok { - t.Fatalf("edit close friends bool = %T, want BoolTrue", box.Bool) + if value, ok := dispatchCanonicalValue(enc).(bool); !ok || !value { + t.Fatalf("edit close friends result = %#v (%T), want true", dispatchCanonicalValue(enc), enc) } var get bin.Buffer @@ -99,12 +95,11 @@ func TestContactsEditCloseFriendsProjectsUserFlag(t *testing.T) { if err != nil { t.Fatalf("dispatch get contacts: %v", err) } - contactsBox, ok := got.(*tg.ContactsContactsBox) + list, ok := got.(*tg.ContactsContacts) if !ok { - t.Fatalf("contacts result = %T %+v, want ContactsContactsBox", got, got) + t.Fatalf("contacts result = %T %+v, want *tg.ContactsContacts", got, got) } - list, ok := contactsBox.Contacts.(*tg.ContactsContacts) - if !ok || len(list.Users) != 1 { + if len(list.Users) != 1 { t.Fatalf("contacts result = %T %+v, want one contact user", got, got) } user, ok := list.Users[0].(*tg.User) diff --git a/internal/rpc/dialogs_rpc_test.go b/internal/rpc/dialogs_rpc_test.go index 4d01c997..aa7b56ff 100644 --- a/internal/rpc/dialogs_rpc_test.go +++ b/internal/rpc/dialogs_rpc_test.go @@ -65,13 +65,9 @@ func TestMessagesGetDialogsReturnsNotModifiedFromFullListHash(t *testing.T) { if err != nil { t.Fatalf("dispatch: %v", err) } - box, ok := enc.(*tg.MessagesDialogsBox) + got, ok := enc.(*tg.MessagesDialogsNotModified) if !ok { - t.Fatalf("response = %T, want *tg.MessagesDialogsBox", enc) - } - got, ok := box.Dialogs.(*tg.MessagesDialogsNotModified) - if !ok { - t.Fatalf("boxed response = %T, want *tg.MessagesDialogsNotModified", box.Dialogs) + t.Fatalf("response = %T, want *tg.MessagesDialogsNotModified", enc) } if got.Count != 3 || dialogs.filter.Hash != 77 { t.Fatalf("not modified = %+v filter %+v, want count/hash from service", got, dialogs.filter) @@ -100,13 +96,9 @@ func TestMessagesGetDialogsHashHitSkipsFullListLoad(t *testing.T) { if err != nil { t.Fatalf("dispatch: %v", err) } - box, ok := enc.(*tg.MessagesDialogsBox) + got, ok := enc.(*tg.MessagesDialogsNotModified) if !ok { - t.Fatalf("response = %T, want *tg.MessagesDialogsBox", enc) - } - got, ok := box.Dialogs.(*tg.MessagesDialogsNotModified) - if !ok { - t.Fatalf("boxed response = %T, want *tg.MessagesDialogsNotModified", box.Dialogs) + t.Fatalf("response = %T, want *tg.MessagesDialogsNotModified", enc) } if got.Count != 5 { t.Fatalf("not modified count = %d, want 5", got.Count) @@ -733,13 +725,12 @@ func TestMessagesGetDialogsIncludesCloudDraft(t *testing.T) { if err != nil { t.Fatalf("get dialogs: %v", err) } - box, ok := got.(*tg.MessagesDialogsBox) + dialogs, ok := got.(*tg.MessagesDialogs) if !ok { - t.Fatalf("response = %T, want boxed messages.dialogs", got) + t.Fatalf("response = %T, want *tg.MessagesDialogs", got) } - dialogs, ok := box.Dialogs.(*tg.MessagesDialogs) - if !ok || len(dialogs.Dialogs) != 1 { - t.Fatalf("dialogs = %T %+v, want one messages.dialogs", box.Dialogs, box.Dialogs) + if len(dialogs.Dialogs) != 1 { + t.Fatalf("dialogs = %+v, want one messages.dialogs", dialogs) } dialog, ok := dialogs.Dialogs[0].(*tg.Dialog) if !ok { @@ -1092,13 +1083,9 @@ func TestMessagesGetDialogsTDesktopInitialPageMergesPinnedHeader(t *testing.T) { if err != nil { t.Fatalf("dispatch get dialogs: %v", err) } - box, ok := enc.(*tg.MessagesDialogsBox) + out, ok := enc.(*tg.MessagesDialogs) if !ok { - t.Fatalf("response = %T, want *tg.MessagesDialogsBox", enc) - } - out, ok := box.Dialogs.(*tg.MessagesDialogs) - if !ok { - t.Fatalf("dialogs response = %T, want *tg.MessagesDialogs", box.Dialogs) + t.Fatalf("response = %T, want *tg.MessagesDialogs", enc) } if dialogs.getDialogsCalls != 2 || len(dialogs.filters) != 2 { t.Fatalf("GetDialogs calls = %d filters %+v, want normal + pinned", dialogs.getDialogsCalls, dialogs.filters) @@ -1186,8 +1173,7 @@ func TestMessagesGetDialogsNonTDesktopKeepsExcludePinnedResponse(t *testing.T) { if err != nil { t.Fatalf("dispatch get dialogs: %v", err) } - box := enc.(*tg.MessagesDialogsBox) - out := box.Dialogs.(*tg.MessagesDialogs) + out := enc.(*tg.MessagesDialogs) if dialogs.getDialogsCalls != 1 { t.Fatalf("GetDialogs calls = %d, want no pinned compatibility load", dialogs.getDialogsCalls) } diff --git a/internal/rpc/doc.go b/internal/rpc/doc.go index d608ee68..4e3d0e04 100644 --- a/internal/rpc/doc.go +++ b/internal/rpc/doc.go @@ -1,4 +1,4 @@ -// Package rpc 是按 TypeID 路由的 RPC 层:封装 tg.ServerDispatcher(或等价薄封装), +// Package rpc 是按 semantic method 路由的 RPC 层:封装 tlprofile.Dispatcher, // 在 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)。 diff --git a/internal/rpc/durable_layer_evidence.go b/internal/rpc/durable_layer_evidence.go index c6364c20..db390e17 100644 --- a/internal/rpc/durable_layer_evidence.go +++ b/internal/rpc/durable_layer_evidence.go @@ -5,8 +5,7 @@ import ( "errors" "fmt" - "github.com/iamxvbaba/td/tg" - + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/store" ) @@ -142,7 +141,7 @@ func (r *Router) cacheResolvedDurableSessionLayer( return nil } key := clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID} - profile, supported := tg.ResolveLayerProfile(value.Layer) + profile, supported := tlprofile.ResolveProfile(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 diff --git a/internal/rpc/encrypted_register.go b/internal/rpc/encrypted_register.go index 3b33cdc5..e81248c9 100644 --- a/internal/rpc/encrypted_register.go +++ b/internal/rpc/encrypted_register.go @@ -1,30 +1,64 @@ package rpc -import "github.com/iamxvbaba/td/tg" +import ( + "context" -// registerEncrypted 注册私聊端对端加密(Secret Chat)域 RPC。 -// -// 归属约定:messages.getDhConfig 属通话域(DH 参数下发),由 registerPhone 注册、 -// 密聊复用,**本处绝不重复注册 OnMessagesGetDhConfig**(gotd ServerDispatcher 同一 -// RPC 重复 On* 是静默 last-wins,会覆盖 phone 域真实现)。 -// -// P0 落地握手三件套;sendEncrypted / sendEncryptedFile / sendEncryptedService / -// readEncryptedHistory / setEncryptedTyping / receivedQueue / reportEncryptedSpam / -// uploadEncryptedFile 暂未注册,落 fallback → NOT_IMPLEMENTED + compatibility trace, -// 属 P1/P2(qts 引擎 + 消息投递)。设计 docs/secret-chat-module.md。 -func (r *Router) registerEncrypted(d *tg.ServerDispatcher) { + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" + // registerEncrypted 注册私聊端对端加密(Secret Chat)域 RPC。 + // + // 归属约定:messages.getDhConfig 属通话域(DH 参数下发),由 registerPhone 注册、 + // 密聊复用,**本处绝不重复注册 messages.getDhConfig**(tlprofile.Dispatcher 同一 + // RPC 重复 On* 是静默 last-wins,会覆盖 phone 域真实现)。 + // + // P0 落地握手三件套;sendEncrypted / sendEncryptedFile / sendEncryptedService / + // readEncryptedHistory / setEncryptedTyping / receivedQueue / reportEncryptedSpam / + // uploadEncryptedFile 暂未注册,落 fallback → NOT_IMPLEMENTED + compatibility trace, + // 属 P1/P2(qts 引擎 + 消息投递)。设计 docs/secret-chat-module.md。 +) + +func (r *Router) registerEncrypted(d *tlprofile.Dispatcher) { + registerRPC[ // P0:握手三件套。 - d.OnMessagesRequestEncryption(r.onMessagesRequestEncryption) - d.OnMessagesAcceptEncryption(r.onMessagesAcceptEncryption) - d.OnMessagesDiscardEncryption(r.onMessagesDiscardEncryption) - // P1:qts 消息收发 + 已读/typing + 队列确认。 - d.OnMessagesSendEncrypted(r.onMessagesSendEncrypted) - d.OnMessagesSendEncryptedService(r.onMessagesSendEncryptedService) - d.OnMessagesReadEncryptedHistory(r.onMessagesReadEncryptedHistory) - d.OnMessagesSetEncryptedTyping(r.onMessagesSetEncryptedTyping) - d.OnMessagesReceivedQueue(r.onMessagesReceivedQueue) - d.OnMessagesReportEncryptedSpam(r.onMessagesReportEncryptedSpam) - // P2:密聊文件。 - d.OnMessagesSendEncryptedFile(r.onMessagesSendEncryptedFile) - d.OnMessagesUploadEncryptedFile(r.onMessagesUploadEncryptedFile) + *tg.MessagesRequestEncryptionRequest](d, tlprofile.SemanticMethodMessagesRequestEncryption, func(ctx context.Context, layerRequest *tg.MessagesRequestEncryptionRequest) (any, error) { + return r.onMessagesRequestEncryption(ctx, layerRequest) + }) + registerRPC[*tg.MessagesAcceptEncryptionRequest](d, tlprofile.SemanticMethodMessagesAcceptEncryption, func(ctx context.Context, layerRequest *tg.MessagesAcceptEncryptionRequest) ( + + // P1:qts 消息收发 + 已读/typing + 队列确认。 + any, error) { + return r.onMessagesAcceptEncryption(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDiscardEncryptionRequest](d, tlprofile.SemanticMethodMessagesDiscardEncryption, func(ctx context.Context, layerRequest *tg.MessagesDiscardEncryptionRequest) (any, error) { + return r.onMessagesDiscardEncryption(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendEncryptedRequest](d, tlprofile.SemanticMethodMessagesSendEncrypted, func(ctx context.Context, layerRequest *tg.MessagesSendEncryptedRequest) (any, error) { + return r.onMessagesSendEncrypted(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendEncryptedServiceRequest](d, tlprofile.SemanticMethodMessagesSendEncryptedService, func(ctx context.Context, layerRequest *tg.MessagesSendEncryptedServiceRequest) (any, error) { + return r.onMessagesSendEncryptedService(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReadEncryptedHistoryRequest](d, tlprofile.SemanticMethodMessagesReadEncryptedHistory, func(ctx context.Context, layerRequest *tg.MessagesReadEncryptedHistoryRequest) (any, error) { + return r.onMessagesReadEncryptedHistory(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetEncryptedTypingRequest](d, tlprofile.SemanticMethodMessagesSetEncryptedTyping, func(ctx context.Context, layerRequest *tg.MessagesSetEncryptedTypingRequest) (any, error) { + return r.onMessagesSetEncryptedTyping(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReceivedQueueRequest](d, tlprofile.SemanticMethodMessagesReceivedQueue, func(ctx context.Context, layerRequest *tg.MessagesReceivedQueueRequest) (any, + + // P2:密聊文件。 + error) { + return r.onMessagesReceivedQueue(ctx, layerRequest. + MaxQts) + }) + registerRPC[*tg.MessagesReportEncryptedSpamRequest](d, tlprofile.SemanticMethodMessagesReportEncryptedSpam, func(ctx context.Context, layerRequest *tg.MessagesReportEncryptedSpamRequest) (any, error) { + return r.onMessagesReportEncryptedSpam(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.MessagesSendEncryptedFileRequest](d, tlprofile.SemanticMethodMessagesSendEncryptedFile, func(ctx context.Context, layerRequest *tg.MessagesSendEncryptedFileRequest) (any, error) { + return r.onMessagesSendEncryptedFile(ctx, layerRequest) + }) + registerRPC[*tg.MessagesUploadEncryptedFileRequest](d, tlprofile.SemanticMethodMessagesUploadEncryptedFile, func(ctx context.Context, layerRequest *tg.MessagesUploadEncryptedFileRequest) (any, error) { + return r.onMessagesUploadEncryptedFile(ctx, layerRequest) + }) } diff --git a/internal/rpc/folders.go b/internal/rpc/folders.go index c2b8babc..75733cb4 100644 --- a/internal/rpc/folders.go +++ b/internal/rpc/folders.go @@ -5,11 +5,16 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) -func (r *Router) registerFolders(d *tg.ServerDispatcher) { - d.OnFoldersEditPeerFolders(r.onFoldersEditPeerFolders) +func (r *Router) registerFolders(d *tlprofile.Dispatcher) { + registerRPC[*tg.FoldersEditPeerFoldersRequest](d, tlprofile.SemanticMethodFoldersEditPeerFolders, func(ctx context.Context, layerRequest *tg.FoldersEditPeerFoldersRequest) (any, error) { + return r.onFoldersEditPeerFolders(ctx, layerRequest. + FolderPeers) + }) + } func (r *Router) onFoldersEditPeerFolders(ctx context.Context, folderPeers []tg.InputFolderPeer) (tg.UpdatesClass, error) { diff --git a/internal/rpc/frozen_gate_test.go b/internal/rpc/frozen_gate_test.go index cbded5ab..9bf76279 100644 --- a/internal/rpc/frozen_gate_test.go +++ b/internal/rpc/frozen_gate_test.go @@ -13,6 +13,7 @@ import ( "github.com/iamxvbaba/td/tgerr" "go.uber.org/zap/zaptest" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) @@ -130,11 +131,11 @@ func TestFrozenMethodGateIsUserScopedAcrossSessionsAndUnfreezesImmediately(t *te func TestFrozenMethodGateReturns420BeforeLayerHandler(t *testing.T) { const userID = int64(1001) - for _, profile := range []tg.LayerProfile{ - tg.LayerProfile225, - tg.LayerProfile226, - tg.LayerProfile227, - tg.LayerProfile228, + for _, profile := range []tlprofile.Profile{ + tlprofile.Profile225, + tlprofile.Profile226, + tlprofile.Profile227, + tlprofile.Profile228, } { t.Run(fmt.Sprintf("layer_%d", profile), func(t *testing.T) { provider := &frozenGateFreezeProvider{freeze: frozenGateActiveState(userID), found: true} @@ -149,7 +150,7 @@ func TestFrozenMethodGateReturns420BeforeLayerHandler(t *testing.T) { Message: "must not reach handler", RandomID: 1, }) - admitted, err := router.AdmitLayer(profile, &body, tg.LayerDecodeLimits{}) + admitted, err := router.AdmitLayer(profile, &body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } diff --git a/internal/rpc/help.go b/internal/rpc/help.go index 10426392..eced459d 100644 --- a/internal/rpc/help.go +++ b/internal/rpc/help.go @@ -6,27 +6,38 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" androidcompat "telesrv/internal/compat/android" ioscompat "telesrv/internal/compat/ios" "telesrv/internal/compat/tdesktop" ) // registerHelp 注册 help.* RPC handler(DC 配置、最近 DC)。 -func (r *Router) registerHelp(d *tg.ServerDispatcher) { - d.OnHelpGetConfig(r.onHelpGetConfig) - d.OnHelpGetNearestDC(func(ctx context.Context) (*tg.NearestDC, error) { +func (r *Router) registerHelp(d *tlprofile.Dispatcher) { + registerRPC[*tg.HelpGetConfigRequest](d, tlprofile.SemanticMethodHelpGetConfig, func(ctx context.Context, layerRequest *tg.HelpGetConfigRequest) (any, error) { + return r.onHelpGetConfig(ctx) + }) + registerRPC[*tg.HelpGetNearestDCRequest](d, tlprofile.SemanticMethodHelpGetNearestDC, func(ctx context.Context, layerRequest *tg.HelpGetNearestDCRequest) (any, error) { return tdesktop.NearestDC(r.cfg.DC), nil }) - d.OnHelpGetInviteText(func(ctx context.Context) (*tg.HelpInviteText, error) { + registerRPC[*tg.HelpGetInviteTextRequest](d, tlprofile.SemanticMethodHelpGetInviteText, func(ctx context.Context, layerRequest *tg.HelpGetInviteTextRequest) (any, error) { return &tg.HelpInviteText{Message: "Join me on Telegram."}, nil }) - d.OnHelpGetAppUpdate(func(ctx context.Context, source string) (tg.HelpAppUpdateClass, error) { + registerRPC[*tg.HelpGetAppUpdateRequest](d, tlprofile.SemanticMethodHelpGetAppUpdate, func(ctx context.Context, layerRequest *tg.HelpGetAppUpdateRequest) (any, error) { + source := layerRequest. + Source + _ = source + if _, _, err := r.currentUserID(ctx); err != nil { return nil, internalErr() } return ioscompat.NoAppUpdate(), nil }) - d.OnHelpGetAppConfig(func(ctx context.Context, hash int) (tg.HelpAppConfigClass, error) { + registerRPC[*tg.HelpGetAppConfigRequest](d, tlprofile.SemanticMethodHelpGetAppConfig, func(ctx context.Context, layerRequest *tg.HelpGetAppConfigRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + if r.deps.Help == nil { return tdesktop.AppConfig(hash), nil } @@ -40,7 +51,7 @@ func (r *Router) registerHelp(d *tg.ServerDispatcher) { } return &tg.HelpAppConfig{Hash: cfg.Hash, Config: tgJSONValue(cfg.JSON)}, nil }) - d.OnHelpGetCountriesList(func(ctx context.Context, req *tg.HelpGetCountriesListRequest) (tg.HelpCountriesListClass, error) { + registerRPC[*tg.HelpGetCountriesListRequest](d, tlprofile.SemanticMethodHelpGetCountriesList, func(ctx context.Context, req *tg.HelpGetCountriesListRequest) (any, error) { if r.deps.Help == nil { return tdesktop.CountriesList(req.Hash), nil } @@ -53,31 +64,53 @@ func (r *Router) registerHelp(d *tg.ServerDispatcher) { } return tgCountriesList(list), nil }) - d.OnHelpGetTimezonesList(func(ctx context.Context, hash int) (tg.HelpTimezonesListClass, error) { + registerRPC[*tg.HelpGetTimezonesListRequest](d, tlprofile.SemanticMethodHelpGetTimezonesList, func(ctx context.Context, layerRequest *tg.HelpGetTimezonesListRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return tdesktop.TimezonesList(hash), nil }) - d.OnHelpGetPeerColors(func(ctx context.Context, hash int) (tg.HelpPeerColorsClass, error) { + registerRPC[*tg.HelpGetPeerColorsRequest](d, tlprofile.SemanticMethodHelpGetPeerColors, func(ctx context.Context, layerRequest *tg.HelpGetPeerColorsRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return tdesktop.PeerColors(hash), nil }) - d.OnHelpGetPeerProfileColors(func(ctx context.Context, hash int) (tg.HelpPeerColorsClass, error) { + registerRPC[*tg.HelpGetPeerProfileColorsRequest](d, tlprofile.SemanticMethodHelpGetPeerProfileColors, func(ctx context.Context, layerRequest *tg.HelpGetPeerProfileColorsRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return tdesktop.PeerProfileColors(hash), nil }) - d.OnHelpGetPromoData(func(ctx context.Context) (tg.HelpPromoDataClass, error) { + registerRPC[*tg.HelpGetPromoDataRequest](d, tlprofile.SemanticMethodHelpGetPromoData, func(ctx context.Context, layerRequest *tg.HelpGetPromoDataRequest) (any, error) { return tdesktop.PromoData(r.clock.Now()), nil }) - d.OnHelpGetTermsOfServiceUpdate(func(ctx context.Context) (tg.HelpTermsOfServiceUpdateClass, error) { + registerRPC[*tg.HelpGetTermsOfServiceUpdateRequest](d, tlprofile.SemanticMethodHelpGetTermsOfServiceUpdate, func(ctx context.Context, layerRequest *tg.HelpGetTermsOfServiceUpdateRequest) (any, error) { return tdesktop.TermsOfServiceUpdate(r.clock.Now()), nil }) + registerRPC[ + // 客户端遇到无法识别的 tg:// 深链时会查询 help.getDeepLinkInfo。telesrv 不维护 // “需更新 App”的特殊深链提示库,对所有 path 返回 deepLinkInfoEmpty——这是规范的 // “无特殊信息”应答:DrKLO 仅在收到非空 deepLinkInfo 时才弹“请更新 App”弹窗 // (LaunchActivity.java:5175),收到 Empty 则静默放行按普通链接处理。此前未注册 // handler 会落 fallback 返回 500 NOT_IMPLEMENTED(污染日志且非正确协议行为)。 - d.OnHelpGetDeepLinkInfo(func(ctx context.Context, path string) (tg.HelpDeepLinkInfoClass, error) { + *tg.HelpGetDeepLinkInfoRequest](d, tlprofile.SemanticMethodHelpGetDeepLinkInfo, func(ctx context.Context, layerRequest *tg.HelpGetDeepLinkInfoRequest) (any, error) { + path := layerRequest. + Path + _ = path + return &tg.HelpDeepLinkInfoEmpty{}, nil }) - d.OnHelpDismissSuggestion(r.onHelpDismissSuggestion) - d.OnHelpGetPremiumPromo(r.onHelpGetPremiumPromo) + registerRPC[*tg.HelpDismissSuggestionRequest](d, tlprofile.SemanticMethodHelpDismissSuggestion, func(ctx context.Context, layerRequest *tg.HelpDismissSuggestionRequest) (any, error) { + return r.onHelpDismissSuggestion(ctx, layerRequest) + }) + registerRPC[*tg.HelpGetPremiumPromoRequest](d, tlprofile.SemanticMethodHelpGetPremiumPromo, func(ctx context.Context, layerRequest *tg.HelpGetPremiumPromoRequest) (any, error) { + return r.onHelpGetPremiumPromo(ctx) + }) } func (r *Router) onHelpGetConfig(ctx context.Context) (*tg.Config, error) { diff --git a/internal/rpc/help_dismiss_suggestion_test.go b/internal/rpc/help_dismiss_suggestion_test.go index 5619a410..2738d82e 100644 --- a/internal/rpc/help_dismiss_suggestion_test.go +++ b/internal/rpc/help_dismiss_suggestion_test.go @@ -26,12 +26,8 @@ func TestHelpDismissSuggestionAndroidChangePhone(t *testing.T) { if err != nil { t.Fatalf("dispatch: %v", err) } - box, ok := enc.(*tg.BoolBox) - if !ok { - t.Fatalf("response = %T, want *tg.BoolBox", enc) - } - if _, ok := box.Bool.(*tg.BoolTrue); !ok { - t.Fatalf("bool response = %T, want BoolTrue", box.Bool) + if value, ok := dispatchCanonicalValue(enc).(bool); !ok || !value { + t.Fatalf("response = %#v (%T), want true", dispatchCanonicalValue(enc), enc) } } diff --git a/internal/rpc/langpack.go b/internal/rpc/langpack.go index fc3dfe8a..1900d241 100644 --- a/internal/rpc/langpack.go +++ b/internal/rpc/langpack.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) // registerLangpack 注册 langpack.* RPC handler。 @@ -12,19 +13,24 @@ import ( // 老客户端(DrKLO)发的是不带 lang_pack 参数的旧构造器,已由 gotdgen client overlay 入站升级为 canonical // 形态并把 lang_pack 置空;故这里 lang_pack 为空时回退到按 client 信息派生(langPackFromClient), // 与历史 handleLegacyLangpack* 的行为一致。 -func (r *Router) registerLangpack(d *tg.ServerDispatcher) { - d.OnLangpackGetLanguages(func(ctx context.Context, langPack string) ([]tg.LangPackLanguage, error) { +func (r *Router) registerLangpack(d *tlprofile.Dispatcher) { + registerRPC[*tg.LangpackGetLanguagesRequest](d, tlprofile.SemanticMethodLangpackGetLanguages, func(ctx context.Context, layerRequest *tg.LangpackGetLanguagesRequest) (any, error) { + langPack := layerRequest. + LangPack + _ = langPack + return r.langpackLanguages(ctx, langPack), nil }) - d.OnLangpackGetLanguage(func(ctx context.Context, req *tg.LangpackGetLanguageRequest) (*tg.LangPackLanguage, error) { + registerRPC[*tg.LangpackGetLanguageRequest](d, tlprofile.SemanticMethodLangpackGetLanguage, func(ctx context.Context, req *tg.LangpackGetLanguageRequest) (any, error) { if req == nil { return nil, inputConstructorInvalidErr() } lang := r.langpackLanguage(ctx, req.LangPack, req.LangCode) return &lang, nil }) - d.OnLangpackGetLangPack(func(ctx context.Context, req *tg.LangpackGetLangPackRequest) (*tg.LangPackDifference, error) { + registerRPC[*tg.LangpackGetLangPackRequest](d, tlprofile.SemanticMethodLangpackGetLangPack, func(ctx context.Context, req *tg.LangpackGetLangPackRequest) (any, error) { langPack := langPackOrClient(ctx, req.LangPack) + _ = langPack if r.deps.LangPack == nil { return &tg.LangPackDifference{LangCode: req.LangCode}, nil } @@ -34,7 +40,7 @@ func (r *Router) registerLangpack(d *tg.ServerDispatcher) { } return tgLangPackDifference(pack), nil }) - d.OnLangpackGetDifference(func(ctx context.Context, req *tg.LangpackGetDifferenceRequest) (*tg.LangPackDifference, error) { + registerRPC[*tg.LangpackGetDifferenceRequest](d, tlprofile.SemanticMethodLangpackGetDifference, func(ctx context.Context, req *tg.LangpackGetDifferenceRequest) (any, error) { if r.deps.LangPack == nil { return &tg.LangPackDifference{LangCode: req.LangCode, FromVersion: req.FromVersion}, nil } @@ -44,9 +50,9 @@ func (r *Router) registerLangpack(d *tg.ServerDispatcher) { } return tgLangPackDifference(pack), nil }) - d.OnLangpackGetStrings(func(ctx context.Context, req *tg.LangpackGetStringsRequest) ([]tg.LangPackStringClass, error) { + registerRPC[*tg.LangpackGetStringsRequest](d, tlprofile.SemanticMethodLangpackGetStrings, func(ctx context.Context, req *tg.LangpackGetStringsRequest) (any, error) { if r.deps.LangPack == nil { - return nil, nil + return []tg.LangPackStringClass{}, nil } pack, err := r.deps.LangPack.GetStrings(ctx, langPackOrClient(ctx, req.LangPack), req.LangCode, req.Keys) if err != nil { @@ -54,6 +60,7 @@ func (r *Router) registerLangpack(d *tg.ServerDispatcher) { } return tgLangPackStrings(pack.Strings), nil }) + } // langPackOrClient 返回请求里的 lang_pack;为空(老客户端经生成 overlay 升级而来)时按 client 派生。 diff --git a/internal/rpc/layer_dispatch.go b/internal/rpc/layer_dispatch.go index 45636b86..69aca08a 100644 --- a/internal/rpc/layer_dispatch.go +++ b/internal/rpc/layer_dispatch.go @@ -7,9 +7,9 @@ import ( "time" "github.com/iamxvbaba/td/bin" - "github.com/iamxvbaba/td/tg" "go.uber.org/zap" + "github.com/iamxvbaba/td/tlprofile" compatandroid "telesrv/internal/compat/android" "telesrv/internal/observability/dbtrace" ) @@ -56,28 +56,28 @@ 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) { +func (r *Router) AdmitLayer(profile tlprofile.Profile, b *bin.Buffer, limits tlprofile.Limits) (tlprofile.Admission, error) { if r == nil || r.dispatcher == nil { - return tg.LayerRequest{}, internalErr() + return tlprofile.Admission{}, internalErr() } if b == nil { - return tg.LayerRequest{}, inputRequestInvalidErr() + return tlprofile.Admission{}, inputRequestInvalidErr() } - return r.dispatcher.AdmitLayerWithLimits(profile, b, limits) + return r.dispatcher.Admit(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) { +func (r *Router) AdmitDefaultLayer(profile tlprofile.Profile, b *bin.Buffer, limits tlprofile.Limits) (tlprofile.Admission, error) { if r == nil || r.dispatcher == nil { - return tg.LayerRequest{}, internalErr() + return tlprofile.Admission{}, internalErr() } if b == nil { - return tg.LayerRequest{}, inputRequestInvalidErr() + return tlprofile.Admission{}, inputRequestInvalidErr() } - return r.dispatcher.AdmitDefaultLayerWithLimits(profile, b, limits) + return r.dispatcher.AdmitDefault(profile, b, limits) } // registerAndroidLayerRPCAdapter installs the only client-private schema seam. @@ -85,20 +85,20 @@ func (r *Router) AdmitDefaultLayer(profile tg.LayerProfile, b *bin.Buffer, limit // 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) { +func (r *Router) registerAndroidLayerRPCAdapter(d *tlprofile.Dispatcher) { if d == nil { panic("rpc: register Android layer RPC adapter on nil dispatcher") } - d.OnLayerRPCUnknownMethod(func(view tg.LayerRPCUnknownMethodView) (tg.LayerOutboundCall, bool, error) { + d.OnUnknownMethod(func(view tlprofile.UnknownMethodView) (tlprofile.OutboundCall, bool, error) { outbound, handled, err := compatandroid.AdaptPrivateLayerRPC(view) if !handled { - return tg.LayerOutboundCall{}, false, nil + return tlprofile.OutboundCall{}, false, nil } if err != nil { - return tg.LayerOutboundCall{}, true, err + return tlprofile.OutboundCall{}, true, err } if r.log != nil { - _, method, _ := tg.LayerSemanticName(outbound.Method()) + _, method, _ := tlprofile.SemanticName(outbound.Method()) r.log.Info("Android private RPC admitted through generated exact adapter", zap.Int("profile", int(view.Profile())), zap.String("method", method), @@ -119,12 +119,12 @@ func (r *Router) PrepareAdmittedReplay( sessionID int64, msgID int64, admissionSeq uint64, - request tg.LayerRequest, + request tlprofile.Admission, ) (func() error, error) { if r == nil || r.dispatcher == nil || request.Prepared().WireSize() <= 0 { return nil, inputRequestInvalidErr() } - _, method, ok := tg.LayerSemanticName(request.Call().Method()) + _, method, ok := tlprofile.SemanticName(request.Call().Method()) if !ok || method == "" { return nil, inputRequestInvalidErr() } @@ -190,11 +190,11 @@ func (r *Router) PrepareAdmittedReplay( // 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) { +func (r *Router) AdmitUnprofiled(b *bin.Buffer, limits tlprofile.Limits) (tlprofile.Admission, error) { if r == nil || r.dispatcher == nil { - return tg.LayerRequest{}, internalErr() + return tlprofile.Admission{}, internalErr() } - return r.dispatcher.AdmitUnprofiledWithLimits(b, limits) + return r.dispatcher.AdmitUnprofiled(b, limits) } // DispatchAdmitted executes one generated admission lease. invokeAfterMsg(s) @@ -206,14 +206,14 @@ func (r *Router) DispatchAdmitted( sessionID int64, msgID int64, admissionSeq uint64, - request tg.LayerRequest, -) (tg.LayerRPCResult, string, error) { + request tlprofile.Admission, +) (tlprofile.Result, string, error) { if r == nil || r.dispatcher == nil { return nil, "", internalErr() } prepared := request.Prepared() call := request.Call() - category, method, ok := tg.LayerSemanticName(call.Method()) + category, method, ok := tlprofile.SemanticName(call.Method()) if !ok || category != "function" || method == "" || prepared.WireSize() <= 0 { return nil, "", inputRequestInvalidErr() } @@ -228,7 +228,7 @@ func (r *Router) DispatchAdmitted( if err != nil { return nil, method, err } - if !r.dispatcher.HasLayerRPCHandler(call.Method()) { + if !r.dispatcher.Has(call.Method()) { fields := append([]zap.Field{ zap.String("method", method), zap.String("type_id", fmt.Sprintf("%#x", call.WireID())), @@ -239,7 +239,7 @@ func (r *Router) DispatchAdmitted( } return nil, method, notImplementedErr() } - canonicalID, hasCanonicalID := tg.LayerWireID(tg.LayerProfileCanonical, call.Method()) + canonicalID, hasCanonicalID := tlprofile.WireID(tlprofile.ProfileCanonical, call.Method()) if !hasCanonicalID { return nil, method, inputRequestInvalidErr() } @@ -262,7 +262,7 @@ func (r *Router) DispatchAdmitted( } dbBefore := dbtrace.SnapshotFromContext(ctx) start := time.Now() - result, err := r.dispatcher.DispatchAdmitted(ctx, request) + result, err := r.dispatcher.Dispatch(ctx, request) dur := time.Since(start) dbDelta := dbtrace.SnapshotFromContext(ctx).Sub(dbBefore) fields := append([]zap.Field{ @@ -294,12 +294,12 @@ func (r *Router) DispatchAdmitted( } type layerRPCWrapperEffect struct { - semantic tg.LayerSemanticID + semantic tlprofile.SemanticID layer int info ClientInfo } -func (r *Router) snapshotLayerRPCWrapperEffects(ctx context.Context, request tg.LayerRequest) ([]layerRPCWrapperEffect, error) { +func (r *Router) snapshotLayerRPCWrapperEffects(ctx context.Context, request tlprofile.Admission) ([]layerRPCWrapperEffect, error) { if err := r.validateLayerRPCWrappers(ctx, request); err != nil { return nil, err } @@ -323,19 +323,19 @@ func (r *Router) snapshotLayerRPCWrapperEffects(ctx context.Context, request tg. wrapper, _ := request.Wrapper(index) effect := layerRPCWrapperEffect{semantic: wrapper.Semantic()} switch wrapper.Semantic() { - case tg.LayerSemanticMethodInvokeWithLayer: + case tlprofile.SemanticMethodInvokeWithLayer: layer, err := layerWrapperRequired[int](wrapper, "layer") if err != nil || layer != int(profile) { return nil, inputRequestInvalidErr() } effect.layer = layer - case tg.LayerSemanticMethodInitConnection: + case tlprofile.SemanticMethodInitConnection: info, err := clientInfoFromLayerWrapper(wrapper) if err != nil { return nil, err } effect.info = info - case tg.LayerSemanticMethodInvokeAfterMsg, tg.LayerSemanticMethodInvokeAfterMsgs: + case tlprofile.SemanticMethodInvokeAfterMsg, tlprofile.SemanticMethodInvokeAfterMsgs: // Dependency completion is an MTProto message-lifecycle fact. The edge // validates it before scheduling this one-shot admission lease. } @@ -346,9 +346,9 @@ func (r *Router) snapshotLayerRPCWrapperEffects(ctx context.Context, request tg. func (r *Router) applyLayerRPCWrapperEffects( ctx context.Context, - profile tg.LayerProfile, + profile tlprofile.Profile, profileKnown bool, - identity tg.LayerPreparedCallIdentity, + identity tlprofile.PreparedIdentity, effects []layerRPCWrapperEffect, msgID int64, admissionSeq uint64, @@ -379,15 +379,15 @@ func (r *Router) applyLayerRPCWrapperEffects( } for _, effect := range effects { switch effect.semantic { - case tg.LayerSemanticMethodInvokeWithLayer: + case tlprofile.SemanticMethodInvokeWithLayer: 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: + case tlprofile.SemanticMethodInvokeWithoutUpdates: ctx = withInvokeWithoutUpdates(ctx) - case tg.LayerSemanticMethodInitConnection: + case tlprofile.SemanticMethodInitConnection: if mode == layerRPCWrapperApplyReplayRestore { if _, exists := ClientInfoFrom(ctx); exists { // prepareRPCDispatchContext restored newer session/auth metadata. @@ -416,7 +416,7 @@ func (r *Router) applyLayerRPCWrapperEffects( return context.WithValue(ctx, layerWrappersAppliedKey{}, identity) } -func (r *Router) applyLayerRPCWrappers(ctx context.Context, msgID int64, admissionSeq uint64, request tg.LayerRequest) (context.Context, error) { +func (r *Router) applyLayerRPCWrappers(ctx context.Context, msgID int64, admissionSeq uint64, request tlprofile.Admission) (context.Context, error) { effects, err := r.snapshotLayerRPCWrapperEffects(ctx, request) if err != nil { return nil, err @@ -428,25 +428,25 @@ func (r *Router) applyLayerRPCWrappers(ctx context.Context, msgID int64, admissi func hasMutableLayerRPCWrapperEffect(effects []layerRPCWrapperEffect) bool { for _, effect := range effects { switch effect.semantic { - case tg.LayerSemanticMethodInvokeWithLayer, tg.LayerSemanticMethodInitConnection: + case tlprofile.SemanticMethodInvokeWithLayer, tlprofile.SemanticMethodInitConnection: return true } } return false } -func (r *Router) validateLayerRPCWrappers(ctx context.Context, request tg.LayerRequest) error { +func (r *Router) validateLayerRPCWrappers(ctx context.Context, request tlprofile.Admission) 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: + case tlprofile.SemanticMethodInvokeWithLayer, + tlprofile.SemanticMethodInvokeWithoutUpdates, + tlprofile.SemanticMethodInitConnection, + tlprofile.SemanticMethodInvokeAfterMsg, + tlprofile.SemanticMethodInvokeAfterMsgs: continue default: - _, name, _ := tg.LayerSemanticName(wrapper.Semantic()) + _, name, _ := tlprofile.SemanticName(wrapper.Semantic()) fields := append([]zap.Field{ zap.String("wrapper", name), zap.String("type_id", fmt.Sprintf("%#x", wrapper.WireID())), @@ -461,15 +461,15 @@ func (r *Router) validateLayerRPCWrappers(ctx context.Context, request tg.LayerR return nil } -func (r *Router) consumeLayerRPCWrappers(ctx context.Context, request tg.LayerRequest, next tg.LayerRPCNext) error { - applied, ok := ctx.Value(layerWrappersAppliedKey{}).(tg.LayerPreparedCallIdentity) +func (r *Router) consumeLayerRPCWrappers(ctx context.Context, request tlprofile.Admission, next tlprofile.Next) error { + applied, ok := ctx.Value(layerWrappersAppliedKey{}).(tlprofile.PreparedIdentity) 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) { +func layerWrapperRequired[T any](wrapper tlprofile.Wrapper, name string) (T, error) { var zero T value, present, ok, err := wrapper.Value(name) if err != nil || !ok || !present { @@ -482,7 +482,7 @@ func layerWrapperRequired[T any](wrapper tg.LayerRPCWrapper, name string) (T, er return typed, nil } -func clientInfoFromLayerWrapper(wrapper tg.LayerRPCWrapper) (ClientInfo, error) { +func clientInfoFromLayerWrapper(wrapper tlprofile.Wrapper) (ClientInfo, error) { apiID, err := layerWrapperRequired[int](wrapper, "api_id") if err != nil { return ClientInfo{}, err diff --git a/internal/rpc/layer_dispatch_test.go b/internal/rpc/layer_dispatch_test.go index cefcf5e4..986defe6 100644 --- a/internal/rpc/layer_dispatch_test.go +++ b/internal/rpc/layer_dispatch_test.go @@ -14,6 +14,7 @@ import ( "github.com/iamxvbaba/td/tgerr" "go.uber.org/zap/zaptest" + "github.com/iamxvbaba/td/tlprofile" appfiles "telesrv/internal/app/files" "telesrv/internal/domain" "telesrv/internal/postresponse" @@ -33,7 +34,7 @@ func TestLayerAdmissionAndroidPrivateOverlayUsesExactProfile(t *testing.T) { body.PutVectorHeader(0) body.PutID(0x7f3b18ea) // inputPeerEmpty - admitted, err := r.AdmitLayer(tg.LayerProfile227, &body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitLayer(tlprofile.Profile227, &body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -41,10 +42,10 @@ func TestLayerAdmissionAndroidPrivateOverlayUsesExactProfile(t *testing.T) { t.Fatalf("private request left %d bytes", body.Len()) } call := admitted.Call() - if call.Profile() != tg.LayerProfile227 || call.Method() != tg.LayerSemanticMethodMessagesForwardMessages { + if call.Profile() != tlprofile.Profile227 || call.Method() != tlprofile.SemanticMethodMessagesForwardMessages { 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 { + if want, ok := tlprofile.WireID(tlprofile.Profile227, call.Method()); !ok || call.WireID() != want { t.Fatalf("private admission wire id = %#x, want %#x (ok=%v)", call.WireID(), want, ok) } } @@ -52,12 +53,12 @@ func TestLayerAdmissionAndroidPrivateOverlayUsesExactProfile(t *testing.T) { 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{}) + body := encodeExactLayerRPC(t, tlprofile.Profile225, request) + admitted, err := r.AdmitLayer(tlprofile.Profile225, &body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } - if body.Len() != 0 || admitted.Call().Method() != tg.LayerSemanticMethodContactsSearch { + if body.Len() != 0 || admitted.Call().Method() != tlprofile.SemanticMethodContactsSearch { t.Fatalf("official overlap = remaining:%d method:%#x", body.Len(), admitted.Call().Method()) } } @@ -66,7 +67,7 @@ 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 { + if _, err := r.AdmitLayer(tlprofile.Profile227, &bounded, tlprofile.Limits{MaxWireBytes: len(boundedOriginal) - 1}); err == nil { t.Fatal("oversized Android-private request was admitted") } if !bytes.Equal(bounded.Raw(), boundedOriginal) { @@ -76,7 +77,7 @@ func TestLayerAdmissionAndroidOverlayFailureDoesNotConsumeInput(t *testing.T) { malformed := bin.Buffer{} malformed.PutID(0x41d41ade) original := malformed.Copy() - if _, err := r.AdmitLayer(tg.LayerProfile227, &malformed, tg.LayerDecodeLimits{}); err == nil { + if _, err := r.AdmitLayer(tlprofile.Profile227, &malformed, tlprofile.Limits{}); err == nil { t.Fatal("malformed Android-private request was admitted") } if string(malformed.Raw()) != string(original) { @@ -86,7 +87,7 @@ func TestLayerAdmissionAndroidOverlayFailureDoesNotConsumeInput(t *testing.T) { unknown := bin.Buffer{} unknown.PutID(0xdeadbeef) original = unknown.Copy() - if _, err := r.AdmitLayer(tg.LayerProfile227, &unknown, tg.LayerDecodeLimits{}); !errors.Is(err, tg.ErrLayerUnknownRPCMethod) { + if _, err := r.AdmitLayer(tlprofile.Profile227, &unknown, tlprofile.Limits{}); !errors.Is(err, tlprofile.ErrUnknownRPCMethod) { t.Fatalf("official unknown error = %v", err) } if string(unknown.Raw()) != string(original) { @@ -154,12 +155,12 @@ func TestLayerAdmissionAndroidPrivateInnermostAcrossWrappers(t *testing.T) { replaceTerminalRPC(t, &initWire, private) var unprofiledInit bin.Buffer unprofiledInit.PutID(tg.InvokeWithLayerRequestTypeID) - unprofiledInit.PutInt(int(tg.LayerProfile227)) + unprofiledInit.PutInt(int(tlprofile.Profile227)) unprofiledInit.Put(initWire.Raw()) var unprofiledBare bin.Buffer unprofiledBare.PutID(tg.InvokeWithLayerRequestTypeID) - unprofiledBare.PutInt(int(tg.LayerProfile227)) + unprofiledBare.PutInt(int(tlprofile.Profile227)) unprofiledBare.Put(private) tests := []struct { @@ -179,18 +180,18 @@ func TestLayerAdmissionAndroidPrivateInnermostAcrossWrappers(t *testing.T) { t.Run(tc.name, func(t *testing.T) { body := bin.Buffer{Buf: append([]byte(nil), tc.body...)} var ( - admitted tg.LayerRequest + admitted tlprofile.Admission err error ) if tc.unprofiled { - admitted, err = r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + admitted, err = r.AdmitUnprofiled(&body, tlprofile.Limits{}) } else { - admitted, err = r.AdmitLayer(tg.LayerProfile227, &body, tg.LayerDecodeLimits{}) + admitted, err = r.AdmitLayer(tlprofile.Profile227, &body, tlprofile.Limits{}) } if err != nil { t.Fatal(err) } - if body.Len() != 0 || admitted.WrapperCount() != tc.wrappers || admitted.Call().Method() != tg.LayerSemanticMethodMessagesForwardMessages { + if body.Len() != 0 || admitted.WrapperCount() != tc.wrappers || admitted.Call().Method() != tlprofile.SemanticMethodMessagesForwardMessages { t.Fatalf("admission = remaining:%d wrappers:%d method:%#x", body.Len(), admitted.WrapperCount(), admitted.Call().Method()) } }) @@ -210,7 +211,7 @@ func TestLayerAdmissionAndroidPrivateFieldPolicyBeforeTypedMaterialization(t *te // 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") { + if _, err := r.AdmitLayer(tlprofile.Profile227, &body, tlprofile.Limits{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) { @@ -219,7 +220,7 @@ func TestLayerAdmissionAndroidPrivateFieldPolicyBeforeTypedMaterialization(t *te } func TestLayerDispatchExactProfilesShareOneHandler(t *testing.T) { - for _, profile := range []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227} { + for _, profile := range []tlprofile.Profile{tlprofile.Profile225, tlprofile.Profile227} { 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{ @@ -239,7 +240,7 @@ func TestLayerDispatchExactProfilesShareOneHandler(t *testing.T) { if err := request.Encode(&body); err != nil { t.Fatal(err) } - admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitUnprofiled(&body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -257,23 +258,19 @@ func TestLayerDispatchExactProfilesShareOneHandler(t *testing.T) { if err := result.Encode(&exact); err != nil { t.Fatal(err) } - decoded, err := tg.DecodeLayer(profile, tg.LayerConstructorConfigType(), &exact) + decodedObject, err := tlprofile.DecodeObject(profile, &exact, tlprofile.Limits{}) if err != nil { t.Fatal(err) } + decoded, ok := decodedObject.(*tg.Config) + if !ok { + t.Fatalf("decoded config type = %T", decodedObject) + } 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 { + if err := result.Encode(&replay); err != nil { t.Fatal(err) } if string(replay.Raw()) != string(tgBufferBytes(t, result)) { @@ -308,7 +305,7 @@ func TestLayerDispatchUnprofiledInvariantDoesNotPublishRepresentativeLayer(t *te if err := request.Encode(&body); err != nil { t.Fatal(err) } - admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitUnprofiled(&body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -339,11 +336,11 @@ func TestLayerDispatchUnprofiledInvariantDoesNotPublishRepresentativeLayer(t *te if err := (&tg.InvokeWithLayerRequest{Layer: 227, Query: request}).Encode(&profiledBody); err != nil { t.Fatal(err) } - profiled, err := r.AdmitUnprofiled(&profiledBody, tg.LayerDecodeLimits{}) + profiled, err := r.AdmitUnprofiled(&profiledBody, tlprofile.Limits{}) if err != nil { t.Fatal(err) } - if profile, ok := profiled.ProfileEvidence(); !ok || profile != tg.LayerProfile227 { + if profile, ok := profiled.ProfileEvidence(); !ok || profile != tlprofile.Profile227 { t.Fatalf("profiled bind evidence = (%d,%v), want layer 227", profile, ok) } freezeAndPublishLayer(t, r, rawAuthKeyID, sessionID, 100, 1, 227) @@ -376,14 +373,14 @@ func TestLayerDispatchInheritedDefaultIsEffectiveWithoutBecomingExplicitEvidence if err := request.Encode(&body); err != nil { t.Fatal(err) } - admitted, err := r.AdmitDefaultLayer(tg.LayerProfile225, &body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitDefaultLayer(tlprofile.Profile225, &body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } - if profile, ok := admitted.EffectiveProfile(); !ok || profile != tg.LayerProfile225 { + if profile, ok := admitted.EffectiveProfile(); !ok || profile != tlprofile.Profile225 { t.Fatalf("effective profile = (%d,%v), want (225,true)", profile, ok) } - if profile, ok := admitted.ProfileEvidence(); ok || profile != tg.LayerProfile(0) { + if profile, ok := admitted.ProfileEvidence(); ok || profile != tlprofile.Profile(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) @@ -419,8 +416,8 @@ func TestLayerDispatchProfiledBareIgnoresStaleMetadataLayer(t *testing.T) { ExpiresAt: 3, EncryptedMessage: []byte("bind"), } - body := encodeExactLayerRPC(t, tg.LayerProfile225, request) - admitted, err := r.AdmitLayer(tg.LayerProfile225, &body, tg.LayerDecodeLimits{}) + body := encodeExactLayerRPC(t, tlprofile.Profile225, request) + admitted, err := r.AdmitLayer(tlprofile.Profile225, &body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -461,7 +458,7 @@ func TestLayerDispatchUnprofiledInvariantWithholdsUpdatesReadinessUntilEvidence( if err := request.Encode(&body); err != nil { t.Fatal(err) } - admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitUnprofiled(&body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -497,7 +494,7 @@ func TestLayerDispatchUnprofiledInvariantWithholdsUpdatesReadinessUntilEvidence( if err := (&tg.InvokeWithLayerRequest{Layer: 227, Query: request}).Encode(&wrapped); err != nil { t.Fatal(err) } - profiled, err := r.AdmitUnprofiled(&wrapped, tg.LayerDecodeLimits{}) + profiled, err := r.AdmitUnprofiled(&wrapped, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -522,14 +519,14 @@ func TestLayerAdmissionPreflightRunsBeforeLargeVectorDecode(t *testing.T) { users[index] = &tg.InputUserEmpty{} } request := &tg.InvokeWithLayerRequest{ - Layer: int(tg.LayerProfile225), + Layer: int(tlprofile.Profile225), 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") { + if _, err := r.AdmitUnprofiled(&body, tlprofile.Limits{}); !tgerr.Is(err, "INPUT_REQUEST_TOO_LONG") { t.Fatalf("admission err = %v, want INPUT_REQUEST_TOO_LONG", err) } } @@ -537,62 +534,62 @@ func TestLayerAdmissionPreflightRunsBeforeLargeVectorDecode(t *testing.T) { func TestLayerAdmissionFieldPoliciesCoverEveryRoutableProfile(t *testing.T) { type vectorCase struct { name string - method tg.LayerSemanticID + method tlprofile.SemanticID 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 { + {"users.getUsers", tlprofile.SemanticMethodUsersGetUsers, 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 { + {"users.getRequirementsToContact", tlprofile.SemanticMethodUsersGetRequirementsToContact, 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 { + {"contacts.importContacts", tlprofile.SemanticMethodContactsImportContacts, 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 { + {"contacts.deleteContacts", tlprofile.SemanticMethodContactsDeleteContacts, 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 { + {"contacts.editCloseFriends", tlprofile.SemanticMethodContactsEditCloseFriends, 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 { + {"contacts.setBlocked", tlprofile.SemanticMethodContactsSetBlocked, 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 { + {"messages.getMessages", tlprofile.SemanticMethodMessagesGetMessages, 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 { + {"messages.getChats", tlprofile.SemanticMethodMessagesGetChats, 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 { + {"messages.getPeerDialogs", tlprofile.SemanticMethodMessagesGetPeerDialogs, 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 { + {"messages.readMessageContents", tlprofile.SemanticMethodMessagesReadMessageContents, 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 { + {"messages.getCustomEmojiDocuments", tlprofile.SemanticMethodMessagesGetCustomEmojiDocuments, 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 { + {"messages.deleteMessages", tlprofile.SemanticMethodMessagesDeleteMessages, 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 { + {"messages.createChat", tlprofile.SemanticMethodMessagesCreateChat, 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 { + {"channels.getChannels", tlprofile.SemanticMethodChannelsGetChannels, 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++ { + limits := tlprofile.Limits{MaxVectorElements: 8 << 10} + for profile := tlprofile.Profile225; profile <= tlprofile.Profile227; profile++ { for _, tc := range cases { tc := tc - if _, available := tg.LayerWireID(profile, tc.method); !available { + if _, available := tlprofile.WireID(profile, tc.method); !available { continue } t.Run(fmt.Sprintf("layer_%d/%s/at_cap", profile, tc.name), func(t *testing.T) { @@ -620,15 +617,15 @@ func TestLayerAdmissionFieldPoliciesCoverEveryRoutableProfile(t *testing.T) { 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++ { + for profile := tlprofile.Profile225; profile <= tlprofile.Profile227; 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 { + if _, err := r.AdmitLayer(profile, &atCap, tlprofile.Limits{}); 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") { + if _, err := r.AdmitLayer(profile, &over, tlprofile.Limits{}); !tgerr.Is(err, "FILE_PART_TOO_BIG") { t.Fatalf("oversized part err = %v", err) } if string(over.Raw()) != string(original) { @@ -637,13 +634,13 @@ func TestLayerAdmissionUploadFieldsCoverEveryProfile(t *testing.T) { }) 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 { + if _, err := r.AdmitLayer(profile, &atCap, tlprofile.Limits{}); 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") { + if _, err := r.AdmitLayer(profile, &body, tlprofile.Limits{}); !tgerr.Is(err, "FILE_PART_INVALID") { t.Fatalf("total parts %d err = %v", totalParts, err) } if string(body.Raw()) != string(original) { @@ -651,7 +648,7 @@ func TestLayerAdmissionUploadFieldsCoverEveryProfile(t *testing.T) { } } 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") { + if _, err := r.AdmitLayer(profile, &over, tlprofile.Limits{}); !tgerr.Is(err, "FILE_PART_TOO_BIG") { t.Fatalf("oversized big part err = %v", err) } }) @@ -666,14 +663,10 @@ func repeatLayerPreflightValue[T any](n int, value T) []T { return result } -func encodeExactLayerRPC(t *testing.T, profile tg.LayerProfile, request bin.Object) bin.Buffer { +func encodeExactLayerRPC(t *testing.T, profile tlprofile.Profile, 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 { + if err := tlprofile.EncodeObject(profile, request, &body); err != nil { t.Fatal(err) } return body @@ -682,7 +675,7 @@ func encodeExactLayerRPC(t *testing.T, profile tg.LayerProfile, request bin.Obje 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), + Layer: int(tlprofile.Profile227), Query: &tg.InvokeWithTakeoutRequest{ TakeoutID: 1, Query: &tg.HelpGetConfigRequest{}, @@ -692,7 +685,7 @@ func TestLayerDispatchRejectsUnsupportedWrapperBeforeHandler(t *testing.T) { if err := request.Encode(&body); err != nil { t.Fatal(err) } - admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitUnprofiled(&body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -715,7 +708,7 @@ func TestPrepareAdmittedReplayRestoresReadinessOnlyAfterDelivery(t *testing.T) { clock.System, ) request := &tg.InvokeWithLayerRequest{ - Layer: int(tg.LayerProfile225), + Layer: int(tlprofile.Profile225), Query: &tg.InitConnectionRequest{ APIID: 123, DeviceModel: "Desktop", SystemVersion: "Windows", AppVersion: "test", SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", @@ -726,7 +719,7 @@ func TestPrepareAdmittedReplayRestoresReadinessOnlyAfterDelivery(t *testing.T) { if err := request.Encode(&body); err != nil { t.Fatal(err) } - admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitUnprofiled(&body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -774,7 +767,7 @@ func TestRequestBoundOnlyLayerRPCDoesNotPublishMetadataOrReadiness(t *testing.T) clock.System, ) request := &tg.InvokeWithLayerRequest{ - Layer: int(tg.LayerProfile225), + Layer: int(tlprofile.Profile225), Query: &tg.InitConnectionRequest{ APIID: 123, DeviceModel: "Stale Desktop", SystemVersion: "Windows", AppVersion: "stale", SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", @@ -785,7 +778,7 @@ func TestRequestBoundOnlyLayerRPCDoesNotPublishMetadataOrReadiness(t *testing.T) if err := request.Encode(&body); err != nil { t.Fatal(err) } - admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitUnprofiled(&body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -830,7 +823,7 @@ func TestPrepareAdmittedReplayDoesNotRollBackNewerExplicitLayerOrClientInfo(t *t clock.System, ) oldRequest := &tg.InvokeWithLayerRequest{ - Layer: int(tg.LayerProfile225), + Layer: int(tlprofile.Profile225), Query: &tg.InitConnectionRequest{ APIID: 123, DeviceModel: "Old Desktop", SystemVersion: "Windows 10", AppVersion: "old", SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", @@ -841,7 +834,7 @@ func TestPrepareAdmittedReplayDoesNotRollBackNewerExplicitLayerOrClientInfo(t *t if err := oldRequest.Encode(&body); err != nil { t.Fatal(err) } - admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitUnprofiled(&body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -886,7 +879,7 @@ func TestDelayedExplicitDispatchCannotRollBackAdmissionTimeLayerOrInitMetadata(t zaptest.NewLogger(t), clock.System, ) - admit := func(layer int, device, version string) tg.LayerRequest { + admit := func(layer int, device, version string) tlprofile.Admission { t.Helper() request := &tg.InvokeWithLayerRequest{ Layer: layer, @@ -900,7 +893,7 @@ func TestDelayedExplicitDispatchCannotRollBackAdmissionTimeLayerOrInitMetadata(t if err := request.Encode(&body); err != nil { t.Fatal(err) } - admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitUnprofiled(&body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } @@ -940,7 +933,7 @@ func TestSameLayerNakedInitConnectionUsesMessageIDWatermark(t *testing.T) { zaptest.NewLogger(t), clock.System, ) - admit := func(device, version string) tg.LayerRequest { + admit := func(device, version string) tlprofile.Admission { t.Helper() request := &tg.InitConnectionRequest{ APIID: 123, DeviceModel: device, SystemVersion: "Windows", AppVersion: version, @@ -951,7 +944,7 @@ func TestSameLayerNakedInitConnectionUsesMessageIDWatermark(t *testing.T) { if err := request.Encode(&body); err != nil { t.Fatal(err) } - admitted, err := r.AdmitDefaultLayer(tg.LayerProfile227, &body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitDefaultLayer(tlprofile.Profile227, &body, tlprofile.Limits{}) if err != nil { t.Fatal(err) } diff --git a/internal/rpc/layer_inheritance.go b/internal/rpc/layer_inheritance.go index 93832a39..7d78e743 100644 --- a/internal/rpc/layer_inheritance.go +++ b/internal/rpc/layer_inheritance.go @@ -7,9 +7,9 @@ import ( "sort" "time" - "github.com/iamxvbaba/td/tg" "go.uber.org/zap" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" "telesrv/internal/store" ) @@ -609,6 +609,6 @@ func isSupportedLayer(layer int) bool { if layer <= 0 { return false } - profile, ok := tg.ResolveLayerProfile(layer) + profile, ok := tlprofile.ResolveProfile(layer) return ok && int(profile) == layer } diff --git a/internal/rpc/messages_create_chat_test.go b/internal/rpc/messages_create_chat_test.go index 9176b763..a7f08eb1 100644 --- a/internal/rpc/messages_create_chat_test.go +++ b/internal/rpc/messages_create_chat_test.go @@ -107,13 +107,12 @@ func TestMessagesCreateChatCreatesMegagroupAndDialogsRPC(t *testing.T) { if err != nil { t.Fatalf("dispatch get dialogs: %v", err) } - box, ok := enc.(*tg.MessagesDialogsBox) + dialogs, ok := enc.(*tg.MessagesDialogs) if !ok { - t.Fatalf("dialogs response = %T, want box", enc) + t.Fatalf("dialogs response = %T, want *tg.MessagesDialogs", enc) } - dialogs, ok := box.Dialogs.(*tg.MessagesDialogs) - if !ok || len(dialogs.Dialogs) != 1 || len(dialogs.Chats) != 1 || len(dialogs.Messages) != 1 { - t.Fatalf("dialogs = %T %+v, want channel dialog/chat/message", box.Dialogs, box.Dialogs) + if len(dialogs.Dialogs) != 1 || len(dialogs.Chats) != 1 || len(dialogs.Messages) != 1 { + t.Fatalf("dialogs = %+v, want channel dialog/chat/message", dialogs) } dialog := dialogs.Dialogs[0].(*tg.Dialog) if peer, ok := dialog.Peer.(*tg.PeerChannel); !ok || peer.ChannelID != channel.ID { @@ -227,12 +226,11 @@ func TestMessagesCreateChatTDesktopReturnsLegacyChatAndAcceptsInputPeerChatRPC(t if err != nil { t.Fatalf("legacy history: %v", err) } - legacyBox, ok := legacyHistory.(*tg.MessagesMessagesBox) + legacyMessages, ok := legacyHistory.(*tg.MessagesMessages) if !ok { - t.Fatalf("legacy history = %T %+v, want messages box", legacyHistory, legacyHistory) + t.Fatalf("legacy history = %T %+v, want *tg.MessagesMessages", legacyHistory, legacyHistory) } - legacyMessages, ok := legacyBox.Messages.(*tg.MessagesMessages) - if !ok || len(legacyMessages.Messages) != 0 { + if len(legacyMessages.Messages) != 0 { t.Fatalf("legacy history = %T %+v, want empty messages.messages", legacyHistory, legacyHistory) } diff --git a/internal/rpc/messages_edit_rpc_test.go b/internal/rpc/messages_edit_rpc_test.go index 563b102f..a930e97b 100644 --- a/internal/rpc/messages_edit_rpc_test.go +++ b/internal/rpc/messages_edit_rpc_test.go @@ -73,13 +73,12 @@ func TestMessagesEditMessageReturnsUpdateAndRecordsOwnerContext(t *testing.T) { if err != nil { t.Fatalf("dispatch: %v", err) } - box, ok := enc.(*tg.UpdatesBox) + got, ok := enc.(*tg.Updates) if !ok { - t.Fatalf("response = %T, want *tg.UpdatesBox", enc) + t.Fatalf("response = %T, want *tg.Updates", enc) } - got, ok := box.Updates.(*tg.Updates) - if !ok || len(got.Updates) != 1 { - t.Fatalf("boxed updates = %T %+v, want one update", box.Updates, box.Updates) + if len(got.Updates) != 1 { + t.Fatalf("updates = %+v, want one update", got) } edit, ok := got.Updates[0].(*tg.UpdateEditMessage) if !ok || edit.Pts != 7 || edit.PtsCount != 1 { diff --git a/internal/rpc/messages_forward_rpc_test.go b/internal/rpc/messages_forward_rpc_test.go index 065b58f6..1a290aee 100644 --- a/internal/rpc/messages_forward_rpc_test.go +++ b/internal/rpc/messages_forward_rpc_test.go @@ -60,11 +60,10 @@ func TestMessagesForwardMessagesRecordsRequestAndReturnsUpdates(t *testing.T) { if messages.sendReq.ReplyTo == nil || messages.sendReq.ReplyTo.MessageID != 9 || messages.sendReq.ReplyTo.Peer.ID != toID || messages.sendReq.ReplyTo.QuoteText != "target" { t.Fatalf("forward reply = %+v, want target peer reply metadata", messages.sendReq.ReplyTo) } - box, ok := enc.(*tg.UpdatesBox) + got, ok := enc.(*tg.Updates) if !ok { - t.Fatalf("response = %T, want *tg.UpdatesBox", enc) + t.Fatalf("response = %T, want *tg.Updates", enc) } - got := box.Updates.(*tg.Updates) if len(got.Updates) != 4 { t.Fatalf("updates = %+v, want two message ids and two new messages", got.Updates) } diff --git a/internal/rpc/messages_history_rpc_test.go b/internal/rpc/messages_history_rpc_test.go index 2fa237e8..6e93452c 100644 --- a/internal/rpc/messages_history_rpc_test.go +++ b/internal/rpc/messages_history_rpc_test.go @@ -130,9 +130,6 @@ func TestMessagesSearchChannelPeerReturnsSingleCopyMessages(t *testing.T) { if err != nil { t.Fatalf("dispatch shared media count search: %v", err) } - if box, ok := enc.(*tg.MessagesMessagesBox); ok { - enc = box.Messages - } channelMessages, ok := enc.(*tg.MessagesChannelMessages) if !ok { t.Fatalf("shared media count search result = %T, want messages.channelMessages", enc) @@ -210,9 +207,6 @@ func TestMessagesSearchChatPhotosDoesNotReturnOrdinaryChannelHistory(t *testing. if err != nil { t.Fatalf("dispatch chat photos search: %v", err) } - if box, ok := enc.(*tg.MessagesMessagesBox); ok { - enc = box.Messages - } got, ok := enc.(*tg.MessagesChannelMessages) if !ok { t.Fatalf("chat photos search result = %T, want messages.channelMessages", enc) @@ -315,9 +309,6 @@ func TestMessagesGetSearchCountersUsesMediaCategoryCounts(t *testing.T) { if err != nil { t.Fatalf("dispatch shared media count search: %v", err) } - if box, ok := enc.(*tg.MessagesMessagesBox); ok { - enc = box.Messages - } channelMessages, ok := enc.(*tg.MessagesChannelMessages) if !ok { t.Fatalf("shared media count search result = %T, want messages.channelMessages", enc) @@ -498,13 +489,9 @@ func TestMessagesGetHistoryReturnsStoredMessages(t *testing.T) { if err != nil { t.Fatalf("dispatch: %v", err) } - box, ok := enc.(*tg.MessagesMessagesBox) + got, ok := enc.(*tg.MessagesMessages) if !ok { - t.Fatalf("response = %T, want *tg.MessagesMessagesBox", enc) - } - got, ok := box.Messages.(*tg.MessagesMessages) - if !ok { - t.Fatalf("boxed response = %T, want *tg.MessagesMessages", box.Messages) + t.Fatalf("response = %T, want *tg.MessagesMessages", enc) } if len(got.Messages) != 1 || len(got.Users) != 1 { t.Fatalf("history = %+v, want one message and one user", got) diff --git a/internal/rpc/messages_monoforum_rpc_test.go b/internal/rpc/messages_monoforum_rpc_test.go index 4b8ab926..5a70beb7 100644 --- a/internal/rpc/messages_monoforum_rpc_test.go +++ b/internal/rpc/messages_monoforum_rpc_test.go @@ -73,13 +73,9 @@ func TestMonoforumSavedDialogsAndHistory(t *testing.T) { if err != nil { t.Fatalf("dispatch getHistory(monoforum): %v", err) } - mainBox, ok := mainEnc.(*tg.MessagesMessagesBox) + mainHistory, ok := mainEnc.(*tg.MessagesChannelMessages) if !ok { - t.Fatalf("getHistory(monoforum) = %T, want MessagesMessagesBox", mainEnc) - } - mainHistory, ok := mainBox.Messages.(*tg.MessagesChannelMessages) - if !ok { - t.Fatalf("getHistory(monoforum) boxed = %T, want MessagesChannelMessages", mainBox.Messages) + t.Fatalf("getHistory(monoforum) = %T, want *tg.MessagesChannelMessages", mainEnc) } if len(mainHistory.Messages) != 1 { t.Fatalf("main monoforum history = %d msgs, want only the creation service", len(mainHistory.Messages)) diff --git a/internal/rpc/messages_received_config_test.go b/internal/rpc/messages_received_config_test.go index 6cb9750b..76216571 100644 --- a/internal/rpc/messages_received_config_test.go +++ b/internal/rpc/messages_received_config_test.go @@ -126,8 +126,8 @@ func TestMessagesReceivedMessagesIsRegistered(t *testing.T) { if method != "messages.receivedMessages" { t.Fatalf("method = %q, want messages.receivedMessages", method) } - vector, ok := result.(*tg.ReceivedNotifyMessageVector) - if !ok || vector == nil || vector.Elems == nil || len(vector.Elems) != 0 { + vector, ok := dispatchCanonicalValue(result).([]tg.ReceivedNotifyMessage) + if !ok || vector == nil || len(vector) != 0 { t.Fatalf("result = %#v (%T), want non-nil empty ReceivedNotifyMessageVector", result, result) } } diff --git a/internal/rpc/messages_register.go b/internal/rpc/messages_register.go index b6f7b5e1..09c63aa8 100644 --- a/internal/rpc/messages_register.go +++ b/internal/rpc/messages_register.go @@ -3,142 +3,394 @@ package rpc import ( "context" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" "unicode/utf8" ) // registerMessages 注册 messages.* RPC handler。 -func (r *Router) registerMessages(d *tg.ServerDispatcher) { - d.OnMessagesReceivedMessages(r.onMessagesReceivedMessages) - d.OnMessagesSetTyping(r.onMessagesSetTyping) - d.OnMessagesSaveDraft(r.onMessagesSaveDraft) - d.OnMessagesSaveDefaultSendAs(r.onMessagesSaveDefaultSendAs) - d.OnMessagesGetAllDrafts(r.onMessagesGetAllDrafts) - d.OnMessagesClearAllDrafts(r.onMessagesClearAllDrafts) - d.OnMessagesGetAllStickers(r.onMessagesGetAllStickers) - d.OnMessagesGetEmojiStickers(r.onMessagesGetEmojiStickers) - d.OnMessagesGetMaskStickers(r.onMessagesGetMaskStickers) - d.OnMessagesGetFeaturedStickers(r.onMessagesGetFeaturedStickers) - d.OnMessagesGetFeaturedEmojiStickers(r.onMessagesGetFeaturedEmojiStickers) - d.OnMessagesGetOldFeaturedStickers(r.onMessagesGetOldFeaturedStickers) - d.OnMessagesGetRecentStickers(r.onMessagesGetRecentStickers) - d.OnMessagesGetFavedStickers(r.onMessagesGetFavedStickers) - d.OnMessagesGetSavedGifs(r.onMessagesGetSavedGifs) - d.OnMessagesFaveSticker(r.onMessagesFaveSticker) - d.OnMessagesSaveRecentSticker(r.onMessagesSaveRecentSticker) - d.OnMessagesSaveGif(r.onMessagesSaveGif) - d.OnMessagesClearRecentStickers(r.onMessagesClearRecentStickers) - d.OnMessagesSendMessage(r.onMessagesSendMessage) - d.OnMessagesForwardMessages(r.onMessagesForwardMessages) - d.OnMessagesGetDialogFilters(r.onMessagesGetDialogFilters) - d.OnMessagesGetSuggestedDialogFilters(func(ctx context.Context) ([]tg.DialogFilterSuggested, error) { +func (r *Router) registerMessages(d *tlprofile.Dispatcher) { + registerRPC[*tg.MessagesReceivedMessagesRequest](d, tlprofile.SemanticMethodMessagesReceivedMessages, func(ctx context.Context, layerRequest *tg.MessagesReceivedMessagesRequest) (any, error) { + return r.onMessagesReceivedMessages(ctx, layerRequest. + MaxID) + }) + registerRPC[*tg.MessagesSetTypingRequest](d, tlprofile.SemanticMethodMessagesSetTyping, func(ctx context.Context, layerRequest *tg.MessagesSetTypingRequest) (any, error) { + return r.onMessagesSetTyping(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSaveDraftRequest](d, tlprofile.SemanticMethodMessagesSaveDraft, func(ctx context.Context, layerRequest *tg.MessagesSaveDraftRequest) (any, error) { + return r.onMessagesSaveDraft(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSaveDefaultSendAsRequest](d, tlprofile.SemanticMethodMessagesSaveDefaultSendAs, func(ctx context.Context, layerRequest *tg.MessagesSaveDefaultSendAsRequest) (any, error) { + return r.onMessagesSaveDefaultSendAs(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetAllDraftsRequest](d, tlprofile.SemanticMethodMessagesGetAllDrafts, func(ctx context.Context, layerRequest *tg.MessagesGetAllDraftsRequest) (any, error) { + return r.onMessagesGetAllDrafts(ctx) + }) + registerRPC[*tg.MessagesClearAllDraftsRequest](d, tlprofile.SemanticMethodMessagesClearAllDrafts, func(ctx context.Context, layerRequest *tg.MessagesClearAllDraftsRequest) (any, error) { + return r.onMessagesClearAllDrafts(ctx) + }) + registerRPC[*tg.MessagesGetAllStickersRequest](d, tlprofile.SemanticMethodMessagesGetAllStickers, func(ctx context.Context, layerRequest *tg.MessagesGetAllStickersRequest) (any, error) { + return r.onMessagesGetAllStickers(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesGetEmojiStickersRequest](d, tlprofile.SemanticMethodMessagesGetEmojiStickers, func(ctx context.Context, layerRequest *tg.MessagesGetEmojiStickersRequest) (any, error) { + return r.onMessagesGetEmojiStickers(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesGetMaskStickersRequest](d, tlprofile.SemanticMethodMessagesGetMaskStickers, func(ctx context.Context, layerRequest *tg.MessagesGetMaskStickersRequest) (any, error) { + return r.onMessagesGetMaskStickers(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesGetFeaturedStickersRequest](d, tlprofile.SemanticMethodMessagesGetFeaturedStickers, func(ctx context.Context, layerRequest *tg.MessagesGetFeaturedStickersRequest) (any, error) { + return r.onMessagesGetFeaturedStickers(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesGetFeaturedEmojiStickersRequest](d, tlprofile.SemanticMethodMessagesGetFeaturedEmojiStickers, func(ctx context.Context, layerRequest *tg.MessagesGetFeaturedEmojiStickersRequest) (any, error) { + return r.onMessagesGetFeaturedEmojiStickers(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesGetOldFeaturedStickersRequest](d, tlprofile.SemanticMethodMessagesGetOldFeaturedStickers, func(ctx context.Context, layerRequest *tg.MessagesGetOldFeaturedStickersRequest) (any, error) { + return r.onMessagesGetOldFeaturedStickers(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetRecentStickersRequest](d, tlprofile.SemanticMethodMessagesGetRecentStickers, func(ctx context.Context, layerRequest *tg.MessagesGetRecentStickersRequest) (any, error) { + return r.onMessagesGetRecentStickers(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetFavedStickersRequest](d, tlprofile.SemanticMethodMessagesGetFavedStickers, func(ctx context.Context, layerRequest *tg.MessagesGetFavedStickersRequest) (any, error) { + return r.onMessagesGetFavedStickers(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesGetSavedGifsRequest](d, tlprofile.SemanticMethodMessagesGetSavedGifs, func(ctx context.Context, layerRequest *tg.MessagesGetSavedGifsRequest) (any, error) { + return r.onMessagesGetSavedGifs(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesFaveStickerRequest](d, tlprofile.SemanticMethodMessagesFaveSticker, func(ctx context.Context, layerRequest *tg.MessagesFaveStickerRequest) (any, error) { + return r.onMessagesFaveSticker(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSaveRecentStickerRequest](d, tlprofile.SemanticMethodMessagesSaveRecentSticker, func(ctx context.Context, layerRequest *tg.MessagesSaveRecentStickerRequest) (any, error) { + return r.onMessagesSaveRecentSticker(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSaveGifRequest](d, tlprofile.SemanticMethodMessagesSaveGif, func(ctx context.Context, layerRequest *tg.MessagesSaveGifRequest) (any, error) { + return r.onMessagesSaveGif(ctx, layerRequest) + }) + registerRPC[*tg.MessagesClearRecentStickersRequest](d, tlprofile.SemanticMethodMessagesClearRecentStickers, func(ctx context.Context, layerRequest *tg.MessagesClearRecentStickersRequest) (any, error) { + return r.onMessagesClearRecentStickers(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendMessageRequest](d, tlprofile.SemanticMethodMessagesSendMessage, func(ctx context.Context, layerRequest *tg.MessagesSendMessageRequest) (any, error) { + return r.onMessagesSendMessage(ctx, layerRequest) + }) + registerRPC[*tg.MessagesForwardMessagesRequest](d, tlprofile.SemanticMethodMessagesForwardMessages, func(ctx context.Context, layerRequest *tg.MessagesForwardMessagesRequest) (any, error) { + return r.onMessagesForwardMessages(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetDialogFiltersRequest](d, tlprofile.SemanticMethodMessagesGetDialogFilters, func(ctx context.Context, layerRequest *tg.MessagesGetDialogFiltersRequest) (any, error) { + return r.onMessagesGetDialogFilters(ctx) + }) + registerRPC[*tg.MessagesGetSuggestedDialogFiltersRequest](d, tlprofile.SemanticMethodMessagesGetSuggestedDialogFilters, func(ctx context.Context, layerRequest *tg.MessagesGetSuggestedDialogFiltersRequest) (any, error) { return tdesktop.SuggestedDialogFilters(), nil }) - d.OnMessagesUpdateDialogFilter(r.onMessagesUpdateDialogFilter) - d.OnMessagesUpdateDialogFiltersOrder(r.onMessagesUpdateDialogFiltersOrder) - d.OnMessagesToggleDialogFilterTags(r.onMessagesToggleDialogFilterTags) - d.OnMessagesGetSavedDialogs(r.onMessagesGetSavedDialogs) - d.OnMessagesGetPinnedSavedDialogs(func(ctx context.Context) (tg.MessagesSavedDialogsClass, error) { + registerRPC[*tg.MessagesUpdateDialogFilterRequest](d, tlprofile.SemanticMethodMessagesUpdateDialogFilter, func(ctx context.Context, layerRequest *tg.MessagesUpdateDialogFilterRequest) (any, error) { + return r.onMessagesUpdateDialogFilter(ctx, layerRequest) + }) + registerRPC[*tg.MessagesUpdateDialogFiltersOrderRequest](d, tlprofile.SemanticMethodMessagesUpdateDialogFiltersOrder, func(ctx context.Context, layerRequest *tg.MessagesUpdateDialogFiltersOrderRequest) (any, error) { + return r.onMessagesUpdateDialogFiltersOrder(ctx, layerRequest. + Order) + }) + registerRPC[*tg.MessagesToggleDialogFilterTagsRequest](d, tlprofile.SemanticMethodMessagesToggleDialogFilterTags, func(ctx context.Context, layerRequest *tg.MessagesToggleDialogFilterTagsRequest) (any, error) { + return r.onMessagesToggleDialogFilterTags(ctx, layerRequest. + Enabled) + }) + registerRPC[*tg.MessagesGetSavedDialogsRequest](d, tlprofile.SemanticMethodMessagesGetSavedDialogs, func(ctx context.Context, layerRequest *tg.MessagesGetSavedDialogsRequest) (any, error) { + return r.onMessagesGetSavedDialogs(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetPinnedSavedDialogsRequest](d, tlprofile.SemanticMethodMessagesGetPinnedSavedDialogs, func(ctx context.Context, layerRequest *tg.MessagesGetPinnedSavedDialogsRequest) (any, error) { return r.onMessagesGetPinnedSavedDialogs(ctx) }) - d.OnMessagesToggleSavedDialogPin(r.onMessagesToggleSavedDialogPin) - d.OnMessagesReorderPinnedSavedDialogs(r.onMessagesReorderPinnedSavedDialogs) - d.OnMessagesGetSavedDialogsByID(r.onMessagesGetSavedDialogsByID) - d.OnMessagesGetSavedHistory(r.onMessagesGetSavedHistory) - d.OnMessagesReadSavedHistory(r.onMessagesReadSavedHistory) - d.OnMessagesDeleteSavedHistory(r.onMessagesDeleteSavedHistory) - d.OnMessagesGetCommonChats(r.onMessagesGetCommonChats) - d.OnMessagesGetDefaultHistoryTTL(r.onMessagesGetDefaultHistoryTTL) - d.OnMessagesSetHistoryTTL(r.onMessagesSetHistoryTTL) - d.OnMessagesSetDefaultHistoryTTL(r.onMessagesSetDefaultHistoryTTL) - d.OnMessagesGetSponsoredMessages(r.onMessagesGetSponsoredMessages) - d.OnMessagesGetWebPagePreview(r.onMessagesGetWebPagePreview) - d.OnMessagesRequestWebView(r.onMessagesRequestWebView) - d.OnMessagesProlongWebView(r.onMessagesProlongWebView) - d.OnMessagesSendWebViewResultMessage(r.onMessagesSendWebViewResultMessage) - d.OnMessagesRequestSimpleWebView(r.onMessagesRequestSimpleWebView) - d.OnMessagesGetBotApp(r.onMessagesGetBotApp) - d.OnMessagesRequestAppWebView(r.onMessagesRequestAppWebView) - d.OnMessagesRequestMainWebView(r.onMessagesRequestMainWebView) - d.OnMessagesSendWebViewData(r.onMessagesSendWebViewData) - d.OnMessagesSendBotRequestedPeer(r.onMessagesSendBotRequestedPeer) - d.OnMessagesGetPreparedInlineMessage(r.onMessagesGetPreparedInlineMessage) - d.OnMessagesGetEmojiGameInfo(r.onMessagesGetEmojiGameInfo) - d.OnMessagesGetGameHighScores(r.onMessagesGetGameHighScores) - d.OnMessagesGetInlineGameHighScores(r.onMessagesGetInlineGameHighScores) - d.OnMessagesSetGameScore(r.onMessagesSetGameScore) - d.OnMessagesSetInlineGameScore(r.onMessagesSetInlineGameScore) - d.OnMessagesUploadMedia(r.onMessagesUploadMedia) - d.OnMessagesSendMedia(r.onMessagesSendMedia) - d.OnMessagesSendMultiMedia(r.onMessagesSendMultiMedia) - d.OnMessagesReportSpam(r.onMessagesReportSpam) - d.OnMessagesReport(r.onMessagesReport) - d.OnMessagesReportReaction(r.onMessagesReportReaction) - d.OnMessagesReportMessagesDelivery(r.onMessagesReportMessagesDelivery) - d.OnMessagesReportReadMetrics(r.onMessagesReportReadMetrics) - d.OnMessagesReportMusicListen(r.onMessagesReportMusicListen) - d.OnMessagesReportSponsoredMessage(r.onMessagesReportSponsoredMessage) - d.OnMessagesReadMessageContents(r.onMessagesReadMessageContents) - d.OnMessagesTranslateText(r.onMessagesTranslateText) - d.OnMessagesTogglePeerTranslations(r.onMessagesTogglePeerTranslations) - d.OnMessagesGetMessagesViews(r.onMessagesGetMessagesViews) - d.OnMessagesGetUnreadMentions(r.onMessagesGetUnreadMentions) - d.OnMessagesReadMentions(r.onMessagesReadMentions) - d.OnMessagesGetSearchCounters(r.onMessagesGetSearchCounters) - d.OnMessagesGetReplies(r.onMessagesGetReplies) - d.OnMessagesGetDiscussionMessage(r.onMessagesGetDiscussionMessage) - d.OnMessagesReadDiscussion(r.onMessagesReadDiscussion) - d.OnMessagesGetForumTopics(r.onMessagesGetForumTopics) - d.OnMessagesGetForumTopicsByID(r.onMessagesGetForumTopicsByID) - d.OnMessagesGetOnlines(r.onMessagesGetOnlines) - d.OnMessagesGetAvailableReactions(r.onMessagesGetAvailableReactions) - d.OnMessagesGetAvailableEffects(r.onMessagesGetAvailableEffects) - d.OnMessagesGetStickers(r.onMessagesGetStickers) - d.OnMessagesInstallStickerSet(r.onMessagesInstallStickerSet) - d.OnMessagesUninstallStickerSet(r.onMessagesUninstallStickerSet) - d.OnMessagesReorderStickerSets(r.onMessagesReorderStickerSets) - d.OnMessagesToggleStickerSets(r.onMessagesToggleStickerSets) - d.OnMessagesGetMyStickers(r.onMessagesGetMyStickers) - d.OnMessagesGetArchivedStickers(func(ctx context.Context, req *tg.MessagesGetArchivedStickersRequest) (*tg.MessagesArchivedStickers, error) { + registerRPC[*tg.MessagesToggleSavedDialogPinRequest](d, tlprofile.SemanticMethodMessagesToggleSavedDialogPin, func(ctx context.Context, layerRequest *tg.MessagesToggleSavedDialogPinRequest) (any, error) { + return r.onMessagesToggleSavedDialogPin(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReorderPinnedSavedDialogsRequest](d, tlprofile.SemanticMethodMessagesReorderPinnedSavedDialogs, func(ctx context.Context, layerRequest *tg.MessagesReorderPinnedSavedDialogsRequest) (any, error) { + return r.onMessagesReorderPinnedSavedDialogs(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetSavedDialogsByIDRequest](d, tlprofile.SemanticMethodMessagesGetSavedDialogsByID, func(ctx context.Context, layerRequest *tg.MessagesGetSavedDialogsByIDRequest) (any, error) { + return r.onMessagesGetSavedDialogsByID(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetSavedHistoryRequest](d, tlprofile.SemanticMethodMessagesGetSavedHistory, func(ctx context.Context, layerRequest *tg.MessagesGetSavedHistoryRequest) (any, error) { + return r.onMessagesGetSavedHistory(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReadSavedHistoryRequest](d, tlprofile.SemanticMethodMessagesReadSavedHistory, func(ctx context.Context, layerRequest *tg.MessagesReadSavedHistoryRequest) (any, error) { + return r.onMessagesReadSavedHistory(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteSavedHistoryRequest](d, tlprofile.SemanticMethodMessagesDeleteSavedHistory, func(ctx context.Context, layerRequest *tg.MessagesDeleteSavedHistoryRequest) (any, error) { + return r.onMessagesDeleteSavedHistory(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetCommonChatsRequest](d, tlprofile.SemanticMethodMessagesGetCommonChats, func(ctx context.Context, layerRequest *tg.MessagesGetCommonChatsRequest) (any, error) { + return r.onMessagesGetCommonChats(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetDefaultHistoryTTLRequest](d, tlprofile.SemanticMethodMessagesGetDefaultHistoryTTL, func(ctx context.Context, layerRequest *tg.MessagesGetDefaultHistoryTTLRequest) (any, error) { + return r.onMessagesGetDefaultHistoryTTL(ctx) + }) + registerRPC[*tg.MessagesSetHistoryTTLRequest](d, tlprofile.SemanticMethodMessagesSetHistoryTTL, func(ctx context.Context, layerRequest *tg.MessagesSetHistoryTTLRequest) (any, error) { + return r.onMessagesSetHistoryTTL(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetDefaultHistoryTTLRequest](d, tlprofile.SemanticMethodMessagesSetDefaultHistoryTTL, func(ctx context.Context, layerRequest *tg.MessagesSetDefaultHistoryTTLRequest) (any, error) { + return r.onMessagesSetDefaultHistoryTTL(ctx, layerRequest. + Period) + }) + registerRPC[*tg.MessagesGetSponsoredMessagesRequest](d, tlprofile.SemanticMethodMessagesGetSponsoredMessages, func(ctx context.Context, layerRequest *tg.MessagesGetSponsoredMessagesRequest) (any, error) { + return r.onMessagesGetSponsoredMessages(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetWebPagePreviewRequest](d, tlprofile.SemanticMethodMessagesGetWebPagePreview, func(ctx context.Context, layerRequest *tg.MessagesGetWebPagePreviewRequest) (any, error) { + return r.onMessagesGetWebPagePreview(ctx, layerRequest) + }) + registerRPC[*tg.MessagesRequestWebViewRequest](d, tlprofile.SemanticMethodMessagesRequestWebView, func(ctx context.Context, layerRequest *tg.MessagesRequestWebViewRequest) (any, error) { + return r.onMessagesRequestWebView(ctx, layerRequest) + }) + registerRPC[*tg.MessagesProlongWebViewRequest](d, tlprofile.SemanticMethodMessagesProlongWebView, func(ctx context.Context, layerRequest *tg.MessagesProlongWebViewRequest) (any, error) { + return r.onMessagesProlongWebView(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendWebViewResultMessageRequest](d, tlprofile.SemanticMethodMessagesSendWebViewResultMessage, func(ctx context.Context, layerRequest *tg.MessagesSendWebViewResultMessageRequest) (any, error) { + return r.onMessagesSendWebViewResultMessage(ctx, layerRequest) + }) + registerRPC[*tg.MessagesRequestSimpleWebViewRequest](d, tlprofile.SemanticMethodMessagesRequestSimpleWebView, func(ctx context.Context, layerRequest *tg.MessagesRequestSimpleWebViewRequest) (any, error) { + return r.onMessagesRequestSimpleWebView(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetBotAppRequest](d, tlprofile.SemanticMethodMessagesGetBotApp, func(ctx context.Context, layerRequest *tg.MessagesGetBotAppRequest) (any, error) { + return r.onMessagesGetBotApp(ctx, layerRequest) + }) + registerRPC[*tg.MessagesRequestAppWebViewRequest](d, tlprofile.SemanticMethodMessagesRequestAppWebView, func(ctx context.Context, layerRequest *tg.MessagesRequestAppWebViewRequest) (any, error) { + return r.onMessagesRequestAppWebView(ctx, layerRequest) + }) + registerRPC[*tg.MessagesRequestMainWebViewRequest](d, tlprofile.SemanticMethodMessagesRequestMainWebView, func(ctx context.Context, layerRequest *tg.MessagesRequestMainWebViewRequest) (any, error) { + return r.onMessagesRequestMainWebView(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendWebViewDataRequest](d, tlprofile.SemanticMethodMessagesSendWebViewData, func(ctx context.Context, layerRequest *tg.MessagesSendWebViewDataRequest) (any, error) { + return r.onMessagesSendWebViewData(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendBotRequestedPeerRequest](d, tlprofile.SemanticMethodMessagesSendBotRequestedPeer, func(ctx context.Context, layerRequest *tg.MessagesSendBotRequestedPeerRequest) (any, error) { + return r.onMessagesSendBotRequestedPeer(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetPreparedInlineMessageRequest](d, tlprofile.SemanticMethodMessagesGetPreparedInlineMessage, func(ctx context.Context, layerRequest *tg.MessagesGetPreparedInlineMessageRequest) (any, error) { + return r.onMessagesGetPreparedInlineMessage(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetEmojiGameInfoRequest](d, tlprofile.SemanticMethodMessagesGetEmojiGameInfo, func(ctx context.Context, layerRequest *tg.MessagesGetEmojiGameInfoRequest) (any, error) { + return r.onMessagesGetEmojiGameInfo(ctx) + }) + registerRPC[*tg.MessagesGetGameHighScoresRequest](d, tlprofile.SemanticMethodMessagesGetGameHighScores, func(ctx context.Context, layerRequest *tg.MessagesGetGameHighScoresRequest) (any, error) { + return r.onMessagesGetGameHighScores(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetInlineGameHighScoresRequest](d, tlprofile.SemanticMethodMessagesGetInlineGameHighScores, func(ctx context.Context, layerRequest *tg.MessagesGetInlineGameHighScoresRequest) (any, error) { + return r.onMessagesGetInlineGameHighScores(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetGameScoreRequest](d, tlprofile.SemanticMethodMessagesSetGameScore, func(ctx context.Context, layerRequest *tg.MessagesSetGameScoreRequest) (any, error) { + return r.onMessagesSetGameScore(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetInlineGameScoreRequest](d, tlprofile.SemanticMethodMessagesSetInlineGameScore, func(ctx context.Context, layerRequest *tg.MessagesSetInlineGameScoreRequest) (any, error) { + return r.onMessagesSetInlineGameScore(ctx, layerRequest) + }) + registerRPC[*tg.MessagesUploadMediaRequest](d, tlprofile.SemanticMethodMessagesUploadMedia, func(ctx context.Context, layerRequest *tg.MessagesUploadMediaRequest) (any, error) { + return r.onMessagesUploadMedia(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendMediaRequest](d, tlprofile.SemanticMethodMessagesSendMedia, func(ctx context.Context, layerRequest *tg.MessagesSendMediaRequest) (any, error) { + return r.onMessagesSendMedia(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendMultiMediaRequest](d, tlprofile.SemanticMethodMessagesSendMultiMedia, func(ctx context.Context, layerRequest *tg.MessagesSendMultiMediaRequest) (any, error) { + return r.onMessagesSendMultiMedia(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReportSpamRequest](d, tlprofile.SemanticMethodMessagesReportSpam, func(ctx context.Context, layerRequest *tg.MessagesReportSpamRequest) (any, error) { + return r.onMessagesReportSpam(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.MessagesReportRequest](d, tlprofile.SemanticMethodMessagesReport, func(ctx context.Context, layerRequest *tg.MessagesReportRequest) (any, error) { + return r.onMessagesReport(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReportReactionRequest](d, tlprofile.SemanticMethodMessagesReportReaction, func(ctx context.Context, layerRequest *tg.MessagesReportReactionRequest) (any, error) { + return r.onMessagesReportReaction(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReportMessagesDeliveryRequest](d, tlprofile.SemanticMethodMessagesReportMessagesDelivery, func(ctx context.Context, layerRequest *tg.MessagesReportMessagesDeliveryRequest) (any, error) { + return r.onMessagesReportMessagesDelivery(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReportReadMetricsRequest](d, tlprofile.SemanticMethodMessagesReportReadMetrics, func(ctx context.Context, layerRequest *tg.MessagesReportReadMetricsRequest) (any, error) { + return r.onMessagesReportReadMetrics(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReportMusicListenRequest](d, tlprofile.SemanticMethodMessagesReportMusicListen, func(ctx context.Context, layerRequest *tg.MessagesReportMusicListenRequest) (any, error) { + return r.onMessagesReportMusicListen(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReportSponsoredMessageRequest](d, tlprofile.SemanticMethodMessagesReportSponsoredMessage, func(ctx context.Context, layerRequest *tg.MessagesReportSponsoredMessageRequest) (any, error) { + return r.onMessagesReportSponsoredMessage(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReadMessageContentsRequest](d, tlprofile.SemanticMethodMessagesReadMessageContents, func(ctx context.Context, layerRequest *tg.MessagesReadMessageContentsRequest) (any, error) { + return r.onMessagesReadMessageContents(ctx, layerRequest. + ID) + }) + registerRPC[*tg.MessagesTranslateTextRequest](d, tlprofile.SemanticMethodMessagesTranslateText, func(ctx context.Context, layerRequest *tg.MessagesTranslateTextRequest) (any, error) { + return r.onMessagesTranslateText(ctx, layerRequest) + }) + registerRPC[*tg.MessagesTogglePeerTranslationsRequest](d, tlprofile.SemanticMethodMessagesTogglePeerTranslations, func(ctx context.Context, layerRequest *tg.MessagesTogglePeerTranslationsRequest) (any, error) { + return r.onMessagesTogglePeerTranslations(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetMessagesViewsRequest](d, tlprofile.SemanticMethodMessagesGetMessagesViews, func(ctx context.Context, layerRequest *tg.MessagesGetMessagesViewsRequest) (any, error) { + return r.onMessagesGetMessagesViews(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetUnreadMentionsRequest](d, tlprofile.SemanticMethodMessagesGetUnreadMentions, func(ctx context.Context, layerRequest *tg.MessagesGetUnreadMentionsRequest) (any, error) { + return r.onMessagesGetUnreadMentions(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReadMentionsRequest](d, tlprofile.SemanticMethodMessagesReadMentions, func(ctx context.Context, layerRequest *tg.MessagesReadMentionsRequest) (any, error) { + return r.onMessagesReadMentions(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetSearchCountersRequest](d, tlprofile.SemanticMethodMessagesGetSearchCounters, func(ctx context.Context, layerRequest *tg.MessagesGetSearchCountersRequest) (any, error) { + return r.onMessagesGetSearchCounters(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetRepliesRequest](d, tlprofile.SemanticMethodMessagesGetReplies, func(ctx context.Context, layerRequest *tg.MessagesGetRepliesRequest) (any, error) { + return r.onMessagesGetReplies(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetDiscussionMessageRequest](d, tlprofile.SemanticMethodMessagesGetDiscussionMessage, func(ctx context.Context, layerRequest *tg.MessagesGetDiscussionMessageRequest) (any, error) { + return r.onMessagesGetDiscussionMessage(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReadDiscussionRequest](d, tlprofile.SemanticMethodMessagesReadDiscussion, func(ctx context.Context, layerRequest *tg.MessagesReadDiscussionRequest) (any, error) { + return r.onMessagesReadDiscussion(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetForumTopicsRequest](d, tlprofile.SemanticMethodMessagesGetForumTopics, func(ctx context.Context, layerRequest *tg.MessagesGetForumTopicsRequest) (any, error) { + return r.onMessagesGetForumTopics(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetForumTopicsByIDRequest](d, tlprofile.SemanticMethodMessagesGetForumTopicsByID, func(ctx context.Context, layerRequest *tg.MessagesGetForumTopicsByIDRequest) (any, error) { + return r.onMessagesGetForumTopicsByID(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetOnlinesRequest](d, tlprofile.SemanticMethodMessagesGetOnlines, func(ctx context.Context, layerRequest *tg.MessagesGetOnlinesRequest) (any, error) { + return r.onMessagesGetOnlines(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.MessagesGetAvailableReactionsRequest](d, tlprofile.SemanticMethodMessagesGetAvailableReactions, func(ctx context.Context, layerRequest *tg.MessagesGetAvailableReactionsRequest) (any, error) { + return r.onMessagesGetAvailableReactions(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesGetAvailableEffectsRequest](d, tlprofile.SemanticMethodMessagesGetAvailableEffects, func(ctx context.Context, layerRequest *tg.MessagesGetAvailableEffectsRequest) (any, error) { + return r.onMessagesGetAvailableEffects(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesGetStickersRequest](d, tlprofile.SemanticMethodMessagesGetStickers, func(ctx context.Context, layerRequest *tg.MessagesGetStickersRequest) (any, error) { + return r.onMessagesGetStickers(ctx, layerRequest) + }) + registerRPC[*tg.MessagesInstallStickerSetRequest](d, tlprofile.SemanticMethodMessagesInstallStickerSet, func(ctx context.Context, layerRequest *tg.MessagesInstallStickerSetRequest) (any, error) { + return r.onMessagesInstallStickerSet(ctx, layerRequest) + }) + registerRPC[*tg.MessagesUninstallStickerSetRequest](d, tlprofile.SemanticMethodMessagesUninstallStickerSet, func(ctx context.Context, layerRequest *tg.MessagesUninstallStickerSetRequest) (any, error) { + return r.onMessagesUninstallStickerSet(ctx, layerRequest. + Stickerset) + }) + registerRPC[*tg.MessagesReorderStickerSetsRequest](d, tlprofile.SemanticMethodMessagesReorderStickerSets, func(ctx context.Context, layerRequest *tg.MessagesReorderStickerSetsRequest) (any, error) { + return r.onMessagesReorderStickerSets(ctx, layerRequest) + }) + registerRPC[*tg.MessagesToggleStickerSetsRequest](d, tlprofile.SemanticMethodMessagesToggleStickerSets, func(ctx context.Context, layerRequest *tg.MessagesToggleStickerSetsRequest) (any, error) { + return r.onMessagesToggleStickerSets(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetMyStickersRequest](d, tlprofile.SemanticMethodMessagesGetMyStickers, func(ctx context.Context, layerRequest *tg.MessagesGetMyStickersRequest) (any, error) { + return r.onMessagesGetMyStickers(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetArchivedStickersRequest](d, tlprofile.SemanticMethodMessagesGetArchivedStickers, func(ctx context.Context, req *tg.MessagesGetArchivedStickersRequest) (any, error) { return &tg.MessagesArchivedStickers{ Count: 0, Sets: []tg.StickerSetCoveredClass{}, }, nil }) - d.OnMessagesGetStickerSet(r.onMessagesGetStickerSet) - d.OnMessagesGetEmojiGroups(func(ctx context.Context, hash int) (tg.MessagesEmojiGroupsClass, error) { + registerRPC[*tg.MessagesGetStickerSetRequest](d, tlprofile.SemanticMethodMessagesGetStickerSet, func(ctx context.Context, layerRequest *tg.MessagesGetStickerSetRequest) (any, error) { + return r.onMessagesGetStickerSet(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetEmojiGroupsRequest](d, tlprofile.SemanticMethodMessagesGetEmojiGroups, func(ctx context.Context, layerRequest *tg.MessagesGetEmojiGroupsRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return tdesktop.EmojiGroups(hash), nil }) - d.OnMessagesGetEmojiStatusGroups(func(ctx context.Context, hash int) (tg.MessagesEmojiGroupsClass, error) { + registerRPC[*tg.MessagesGetEmojiStatusGroupsRequest](d, tlprofile.SemanticMethodMessagesGetEmojiStatusGroups, func(ctx context.Context, layerRequest *tg.MessagesGetEmojiStatusGroupsRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return tdesktop.EmojiStatusGroups(), nil }) - d.OnMessagesGetEmojiStickerGroups(r.onMessagesGetEmojiStickerGroups) - d.OnMessagesGetEmojiProfilePhotoGroups(func(ctx context.Context, hash int) (tg.MessagesEmojiGroupsClass, error) { + registerRPC[*tg.MessagesGetEmojiStickerGroupsRequest](d, tlprofile.SemanticMethodMessagesGetEmojiStickerGroups, func(ctx context.Context, layerRequest *tg.MessagesGetEmojiStickerGroupsRequest) (any, error) { + return r.onMessagesGetEmojiStickerGroups(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesGetEmojiProfilePhotoGroupsRequest](d, tlprofile.SemanticMethodMessagesGetEmojiProfilePhotoGroups, func(ctx context.Context, layerRequest *tg.MessagesGetEmojiProfilePhotoGroupsRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return tdesktop.EmojiProfilePhotoGroups(), nil }) - d.OnMessagesGetEmojiKeywords(r.onMessagesGetEmojiKeywords) - d.OnMessagesGetEmojiKeywordsDifference(r.onMessagesGetEmojiKeywordsDifference) - d.OnMessagesGetEmojiKeywordsLanguages(func(ctx context.Context, langcodes []string) ([]tg.EmojiLanguage, error) { + registerRPC[*tg.MessagesGetEmojiKeywordsRequest](d, tlprofile.SemanticMethodMessagesGetEmojiKeywords, func(ctx context.Context, layerRequest *tg.MessagesGetEmojiKeywordsRequest) (any, error) { + return r.onMessagesGetEmojiKeywords(ctx, layerRequest. + LangCode) + }) + registerRPC[*tg.MessagesGetEmojiKeywordsDifferenceRequest](d, tlprofile.SemanticMethodMessagesGetEmojiKeywordsDifference, func(ctx context.Context, layerRequest *tg.MessagesGetEmojiKeywordsDifferenceRequest) (any, error) { + return r.onMessagesGetEmojiKeywordsDifference(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetEmojiKeywordsLanguagesRequest](d, tlprofile.SemanticMethodMessagesGetEmojiKeywordsLanguages, func(ctx context.Context, layerRequest *tg.MessagesGetEmojiKeywordsLanguagesRequest) (any, error) { + langcodes := layerRequest. + LangCodes + _ = langcodes + return []tg.EmojiLanguage{}, nil }) - d.OnMessagesGetCustomEmojiDocuments(r.onMessagesGetCustomEmojiDocuments) - d.OnMessagesGetAttachedStickers(r.onMessagesGetAttachedStickers) - d.OnMessagesSearchStickerSets(r.onMessagesSearchStickerSets) - d.OnMessagesSearchStickers(r.onMessagesSearchStickers) - d.OnMessagesGetAttachMenuBots(r.onMessagesGetAttachMenuBots) - d.OnMessagesGetAttachMenuBot(r.onMessagesGetAttachMenuBot) - d.OnMessagesToggleBotInAttachMenu(r.onMessagesToggleBotInAttachMenu) - d.OnMessagesGetQuickReplies(r.onMessagesGetQuickReplies) - d.OnMessagesCheckQuickReplyShortcut(r.onMessagesCheckQuickReplyShortcut) - d.OnMessagesReorderQuickReplies(r.onMessagesReorderQuickReplies) - d.OnMessagesEditQuickReplyShortcut(r.onMessagesEditQuickReplyShortcut) - d.OnMessagesDeleteQuickReplyShortcut(r.onMessagesDeleteQuickReplyShortcut) - d.OnMessagesGetQuickReplyMessages(r.onMessagesGetQuickReplyMessages) - d.OnMessagesSendQuickReplyMessages(r.onMessagesSendQuickReplyMessages) - d.OnMessagesDeleteQuickReplyMessages(r.onMessagesDeleteQuickReplyMessages) - d.OnMessagesGetWebPage(r.onMessagesGetWebPage) - d.OnMessagesGetDialogs(func(ctx context.Context, req *tg.MessagesGetDialogsRequest) (tg.MessagesDialogsClass, error) { + registerRPC[*tg.MessagesGetCustomEmojiDocumentsRequest](d, tlprofile.SemanticMethodMessagesGetCustomEmojiDocuments, func(ctx context.Context, layerRequest *tg.MessagesGetCustomEmojiDocumentsRequest) (any, error) { + return r.onMessagesGetCustomEmojiDocuments(ctx, layerRequest. + DocumentID) + }) + registerRPC[*tg.MessagesGetAttachedStickersRequest](d, tlprofile.SemanticMethodMessagesGetAttachedStickers, func(ctx context.Context, layerRequest *tg.MessagesGetAttachedStickersRequest) (any, error) { + return r.onMessagesGetAttachedStickers(ctx, layerRequest. + Media) + }) + registerRPC[*tg.MessagesSearchStickerSetsRequest](d, tlprofile.SemanticMethodMessagesSearchStickerSets, func(ctx context.Context, layerRequest *tg.MessagesSearchStickerSetsRequest) (any, error) { + return r.onMessagesSearchStickerSets(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSearchStickersRequest](d, tlprofile.SemanticMethodMessagesSearchStickers, func(ctx context.Context, layerRequest *tg.MessagesSearchStickersRequest) (any, error) { + return r.onMessagesSearchStickers(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetAttachMenuBotsRequest](d, tlprofile.SemanticMethodMessagesGetAttachMenuBots, func(ctx context.Context, layerRequest *tg.MessagesGetAttachMenuBotsRequest) (any, error) { + return r.onMessagesGetAttachMenuBots(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesGetAttachMenuBotRequest](d, tlprofile.SemanticMethodMessagesGetAttachMenuBot, func(ctx context.Context, layerRequest *tg.MessagesGetAttachMenuBotRequest) (any, error) { + return r.onMessagesGetAttachMenuBot(ctx, layerRequest. + Bot) + }) + registerRPC[*tg.MessagesToggleBotInAttachMenuRequest](d, tlprofile.SemanticMethodMessagesToggleBotInAttachMenu, func(ctx context.Context, layerRequest *tg.MessagesToggleBotInAttachMenuRequest) (any, error) { + return r.onMessagesToggleBotInAttachMenu(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetQuickRepliesRequest](d, tlprofile.SemanticMethodMessagesGetQuickReplies, func(ctx context.Context, layerRequest *tg.MessagesGetQuickRepliesRequest) (any, error) { + return r.onMessagesGetQuickReplies(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesCheckQuickReplyShortcutRequest](d, tlprofile.SemanticMethodMessagesCheckQuickReplyShortcut, func(ctx context.Context, layerRequest *tg.MessagesCheckQuickReplyShortcutRequest) (any, error) { + return r.onMessagesCheckQuickReplyShortcut(ctx, layerRequest. + Shortcut) + }) + registerRPC[*tg.MessagesReorderQuickRepliesRequest](d, tlprofile.SemanticMethodMessagesReorderQuickReplies, func(ctx context.Context, layerRequest *tg.MessagesReorderQuickRepliesRequest) (any, error) { + return r.onMessagesReorderQuickReplies(ctx, layerRequest. + Order) + }) + registerRPC[*tg.MessagesEditQuickReplyShortcutRequest](d, tlprofile.SemanticMethodMessagesEditQuickReplyShortcut, func(ctx context.Context, layerRequest *tg.MessagesEditQuickReplyShortcutRequest) (any, error) { + return r.onMessagesEditQuickReplyShortcut(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteQuickReplyShortcutRequest](d, tlprofile.SemanticMethodMessagesDeleteQuickReplyShortcut, func(ctx context.Context, layerRequest *tg.MessagesDeleteQuickReplyShortcutRequest) (any, error) { + return r.onMessagesDeleteQuickReplyShortcut(ctx, layerRequest. + ShortcutID) + }) + registerRPC[*tg.MessagesGetQuickReplyMessagesRequest](d, tlprofile.SemanticMethodMessagesGetQuickReplyMessages, func(ctx context.Context, layerRequest *tg.MessagesGetQuickReplyMessagesRequest) (any, error) { + return r.onMessagesGetQuickReplyMessages(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendQuickReplyMessagesRequest](d, tlprofile.SemanticMethodMessagesSendQuickReplyMessages, func(ctx context.Context, layerRequest *tg.MessagesSendQuickReplyMessagesRequest) (any, error) { + return r.onMessagesSendQuickReplyMessages(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteQuickReplyMessagesRequest](d, tlprofile.SemanticMethodMessagesDeleteQuickReplyMessages, func(ctx context.Context, layerRequest *tg.MessagesDeleteQuickReplyMessagesRequest) (any, error) { + return r.onMessagesDeleteQuickReplyMessages(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetWebPageRequest](d, tlprofile.SemanticMethodMessagesGetWebPage, func(ctx context.Context, layerRequest *tg.MessagesGetWebPageRequest) (any, error) { + return r.onMessagesGetWebPage(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetDialogsRequest](d, tlprofile.SemanticMethodMessagesGetDialogs, func(ctx context.Context, req *tg.MessagesGetDialogsRequest) (any, error) { if r.deps.Dialogs == nil { return &tg.MessagesDialogs{}, nil } @@ -175,7 +427,11 @@ func (r *Router) registerMessages(d *tg.ServerDispatcher) { } return r.tgMessagesDialogs(ctx, userID, r.withDialogListPresence(ctx, userID, list)), nil }) - d.OnMessagesGetPinnedDialogs(func(ctx context.Context, folderID int) (*tg.MessagesPeerDialogs, error) { + registerRPC[*tg.MessagesGetPinnedDialogsRequest](d, tlprofile.SemanticMethodMessagesGetPinnedDialogs, func(ctx context.Context, layerRequest *tg.MessagesGetPinnedDialogsRequest) (any, error) { + folderID := layerRequest. + FolderID + _ = folderID + id, _ := AuthKeyIDFrom(ctx) userID, _, err := r.currentUserID(ctx) if err != nil { @@ -195,7 +451,11 @@ func (r *Router) registerMessages(d *tg.ServerDispatcher) { } return r.tgPeerDialogs(ctx, userID, r.withDialogListPresence(ctx, userID, list), st), nil }) - d.OnMessagesGetPeerDialogs(func(ctx context.Context, peers []tg.InputDialogPeerClass) (*tg.MessagesPeerDialogs, error) { + registerRPC[*tg.MessagesGetPeerDialogsRequest](d, tlprofile.SemanticMethodMessagesGetPeerDialogs, func(ctx context.Context, layerRequest *tg.MessagesGetPeerDialogsRequest) (any, error) { + peers := layerRequest. + Peers + _ = peers + id, _ := AuthKeyIDFrom(ctx) userID, _, err := r.currentUserID(ctx) if err != nil { @@ -240,21 +500,52 @@ func (r *Router) registerMessages(d *tg.ServerDispatcher) { r.trackChannelInterest(ctx, userID, channelIDsFromDialogs(list)...) return r.tgPeerDialogs(ctx, userID, r.withDialogListPresence(ctx, userID, list), st), nil }) - d.OnMessagesGetPeerSettings(r.onMessagesGetPeerSettings) - d.OnMessagesToggleDialogPin(r.onMessagesToggleDialogPin) - d.OnMessagesReorderPinnedDialogs(r.onMessagesReorderPinnedDialogs) - d.OnMessagesMarkDialogUnread(r.onMessagesMarkDialogUnread) - d.OnMessagesGetDialogUnreadMarks(r.onMessagesGetDialogUnreadMarks) - d.OnMessagesHidePeerSettingsBar(r.onMessagesHidePeerSettingsBar) - d.OnMessagesGetMessageEditData(r.onMessagesGetMessageEditData) - d.OnMessagesEditMessage(r.onMessagesEditMessage) - d.OnMessagesGetOutboxReadDate(r.onMessagesGetOutboxReadDate) - d.OnMessagesGetMessageReadParticipants(r.onMessagesGetMessageReadParticipants) - d.OnMessagesDeleteMessages(r.onMessagesDeleteMessages) - d.OnMessagesDeleteHistory(r.onMessagesDeleteHistory) - d.OnMessagesGetMessages(r.onMessagesGetMessages) - d.OnMessagesGetRichMessage(r.onMessagesGetRichMessage) - d.OnMessagesGetHistory(func(ctx context.Context, req *tg.MessagesGetHistoryRequest) (tg.MessagesMessagesClass, error) { + registerRPC[*tg.MessagesGetPeerSettingsRequest](d, tlprofile.SemanticMethodMessagesGetPeerSettings, func(ctx context.Context, layerRequest *tg.MessagesGetPeerSettingsRequest) (any, error) { + return r.onMessagesGetPeerSettings(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.MessagesToggleDialogPinRequest](d, tlprofile.SemanticMethodMessagesToggleDialogPin, func(ctx context.Context, layerRequest *tg.MessagesToggleDialogPinRequest) (any, error) { + return r.onMessagesToggleDialogPin(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReorderPinnedDialogsRequest](d, tlprofile.SemanticMethodMessagesReorderPinnedDialogs, func(ctx context.Context, layerRequest *tg.MessagesReorderPinnedDialogsRequest) (any, error) { + return r.onMessagesReorderPinnedDialogs(ctx, layerRequest) + }) + registerRPC[*tg.MessagesMarkDialogUnreadRequest](d, tlprofile.SemanticMethodMessagesMarkDialogUnread, func(ctx context.Context, layerRequest *tg.MessagesMarkDialogUnreadRequest) (any, error) { + return r.onMessagesMarkDialogUnread(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetDialogUnreadMarksRequest](d, tlprofile.SemanticMethodMessagesGetDialogUnreadMarks, func(ctx context.Context, layerRequest *tg.MessagesGetDialogUnreadMarksRequest) (any, error) { + return r.onMessagesGetDialogUnreadMarks(ctx, layerRequest) + }) + registerRPC[*tg.MessagesHidePeerSettingsBarRequest](d, tlprofile.SemanticMethodMessagesHidePeerSettingsBar, func(ctx context.Context, layerRequest *tg.MessagesHidePeerSettingsBarRequest) (any, error) { + return r.onMessagesHidePeerSettingsBar(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.MessagesGetMessageEditDataRequest](d, tlprofile.SemanticMethodMessagesGetMessageEditData, func(ctx context.Context, layerRequest *tg.MessagesGetMessageEditDataRequest) (any, error) { + return r.onMessagesGetMessageEditData(ctx, layerRequest) + }) + registerRPC[*tg.MessagesEditMessageRequest](d, tlprofile.SemanticMethodMessagesEditMessage, func(ctx context.Context, layerRequest *tg.MessagesEditMessageRequest) (any, error) { + return r.onMessagesEditMessage(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetOutboxReadDateRequest](d, tlprofile.SemanticMethodMessagesGetOutboxReadDate, func(ctx context.Context, layerRequest *tg.MessagesGetOutboxReadDateRequest) (any, error) { + return r.onMessagesGetOutboxReadDate(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetMessageReadParticipantsRequest](d, tlprofile.SemanticMethodMessagesGetMessageReadParticipants, func(ctx context.Context, layerRequest *tg.MessagesGetMessageReadParticipantsRequest) (any, error) { + return r.onMessagesGetMessageReadParticipants(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteMessagesRequest](d, tlprofile.SemanticMethodMessagesDeleteMessages, func(ctx context.Context, layerRequest *tg.MessagesDeleteMessagesRequest) (any, error) { + return r.onMessagesDeleteMessages(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteHistoryRequest](d, tlprofile.SemanticMethodMessagesDeleteHistory, func(ctx context.Context, layerRequest *tg.MessagesDeleteHistoryRequest) (any, error) { + return r.onMessagesDeleteHistory(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetMessagesRequest](d, tlprofile.SemanticMethodMessagesGetMessages, func(ctx context.Context, layerRequest *tg.MessagesGetMessagesRequest) (any, error) { + return r.onMessagesGetMessages(ctx, layerRequest. + ID) + }) + registerRPC[*tg.MessagesGetRichMessageRequest](d, tlprofile.SemanticMethodMessagesGetRichMessage, func(ctx context.Context, layerRequest *tg.MessagesGetRichMessageRequest) (any, error) { + return r.onMessagesGetRichMessage(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetHistoryRequest](d, tlprofile.SemanticMethodMessagesGetHistory, func(ctx context.Context, req *tg.MessagesGetHistoryRequest) (any, error) { userID, _, err := r.currentUserID(ctx) if err != nil { return nil, internalErr() @@ -309,8 +600,10 @@ func (r *Router) registerMessages(d *tg.ServerDispatcher) { } return r.tgMessagesMessages(ctx, userID, r.enrichMessageList(ctx, userID, list)), nil }) - d.OnMessagesGetRecentLocations(r.onMessagesGetRecentLocations) - d.OnMessagesReadHistory(func(ctx context.Context, req *tg.MessagesReadHistoryRequest) (*tg.MessagesAffectedMessages, error) { + registerRPC[*tg.MessagesGetRecentLocationsRequest](d, tlprofile.SemanticMethodMessagesGetRecentLocations, func(ctx context.Context, layerRequest *tg.MessagesGetRecentLocationsRequest) (any, error) { + return r.onMessagesGetRecentLocations(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReadHistoryRequest](d, tlprofile.SemanticMethodMessagesReadHistory, func(ctx context.Context, req *tg.MessagesReadHistoryRequest) (any, error) { id, _ := AuthKeyIDFrom(ctx) userID, _, err := r.currentUserID(ctx) if err != nil { @@ -365,7 +658,7 @@ func (r *Router) registerMessages(d *tg.ServerDispatcher) { } return r.affectedMessages(ctx, id, userID) }) - d.OnMessagesSearch(func(ctx context.Context, req *tg.MessagesSearchRequest) (tg.MessagesMessagesClass, error) { + registerRPC[*tg.MessagesSearchRequest](d, tlprofile.SemanticMethodMessagesSearch, func(ctx context.Context, req *tg.MessagesSearchRequest) (any, error) { if utf8.RuneCountInString(req.Q) > maxMessageSearchQLength { return nil, limitInvalidErr() } @@ -536,51 +829,132 @@ func (r *Router) registerMessages(d *tg.ServerDispatcher) { } return r.tgMessagesMessages(ctx, userID, r.enrichMessageList(ctx, userID, list)), nil }) - d.OnMessagesSearchGlobal(r.onMessagesSearchGlobal) - d.OnMessagesGetSearchResultsCalendar(r.onMessagesGetSearchResultsCalendar) - d.OnMessagesGetSearchResultsPositions(r.onMessagesGetSearchResultsPositions) - d.OnMessagesSendReaction(r.onMessagesSendReaction) - d.OnMessagesComposeMessageWithAI(r.onMessagesComposeMessageWithAI) - // 语音转文字无识别后端:注册为显式失败(TRANSCRIPTION_FAILED),premium - // 客户端点击转录按钮得到优雅失败提示,而不是 NOT_IMPLEMENTED trace。 - d.OnMessagesTranscribeAudio(func(ctx context.Context, req *tg.MessagesTranscribeAudioRequest) (*tg.MessagesTranscribedAudio, error) { + registerRPC[*tg.MessagesSearchGlobalRequest](d, tlprofile.SemanticMethodMessagesSearchGlobal, func(ctx context.Context, layerRequest *tg.MessagesSearchGlobalRequest) (any, error) { + return r.onMessagesSearchGlobal(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetSearchResultsCalendarRequest](d, tlprofile.SemanticMethodMessagesGetSearchResultsCalendar, func(ctx context.Context, layerRequest *tg.MessagesGetSearchResultsCalendarRequest) (any, error) { + return r.onMessagesGetSearchResultsCalendar(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetSearchResultsPositionsRequest](d, tlprofile.SemanticMethodMessagesGetSearchResultsPositions, func(ctx context.Context, layerRequest *tg.MessagesGetSearchResultsPositionsRequest) (any, error) { + return r.onMessagesGetSearchResultsPositions(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendReactionRequest](d, tlprofile.SemanticMethodMessagesSendReaction, func(ctx context.Context, layerRequest *tg.MessagesSendReactionRequest) (any, error) { + + // 语音转文字无识别后端:注册为显式失败(TRANSCRIPTION_FAILED),premium + // 客户端点击转录按钮得到优雅失败提示,而不是 NOT_IMPLEMENTED trace。 + return r.onMessagesSendReaction(ctx, layerRequest) + }) + registerRPC[*tg.MessagesComposeMessageWithAIRequest](d, tlprofile.SemanticMethodMessagesComposeMessageWithAI, func(ctx context.Context, layerRequest *tg.MessagesComposeMessageWithAIRequest) (any, error) { + return r.onMessagesComposeMessageWithAI(ctx, layerRequest) + }) + registerRPC[*tg.MessagesTranscribeAudioRequest](d, tlprofile.SemanticMethodMessagesTranscribeAudio, func(ctx context.Context, req *tg.MessagesTranscribeAudioRequest) (any, error) { if _, _, err := r.currentUserID(ctx); err != nil { return nil, internalErr() } return nil, tgerr400("TRANSCRIPTION_FAILED") }) - d.OnMessagesGetMessagesReactions(r.onMessagesGetMessagesReactions) - d.OnMessagesGetMessageReactionsList(r.onMessagesGetMessageReactionsList) - d.OnMessagesSetDefaultReaction(r.onMessagesSetDefaultReaction) - d.OnMessagesGetPaidReactionPrivacy(r.onMessagesGetPaidReactionPrivacy) - d.OnMessagesTogglePaidReactionPrivacy(r.onMessagesTogglePaidReactionPrivacy) - d.OnMessagesSendPaidReaction(r.onMessagesSendPaidReaction) - d.OnMessagesDeleteParticipantReactions(r.onMessagesDeleteParticipantReactions) - d.OnMessagesDeleteParticipantReaction(r.onMessagesDeleteParticipantReaction) - d.OnMessagesGetUnreadReactions(r.onMessagesGetUnreadReactions) - d.OnMessagesReadReactions(r.onMessagesReadReactions) - d.OnMessagesGetTopReactions(r.onMessagesGetTopReactions) - d.OnMessagesGetRecentReactions(r.onMessagesGetRecentReactions) - d.OnMessagesClearRecentReactions(r.onMessagesClearRecentReactions) - d.OnMessagesGetSavedReactionTags(r.onMessagesGetSavedReactionTags) - d.OnMessagesUpdateSavedReactionTag(r.onMessagesUpdateSavedReactionTag) - d.OnMessagesGetDefaultTagReactions(r.onMessagesGetDefaultTagReactions) - d.OnMessagesSendVote(r.onMessagesSendVote) - d.OnMessagesGetPollResults(r.onMessagesGetPollResults) - d.OnMessagesGetPollVotes(r.onMessagesGetPollVotes) - d.OnMessagesAddPollAnswer(r.onMessagesAddPollAnswer) - d.OnMessagesDeletePollAnswer(r.onMessagesDeletePollAnswer) - d.OnMessagesGetUnreadPollVotes(r.onMessagesGetUnreadPollVotes) - d.OnMessagesReadPollVotes(r.onMessagesReadPollVotes) - d.OnMessagesAppendTodoList(r.onMessagesAppendTodoList) - d.OnMessagesToggleTodoCompleted(r.onMessagesToggleTodoCompleted) - d.OnMessagesGetScheduledHistory(r.onMessagesGetScheduledHistory) - d.OnMessagesGetScheduledMessages(r.onMessagesGetScheduledMessages) - d.OnMessagesSendScheduledMessages(r.onMessagesSendScheduledMessages) - d.OnMessagesDeleteScheduledMessages(r.onMessagesDeleteScheduledMessages) - d.OnMessagesCreateForumTopic(r.onMessagesCreateForumTopic) - d.OnMessagesEditForumTopic(r.onMessagesEditForumTopic) - d.OnMessagesUpdatePinnedForumTopic(r.onMessagesUpdatePinnedForumTopic) - d.OnMessagesReorderPinnedForumTopics(r.onMessagesReorderPinnedForumTopics) - d.OnMessagesDeleteTopicHistory(r.onMessagesDeleteTopicHistory) + registerRPC[*tg.MessagesGetMessagesReactionsRequest](d, tlprofile.SemanticMethodMessagesGetMessagesReactions, func(ctx context.Context, layerRequest *tg.MessagesGetMessagesReactionsRequest) (any, error) { + return r.onMessagesGetMessagesReactions(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetMessageReactionsListRequest](d, tlprofile.SemanticMethodMessagesGetMessageReactionsList, func(ctx context.Context, layerRequest *tg.MessagesGetMessageReactionsListRequest) (any, error) { + return r.onMessagesGetMessageReactionsList(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSetDefaultReactionRequest](d, tlprofile.SemanticMethodMessagesSetDefaultReaction, func(ctx context.Context, layerRequest *tg.MessagesSetDefaultReactionRequest) (any, error) { + return r.onMessagesSetDefaultReaction(ctx, layerRequest. + Reaction) + }) + registerRPC[*tg.MessagesGetPaidReactionPrivacyRequest](d, tlprofile.SemanticMethodMessagesGetPaidReactionPrivacy, func(ctx context.Context, layerRequest *tg.MessagesGetPaidReactionPrivacyRequest) (any, error) { + return r.onMessagesGetPaidReactionPrivacy(ctx) + }) + registerRPC[*tg.MessagesTogglePaidReactionPrivacyRequest](d, tlprofile.SemanticMethodMessagesTogglePaidReactionPrivacy, func(ctx context.Context, layerRequest *tg.MessagesTogglePaidReactionPrivacyRequest) (any, error) { + return r.onMessagesTogglePaidReactionPrivacy(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendPaidReactionRequest](d, tlprofile.SemanticMethodMessagesSendPaidReaction, func(ctx context.Context, layerRequest *tg.MessagesSendPaidReactionRequest) (any, error) { + return r.onMessagesSendPaidReaction(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteParticipantReactionsRequest](d, tlprofile.SemanticMethodMessagesDeleteParticipantReactions, func(ctx context.Context, layerRequest *tg.MessagesDeleteParticipantReactionsRequest) (any, error) { + return r.onMessagesDeleteParticipantReactions(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteParticipantReactionRequest](d, tlprofile.SemanticMethodMessagesDeleteParticipantReaction, func(ctx context.Context, layerRequest *tg.MessagesDeleteParticipantReactionRequest) (any, error) { + return r.onMessagesDeleteParticipantReaction(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetUnreadReactionsRequest](d, tlprofile.SemanticMethodMessagesGetUnreadReactions, func(ctx context.Context, layerRequest *tg.MessagesGetUnreadReactionsRequest) (any, error) { + return r.onMessagesGetUnreadReactions(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReadReactionsRequest](d, tlprofile.SemanticMethodMessagesReadReactions, func(ctx context.Context, layerRequest *tg.MessagesReadReactionsRequest) (any, error) { + return r.onMessagesReadReactions(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetTopReactionsRequest](d, tlprofile.SemanticMethodMessagesGetTopReactions, func(ctx context.Context, layerRequest *tg.MessagesGetTopReactionsRequest) (any, error) { + return r.onMessagesGetTopReactions(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetRecentReactionsRequest](d, tlprofile.SemanticMethodMessagesGetRecentReactions, func(ctx context.Context, layerRequest *tg.MessagesGetRecentReactionsRequest) (any, error) { + return r.onMessagesGetRecentReactions(ctx, layerRequest) + }) + registerRPC[*tg.MessagesClearRecentReactionsRequest](d, tlprofile.SemanticMethodMessagesClearRecentReactions, func(ctx context.Context, layerRequest *tg.MessagesClearRecentReactionsRequest) (any, error) { + return r.onMessagesClearRecentReactions(ctx) + }) + registerRPC[*tg.MessagesGetSavedReactionTagsRequest](d, tlprofile.SemanticMethodMessagesGetSavedReactionTags, func(ctx context.Context, layerRequest *tg.MessagesGetSavedReactionTagsRequest) (any, error) { + return r.onMessagesGetSavedReactionTags(ctx, layerRequest) + }) + registerRPC[*tg.MessagesUpdateSavedReactionTagRequest](d, tlprofile.SemanticMethodMessagesUpdateSavedReactionTag, func(ctx context.Context, layerRequest *tg.MessagesUpdateSavedReactionTagRequest) (any, error) { + return r.onMessagesUpdateSavedReactionTag(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetDefaultTagReactionsRequest](d, tlprofile.SemanticMethodMessagesGetDefaultTagReactions, func(ctx context.Context, layerRequest *tg.MessagesGetDefaultTagReactionsRequest) (any, error) { + return r.onMessagesGetDefaultTagReactions(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.MessagesSendVoteRequest](d, tlprofile.SemanticMethodMessagesSendVote, func(ctx context.Context, layerRequest *tg.MessagesSendVoteRequest) (any, error) { + return r.onMessagesSendVote(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetPollResultsRequest](d, tlprofile.SemanticMethodMessagesGetPollResults, func(ctx context.Context, layerRequest *tg.MessagesGetPollResultsRequest) (any, error) { + return r.onMessagesGetPollResults(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetPollVotesRequest](d, tlprofile.SemanticMethodMessagesGetPollVotes, func(ctx context.Context, layerRequest *tg.MessagesGetPollVotesRequest) (any, error) { + return r.onMessagesGetPollVotes(ctx, layerRequest) + }) + registerRPC[*tg.MessagesAddPollAnswerRequest](d, tlprofile.SemanticMethodMessagesAddPollAnswer, func(ctx context.Context, layerRequest *tg.MessagesAddPollAnswerRequest) (any, error) { + return r.onMessagesAddPollAnswer(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeletePollAnswerRequest](d, tlprofile.SemanticMethodMessagesDeletePollAnswer, func(ctx context.Context, layerRequest *tg.MessagesDeletePollAnswerRequest) (any, error) { + return r.onMessagesDeletePollAnswer(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetUnreadPollVotesRequest](d, tlprofile.SemanticMethodMessagesGetUnreadPollVotes, func(ctx context.Context, layerRequest *tg.MessagesGetUnreadPollVotesRequest) (any, error) { + return r.onMessagesGetUnreadPollVotes(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReadPollVotesRequest](d, tlprofile.SemanticMethodMessagesReadPollVotes, func(ctx context.Context, layerRequest *tg.MessagesReadPollVotesRequest) (any, error) { + return r.onMessagesReadPollVotes(ctx, layerRequest) + }) + registerRPC[*tg.MessagesAppendTodoListRequest](d, tlprofile.SemanticMethodMessagesAppendTodoList, func(ctx context.Context, layerRequest *tg.MessagesAppendTodoListRequest) (any, error) { + return r.onMessagesAppendTodoList(ctx, layerRequest) + }) + registerRPC[*tg.MessagesToggleTodoCompletedRequest](d, tlprofile.SemanticMethodMessagesToggleTodoCompleted, func(ctx context.Context, layerRequest *tg.MessagesToggleTodoCompletedRequest) (any, error) { + return r.onMessagesToggleTodoCompleted(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetScheduledHistoryRequest](d, tlprofile.SemanticMethodMessagesGetScheduledHistory, func(ctx context.Context, layerRequest *tg.MessagesGetScheduledHistoryRequest) (any, error) { + return r.onMessagesGetScheduledHistory(ctx, layerRequest) + }) + registerRPC[*tg.MessagesGetScheduledMessagesRequest](d, tlprofile.SemanticMethodMessagesGetScheduledMessages, func(ctx context.Context, layerRequest *tg.MessagesGetScheduledMessagesRequest) (any, error) { + return r.onMessagesGetScheduledMessages(ctx, layerRequest) + }) + registerRPC[*tg.MessagesSendScheduledMessagesRequest](d, tlprofile.SemanticMethodMessagesSendScheduledMessages, func(ctx context.Context, layerRequest *tg.MessagesSendScheduledMessagesRequest) (any, error) { + return r.onMessagesSendScheduledMessages(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteScheduledMessagesRequest](d, tlprofile.SemanticMethodMessagesDeleteScheduledMessages, func(ctx context.Context, layerRequest *tg.MessagesDeleteScheduledMessagesRequest) (any, error) { + return r.onMessagesDeleteScheduledMessages(ctx, layerRequest) + }) + registerRPC[*tg.MessagesCreateForumTopicRequest](d, tlprofile.SemanticMethodMessagesCreateForumTopic, func(ctx context.Context, layerRequest *tg.MessagesCreateForumTopicRequest) (any, error) { + return r.onMessagesCreateForumTopic(ctx, layerRequest) + }) + registerRPC[*tg.MessagesEditForumTopicRequest](d, tlprofile.SemanticMethodMessagesEditForumTopic, func(ctx context.Context, layerRequest *tg.MessagesEditForumTopicRequest) (any, error) { + return r.onMessagesEditForumTopic(ctx, layerRequest) + }) + registerRPC[*tg.MessagesUpdatePinnedForumTopicRequest](d, tlprofile.SemanticMethodMessagesUpdatePinnedForumTopic, func(ctx context.Context, layerRequest *tg.MessagesUpdatePinnedForumTopicRequest) (any, error) { + return r.onMessagesUpdatePinnedForumTopic(ctx, layerRequest) + }) + registerRPC[*tg.MessagesReorderPinnedForumTopicsRequest](d, tlprofile.SemanticMethodMessagesReorderPinnedForumTopics, func(ctx context.Context, layerRequest *tg.MessagesReorderPinnedForumTopicsRequest) (any, error) { + return r.onMessagesReorderPinnedForumTopics(ctx, layerRequest) + }) + registerRPC[*tg.MessagesDeleteTopicHistoryRequest](d, tlprofile.SemanticMethodMessagesDeleteTopicHistory, func(ctx context.Context, layerRequest *tg.MessagesDeleteTopicHistoryRequest) (any, error) { + return r.onMessagesDeleteTopicHistory(ctx, layerRequest) + }) } diff --git a/internal/rpc/messages_saved_dialogs_rpc_test.go b/internal/rpc/messages_saved_dialogs_rpc_test.go index d85ea3db..6b549d30 100644 --- a/internal/rpc/messages_saved_dialogs_rpc_test.go +++ b/internal/rpc/messages_saved_dialogs_rpc_test.go @@ -600,17 +600,9 @@ func TestModernForwardMessagesConstructorSavesToSelf(t *testing.T) { if err != nil { t.Fatalf("dispatch messages.forwardMessages#41d41ade: %v", err) } - // 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) { - case tg.UpdatesClass: - case *tg.UpdatesBox: - if v.Updates == nil { - t.Fatalf("forward result box has nil Updates") - } - default: - t.Fatalf("forward result = %T, want UpdatesClass or *tg.UpdatesBox", enc) + // The sparse dispatcher exposes the canonical concrete class result. + if _, ok := enc.(tg.UpdatesClass); !ok { + t.Fatalf("forward result = %T, want tg.UpdatesClass", enc) } res, err := r.onMessagesGetSavedDialogs(WithUserID(ctx, alice.ID), &tg.MessagesGetSavedDialogsRequest{Limit: 20}) diff --git a/internal/rpc/messages_send_rpc_test.go b/internal/rpc/messages_send_rpc_test.go index 680cebb0..6876ada0 100644 --- a/internal/rpc/messages_send_rpc_test.go +++ b/internal/rpc/messages_send_rpc_test.go @@ -41,13 +41,9 @@ func TestMessagesSendMessageReturnsUpdateAndRecordsOwnerContext(t *testing.T) { if err != nil { t.Fatalf("dispatch: %v", err) } - box, ok := enc.(*tg.UpdatesBox) + got, ok := enc.(*tg.Updates) if !ok { - t.Fatalf("response = %T, want *tg.UpdatesBox", enc) - } - got, ok := box.Updates.(*tg.Updates) - if !ok { - t.Fatalf("boxed response = %T, want *tg.Updates", box.Updates) + t.Fatalf("response = %T, want *tg.Updates", enc) } if messages.sendUserID != sender.ID || messages.sendReq.SenderUserID != sender.ID || messages.sendReq.RecipientUserID != recipient.ID || messages.sendReq.OriginSessionID != 77 { t.Fatalf("send context = user %d req %+v, want sender/recipient/session", messages.sendUserID, messages.sendReq) @@ -176,11 +172,10 @@ func TestMessagesSendMessageSupportsReplyAndFlags(t *testing.T) { if !messages.sendReq.Silent || !messages.sendReq.NoForwards { t.Fatalf("send flags silent=%v noforwards=%v, want true/true", messages.sendReq.Silent, messages.sendReq.NoForwards) } - box, ok := enc.(*tg.UpdatesBox) + got, ok := enc.(*tg.Updates) if !ok { - t.Fatalf("response = %T, want *tg.UpdatesBox", enc) + t.Fatalf("response = %T, want *tg.Updates", enc) } - got := box.Updates.(*tg.Updates) newMsg := got.Updates[1].(*tg.UpdateNewMessage) msg := newMsg.Message.(*tg.Message) if !msg.Silent || !msg.Noforwards { diff --git a/internal/rpc/messages_upload_media_android_compat_test.go b/internal/rpc/messages_upload_media_android_compat_test.go index 8662cb21..ed2df9f3 100644 --- a/internal/rpc/messages_upload_media_android_compat_test.go +++ b/internal/rpc/messages_upload_media_android_compat_test.go @@ -44,15 +44,10 @@ func TestLegacyAndroidMessagesUploadMediaDispatch(t *testing.T) { if err != nil { t.Fatalf("dispatch legacy uploadMedia: %v", err) } - // Routed through the generated static client overlay + the normal - // gotd dispatcher, which boxes a class result (MessageMedia) as *...Box. - box, ok := enc.(*tg.MessageMediaBox) + // Routed through the generated static client overlay and sparse dispatcher. + media, ok := enc.(*tg.MessageMediaPhoto) if !ok { - t.Fatalf("response = %T, want *tg.MessageMediaBox", enc) - } - media, ok := box.MessageMedia.(*tg.MessageMediaPhoto) - if !ok { - t.Fatalf("media = %T, want messageMediaPhoto", box.MessageMedia) + t.Fatalf("response = %T, want *tg.MessageMediaPhoto", enc) } photo, ok := media.Photo.(*tg.Photo) if !ok || photo.ID != 777 { diff --git a/internal/rpc/passive_compat_test.go b/internal/rpc/passive_compat_test.go index 66e7a12b..d75a7f17 100644 --- a/internal/rpc/passive_compat_test.go +++ b/internal/rpc/passive_compat_test.go @@ -23,13 +23,9 @@ func TestAccountGetChatThemesReturnsStaticThemes(t *testing.T) { if err != nil { t.Fatalf("dispatch: %v", err) } - box, ok := got.(*tg.AccountThemesBox) + themes, ok := got.(*tg.AccountThemes) if !ok { - t.Fatalf("response type = %T, want *tg.AccountThemesBox", got) - } - themes, ok := box.Themes.(*tg.AccountThemes) - if !ok { - t.Fatalf("boxed response type = %T, want *tg.AccountThemes", box.Themes) + t.Fatalf("response type = %T, want *tg.AccountThemes", got) } if themes.Hash == 0 || len(themes.Themes) == 0 { t.Fatalf("themes = %+v, want non-empty stable list", themes) @@ -48,20 +44,16 @@ func TestAccountGetUniqueGiftChatThemesReturnsEmptyStub(t *testing.T) { if err != nil { t.Fatalf("dispatch: %v", err) } - box, ok := got.(*tg.AccountChatThemesBox) + themes, ok := got.(*tg.AccountChatThemes) if !ok { - t.Fatalf("response type = %T, want *tg.AccountChatThemesBox", got) - } - themes, ok := box.ChatThemes.(*tg.AccountChatThemes) - if !ok { - t.Fatalf("boxed response type = %T, want *tg.AccountChatThemes", box.ChatThemes) + t.Fatalf("response type = %T, want *tg.AccountChatThemes", got) } if themes.Hash == 0 || len(themes.Themes) != 0 || len(themes.Chats) != 0 || len(themes.Users) != 0 { t.Fatalf("unique gift themes = %+v, want stable empty catalog", themes) } } -func TestAccountGetWallPapersReturnsDefaultCatalog(t *testing.T) { +func TestAccountGetWallPapersReturnsOrangeCatalog(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 @@ -73,13 +65,9 @@ func TestAccountGetWallPapersReturnsDefaultCatalog(t *testing.T) { if err != nil { t.Fatalf("dispatch: %v", err) } - box, ok := got.(*tg.AccountWallPapersBox) + wallpapers, ok := got.(*tg.AccountWallPapers) if !ok { - t.Fatalf("response type = %T, want *tg.AccountWallPapersBox", got) - } - wallpapers, ok := box.WallPapers.(*tg.AccountWallPapers) - if !ok { - t.Fatalf("boxed response type = %T, want *tg.AccountWallPapers", box.WallPapers) + t.Fatalf("response type = %T, want *tg.AccountWallPapers", got) } if wallpapers.Hash == 0 || len(wallpapers.Wallpapers) == 0 { t.Fatalf("wallpapers = %+v, want stable default catalog", wallpapers) @@ -98,7 +86,7 @@ func TestAccountWallpaperSeedLookupAndAckRPCs(t *testing.T) { if err != nil { t.Fatalf("dispatch list: %v", err) } - list := listGot.(*tg.AccountWallPapersBox).WallPapers.(*tg.AccountWallPapers) + list := listGot.(*tg.AccountWallPapers) first := list.Wallpapers[0].(*tg.WallPaper) input := &tg.InputWallPaper{ID: first.ID, AccessHash: first.AccessHash} @@ -110,13 +98,9 @@ func TestAccountWallpaperSeedLookupAndAckRPCs(t *testing.T) { if err != nil { t.Fatalf("dispatch getWallPaper: %v", err) } - oneBox, ok := oneGot.(*tg.WallPaperBox) + oneWallpaper, ok := oneGot.(*tg.WallPaper) if !ok { - t.Fatalf("getWallPaper = %T, want *tg.WallPaperBox", oneGot) - } - oneWallpaper, ok := oneBox.WallPaper.(*tg.WallPaper) - if !ok { - t.Fatalf("getWallPaper boxed = %T, want *tg.WallPaper", oneBox.WallPaper) + t.Fatalf("getWallPaper = %T, want *tg.WallPaper", oneGot) } if oneWallpaper.ID != first.ID { t.Fatalf("getWallPaper id = %d, want %d", oneWallpaper.ID, first.ID) @@ -131,13 +115,12 @@ func TestAccountWallpaperSeedLookupAndAckRPCs(t *testing.T) { if err != nil { t.Fatalf("dispatch getWallPaper nofile: %v", err) } - nofileBox, ok := nofileGot.(*tg.WallPaperBox) + nofileWallpaper, ok := nofileGot.(*tg.WallPaperNoFile) if !ok { - t.Fatalf("getWallPaper nofile = %T, want *tg.WallPaperBox", nofileGot) + t.Fatalf("getWallPaper nofile = %T, want *tg.WallPaperNoFile", nofileGot) } - nofileWallpaper, ok := nofileBox.WallPaper.(*tg.WallPaperNoFile) - if !ok || nofileWallpaper.ID != nofileInput.ID { - t.Fatalf("getWallPaper nofile boxed = %T %#v, want no-file id", nofileBox.WallPaper, nofileBox.WallPaper) + if nofileWallpaper.ID != nofileInput.ID { + t.Fatalf("getWallPaper nofile = %#v, want no-file id", nofileWallpaper) } var multiReq bin.Buffer @@ -152,7 +135,7 @@ func TestAccountWallpaperSeedLookupAndAckRPCs(t *testing.T) { if err != nil { t.Fatalf("dispatch getMultiWallPapers: %v", err) } - if vector, ok := multiGot.(*tg.WallPaperClassVector); !ok || len(vector.Elems) != 3 { + if vector, ok := dispatchCanonicalValue(multiGot).([]tg.WallPaperClass); !ok || len(vector) != 3 { t.Fatalf("getMultiWallPapers = %T %#v, want 3 wallpapers", multiGot, multiGot) } @@ -171,12 +154,8 @@ func TestAccountWallpaperSeedLookupAndAckRPCs(t *testing.T) { if err != nil { t.Fatalf("dispatch %s: %v", name, err) } - box, ok := got.(*tg.BoolBox) - if !ok { - t.Fatalf("%s = %T, want *tg.BoolBox", name, got) - } - if _, ok := box.Bool.(*tg.BoolTrue); !ok { - t.Fatalf("%s boxed = %T, want *tg.BoolTrue", name, box.Bool) + if value, ok := dispatchCanonicalValue(got).(bool); !ok || !value { + t.Fatalf("%s = %#v (%T), want true", name, dispatchCanonicalValue(got), got) } } @@ -201,13 +180,9 @@ func TestPaymentsGetStarGiftCollectionsNoServiceFallbackAndValidatesPeer(t *test if err != nil { t.Fatalf("dispatch: %v", err) } - box, ok := got.(*tg.PaymentsStarGiftCollectionsBox) + collections, ok := got.(*tg.PaymentsStarGiftCollections) if !ok { - t.Fatalf("response type = %T, want *tg.PaymentsStarGiftCollectionsBox", got) - } - collections, ok := box.StarGiftCollections.(*tg.PaymentsStarGiftCollections) - if !ok { - t.Fatalf("boxed response type = %T, want *tg.PaymentsStarGiftCollections", box.StarGiftCollections) + t.Fatalf("response type = %T, want *tg.PaymentsStarGiftCollections", got) } if len(collections.Collections) != 0 { t.Fatalf("collections = %+v, want empty list", collections.Collections) diff --git a/internal/rpc/payments.go b/internal/rpc/payments.go index a1cb70b1..378821ee 100644 --- a/internal/rpc/payments.go +++ b/internal/rpc/payments.go @@ -7,45 +7,97 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" ) // registerPayments 注册 payments.* RPC:Stars 本地账本(余额/流水真实化)+ 其余 // gift/auction/revenue 第一阶段兼容桩。 -func (r *Router) registerPayments(d *tg.ServerDispatcher) { - d.OnPaymentsGetStarsTopupOptions(func(ctx context.Context) ([]tg.StarsTopupOption, error) { +func (r *Router) registerPayments(d *tlprofile.Dispatcher) { + registerRPC[*tg.PaymentsGetStarsTopupOptionsRequest](d, tlprofile.SemanticMethodPaymentsGetStarsTopupOptions, func(ctx context.Context, layerRequest *tg.PaymentsGetStarsTopupOptionsRequest) (any, + + // premium 订阅赠送 telesrv 不实现(无支付流),返回空选项。关键作用:TDesktop 送礼框 + // ShowStarGiftBox 的 ready() 门控要求 getPremiumGiftCodeOptions 成功返回(on_next)才置 + // premiumGiftsReady=true,否则整框不弹出——此前返 NOT_IMPLEMENTED 导致点生日礼物无反应。 + // 空列表即解门,星礼物正常发送;premium 区段另由 userFull.disallow_premium_gifts=true 隐藏。 + error) { return devStarsTopupOptions(), nil }) - // premium 订阅赠送 telesrv 不实现(无支付流),返回空选项。关键作用:TDesktop 送礼框 - // ShowStarGiftBox 的 ready() 门控要求 getPremiumGiftCodeOptions 成功返回(on_next)才置 - // premiumGiftsReady=true,否则整框不弹出——此前返 NOT_IMPLEMENTED 导致点生日礼物无反应。 - // 空列表即解门,星礼物正常发送;premium 区段另由 userFull.disallow_premium_gifts=true 隐藏。 - d.OnPaymentsGetPremiumGiftCodeOptions(func(ctx context.Context, req *tg.PaymentsGetPremiumGiftCodeOptionsRequest) ([]tg.PremiumGiftCodeOption, error) { + registerRPC[*tg.PaymentsGetPremiumGiftCodeOptionsRequest](d, tlprofile.SemanticMethodPaymentsGetPremiumGiftCodeOptions, func(ctx context.Context, req *tg.PaymentsGetPremiumGiftCodeOptionsRequest) (any, error) { return []tg.PremiumGiftCodeOption{}, nil }) - d.OnPaymentsGetStarsStatus(r.onPaymentsGetStarsStatus) - d.OnPaymentsGetStarsTransactions(r.onPaymentsGetStarsTransactions) - d.OnPaymentsGetStarGiftActiveAuctions(func(ctx context.Context, hash int64) (tg.PaymentsStarGiftActiveAuctionsClass, error) { + registerRPC[*tg.PaymentsGetStarsStatusRequest](d, tlprofile.SemanticMethodPaymentsGetStarsStatus, func(ctx context.Context, layerRequest *tg.PaymentsGetStarsStatusRequest) (any, error) { + return r.onPaymentsGetStarsStatus(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsGetStarsTransactionsRequest](d, tlprofile.SemanticMethodPaymentsGetStarsTransactions, func(ctx context.Context, layerRequest *tg.PaymentsGetStarsTransactionsRequest) (any, error) { + return r.onPaymentsGetStarsTransactions(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsGetStarGiftActiveAuctionsRequest](d, tlprofile.SemanticMethodPaymentsGetStarGiftActiveAuctions, func(ctx context.Context, layerRequest *tg.PaymentsGetStarGiftActiveAuctionsRequest) (any, error) { + hash := layerRequest. + Hash + _ = hash + return tdesktop.StarGiftActiveAuctions(), nil }) - d.OnPaymentsGetStarGifts(r.onPaymentsGetStarGifts) - d.OnPaymentsGetStarGiftUpgradePreview(r.onPaymentsGetStarGiftUpgradePreview) - d.OnPaymentsGetUniqueStarGift(r.onPaymentsGetUniqueStarGift) - d.OnPaymentsGetPaymentForm(r.onPaymentsGetPaymentForm) - d.OnPaymentsSendStarsForm(r.onPaymentsSendStarsForm) - d.OnPaymentsGetSavedStarGifts(r.onPaymentsGetSavedStarGifts) - d.OnPaymentsGetSavedStarGift(r.onPaymentsGetSavedStarGift) - d.OnPaymentsSaveStarGift(r.onPaymentsSaveStarGift) - d.OnPaymentsConvertStarGift(r.onPaymentsConvertStarGift) - d.OnPaymentsUpgradeStarGift(r.onPaymentsUpgradeStarGift) - d.OnPaymentsGetStarGiftCollections(r.onPaymentsGetStarGiftCollections) - d.OnPaymentsCreateStarGiftCollection(r.onPaymentsCreateStarGiftCollection) - d.OnPaymentsUpdateStarGiftCollection(r.onPaymentsUpdateStarGiftCollection) - d.OnPaymentsDeleteStarGiftCollection(r.onPaymentsDeleteStarGiftCollection) - d.OnPaymentsReorderStarGiftCollections(r.onPaymentsReorderStarGiftCollections) - d.OnPaymentsToggleStarGiftsPinnedToTop(r.onPaymentsToggleStarGiftsPinnedToTop) - d.OnPaymentsGetStarsRevenueAdsAccountURL(func(ctx context.Context, peer tg.InputPeerClass) (*tg.PaymentsStarsRevenueAdsAccountURL, error) { + registerRPC[*tg.PaymentsGetStarGiftsRequest](d, tlprofile.SemanticMethodPaymentsGetStarGifts, func(ctx context.Context, layerRequest *tg.PaymentsGetStarGiftsRequest) (any, error) { + return r.onPaymentsGetStarGifts(ctx, layerRequest. + Hash) + }) + registerRPC[*tg.PaymentsGetStarGiftUpgradePreviewRequest](d, tlprofile.SemanticMethodPaymentsGetStarGiftUpgradePreview, func(ctx context.Context, layerRequest *tg.PaymentsGetStarGiftUpgradePreviewRequest) (any, error) { + return r.onPaymentsGetStarGiftUpgradePreview(ctx, layerRequest. + GiftID) + }) + registerRPC[*tg.PaymentsGetUniqueStarGiftRequest](d, tlprofile.SemanticMethodPaymentsGetUniqueStarGift, func(ctx context.Context, layerRequest *tg.PaymentsGetUniqueStarGiftRequest) (any, error) { + return r.onPaymentsGetUniqueStarGift(ctx, layerRequest. + Slug) + }) + registerRPC[*tg.PaymentsGetPaymentFormRequest](d, tlprofile.SemanticMethodPaymentsGetPaymentForm, func(ctx context.Context, layerRequest *tg.PaymentsGetPaymentFormRequest) (any, error) { + return r.onPaymentsGetPaymentForm(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsSendStarsFormRequest](d, tlprofile.SemanticMethodPaymentsSendStarsForm, func(ctx context.Context, layerRequest *tg.PaymentsSendStarsFormRequest) (any, error) { + return r.onPaymentsSendStarsForm(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsGetSavedStarGiftsRequest](d, tlprofile.SemanticMethodPaymentsGetSavedStarGifts, func(ctx context.Context, layerRequest *tg.PaymentsGetSavedStarGiftsRequest) (any, error) { + return r.onPaymentsGetSavedStarGifts(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsGetSavedStarGiftRequest](d, tlprofile.SemanticMethodPaymentsGetSavedStarGift, func(ctx context.Context, layerRequest *tg.PaymentsGetSavedStarGiftRequest) (any, error) { + return r.onPaymentsGetSavedStarGift(ctx, layerRequest. + Stargift) + }) + registerRPC[*tg.PaymentsSaveStarGiftRequest](d, tlprofile.SemanticMethodPaymentsSaveStarGift, func(ctx context.Context, layerRequest *tg.PaymentsSaveStarGiftRequest) (any, error) { + return r.onPaymentsSaveStarGift(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsConvertStarGiftRequest](d, tlprofile.SemanticMethodPaymentsConvertStarGift, func(ctx context.Context, layerRequest *tg.PaymentsConvertStarGiftRequest) (any, error) { + return r.onPaymentsConvertStarGift(ctx, layerRequest. + Stargift) + }) + registerRPC[*tg.PaymentsUpgradeStarGiftRequest](d, tlprofile.SemanticMethodPaymentsUpgradeStarGift, func(ctx context.Context, layerRequest *tg.PaymentsUpgradeStarGiftRequest) (any, error) { + return r.onPaymentsUpgradeStarGift(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsGetStarGiftCollectionsRequest](d, tlprofile.SemanticMethodPaymentsGetStarGiftCollections, func(ctx context.Context, layerRequest *tg.PaymentsGetStarGiftCollectionsRequest) (any, error) { + return r.onPaymentsGetStarGiftCollections(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsCreateStarGiftCollectionRequest](d, tlprofile.SemanticMethodPaymentsCreateStarGiftCollection, func(ctx context.Context, layerRequest *tg.PaymentsCreateStarGiftCollectionRequest) (any, error) { + return r.onPaymentsCreateStarGiftCollection(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsUpdateStarGiftCollectionRequest](d, tlprofile.SemanticMethodPaymentsUpdateStarGiftCollection, func(ctx context.Context, layerRequest *tg.PaymentsUpdateStarGiftCollectionRequest) (any, error) { + return r.onPaymentsUpdateStarGiftCollection(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsDeleteStarGiftCollectionRequest](d, tlprofile.SemanticMethodPaymentsDeleteStarGiftCollection, func(ctx context.Context, layerRequest *tg.PaymentsDeleteStarGiftCollectionRequest) (any, error) { + return r.onPaymentsDeleteStarGiftCollection(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsReorderStarGiftCollectionsRequest](d, tlprofile.SemanticMethodPaymentsReorderStarGiftCollections, func(ctx context.Context, layerRequest *tg.PaymentsReorderStarGiftCollectionsRequest) (any, error) { + return r.onPaymentsReorderStarGiftCollections(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsToggleStarGiftsPinnedToTopRequest](d, tlprofile.SemanticMethodPaymentsToggleStarGiftsPinnedToTop, func(ctx context.Context, layerRequest *tg.PaymentsToggleStarGiftsPinnedToTopRequest) (any, error) { + return r.onPaymentsToggleStarGiftsPinnedToTop(ctx, layerRequest) + }) + registerRPC[*tg.PaymentsGetStarsRevenueAdsAccountURLRequest](d, tlprofile.SemanticMethodPaymentsGetStarsRevenueAdsAccountURL, func(ctx context.Context, layerRequest *tg.PaymentsGetStarsRevenueAdsAccountURLRequest) (any, error) { + peer := layerRequest. + Peer + _ = peer + userID, _, err := r.currentUserID(ctx) if err != nil { return nil, internalErr() @@ -55,7 +107,7 @@ func (r *Router) registerPayments(d *tg.ServerDispatcher) { } return &tg.PaymentsStarsRevenueAdsAccountURL{URL: "https://ads.telegram.org/"}, nil }) - d.OnPaymentsGetStarsRevenueStats(func(ctx context.Context, req *tg.PaymentsGetStarsRevenueStatsRequest) (*tg.PaymentsStarsRevenueStats, error) { + registerRPC[*tg.PaymentsGetStarsRevenueStatsRequest](d, tlprofile.SemanticMethodPaymentsGetStarsRevenueStats, func(ctx context.Context, req *tg.PaymentsGetStarsRevenueStatsRequest) (any, error) { userID, _, err := r.currentUserID(ctx) if err != nil { return nil, internalErr() @@ -68,6 +120,7 @@ func (r *Router) registerPayments(d *tg.ServerDispatcher) { } return tdesktop.StarsRevenueStats(req.GetTon()), nil }) + } // onPaymentsGetStarsStatus 返回当前账号的 Stars 余额(首读时惰性授予起始余额)。 diff --git a/internal/rpc/payments_star_gifts_rpc_test.go b/internal/rpc/payments_star_gifts_rpc_test.go index 0c714bdd..2080815f 100644 --- a/internal/rpc/payments_star_gifts_rpc_test.go +++ b/internal/rpc/payments_star_gifts_rpc_test.go @@ -10,6 +10,7 @@ import ( "github.com/iamxvbaba/td/tgerr" "go.uber.org/zap/zaptest" + "github.com/iamxvbaba/td/tlprofile" appchannels "telesrv/internal/app/channels" appmessages "telesrv/internal/app/messages" appstargifts "telesrv/internal/app/stargifts" @@ -107,16 +108,20 @@ func TestSavedStarGiftProjectionCombinesHistoricalCatalogWithCurrentCollectibleA if upgradeStars, ok := gift.GetUpgradeStars(); !ok || upgradeStars != 75 { t.Fatalf("upgrade_stars = %d ok=%v, want current price 75", upgradeStars, ok) } - for _, profile := range []tg.LayerProfile{tg.LayerProfile227, tg.LayerProfile228} { + for _, profile := range []tlprofile.Profile{tlprofile.Profile227, tlprofile.Profile228} { wire := &tg.PaymentsSavedStarGifts{Count: 1, Gifts: projected, Chats: []tg.ChatClass{}, Users: []tg.UserClass{}} encoded := &bin.Buffer{} - if err := tg.EncodeLayer(profile, tg.LayerConstructorPaymentsSavedStarGiftsType(), wire, encoded); err != nil { + if err := tlprofile.EncodeObject(profile, wire, encoded); err != nil { t.Fatalf("encode Layer %d saved gift: %v", profile, err) } - decoded, err := tg.DecodeLayer(profile, tg.LayerConstructorPaymentsSavedStarGiftsType(), &bin.Buffer{Buf: encoded.Buf}) + decodedObject, err := tlprofile.DecodeObject(profile, &bin.Buffer{Buf: encoded.Buf}, tlprofile.Limits{}) if err != nil { t.Fatalf("decode Layer %d saved gift: %v", profile, err) } + decoded, ok := decodedObject.(*tg.PaymentsSavedStarGifts) + if !ok { + t.Fatalf("decode Layer %d saved gift type = %T", profile, decodedObject) + } inner, ok := decoded.Gifts[0].Gift.(*tg.StarGift) if !ok || !decoded.Gifts[0].CanUpgrade || inner.UpgradeStars != 75 { t.Fatalf("Layer %d projection lost upgrade flags: %#v", profile, decoded.Gifts[0]) @@ -219,28 +224,36 @@ func TestStarGiftCollectiblePreviewUpgradeFormUniqueAndServiceProjection(t *test } else if user, ok := peer.(*tg.PeerUser); !ok || user.UserID != owner.ID { t.Fatalf("unique service action peer = %#v", peer) } - for _, profile := range []tg.LayerProfile{tg.LayerProfile227, tg.LayerProfile228} { + for _, profile := range []tlprofile.Profile{tlprofile.Profile227, tlprofile.Profile228} { responseWire := &bin.Buffer{} - if err := tg.EncodeLayer(profile, tg.LayerConstructorPaymentsUniqueStarGiftType(), uniqueResponse, responseWire); err != nil { + if err := tlprofile.EncodeObject(profile, uniqueResponse, responseWire); err != nil { t.Fatalf("encode Layer %d unique response: %v", profile, err) } - decodedResponse, err := tg.DecodeLayer(profile, tg.LayerConstructorPaymentsUniqueStarGiftType(), &bin.Buffer{Buf: responseWire.Buf}) + decodedResponseObject, err := tlprofile.DecodeObject(profile, &bin.Buffer{Buf: responseWire.Buf}, tlprofile.Limits{}) if err != nil { t.Fatalf("decode Layer %d unique response: %v", profile, err) } + decodedResponse, ok := decodedResponseObject.(*tg.PaymentsUniqueStarGift) + if !ok { + t.Fatalf("decode Layer %d unique response type = %T", profile, decodedResponseObject) + } decodedGift, ok := decodedResponse.Gift.(*tg.StarGiftUnique) if !ok || decodedGift.Slug != unique.Slug || len(decodedGift.Attributes) != 4 { t.Fatalf("Layer %d unique response lost fields: %#v", profile, decodedResponse.Gift) } actionWire := &bin.Buffer{} - if err := tg.EncodeLayer(profile, tg.LayerConstructorMessageActionStarGiftUniqueType(), action, actionWire); err != nil { + if err := tlprofile.EncodeObject(profile, action, actionWire); err != nil { t.Fatalf("encode Layer %d unique action: %v", profile, err) } - decodedAction, err := tg.DecodeLayer(profile, tg.LayerConstructorMessageActionStarGiftUniqueType(), &bin.Buffer{Buf: actionWire.Buf}) + decodedActionObject, err := tlprofile.DecodeObject(profile, &bin.Buffer{Buf: actionWire.Buf}, tlprofile.Limits{}) if err != nil { t.Fatalf("decode Layer %d unique action: %v", profile, err) } + decodedAction, ok := decodedActionObject.(*tg.MessageActionStarGiftUnique) + if !ok { + t.Fatalf("decode Layer %d unique action type = %T", profile, decodedActionObject) + } if decodedActionGift, ok := decodedAction.Gift.(*tg.StarGiftUnique); !ok || !decodedAction.Upgrade || decodedActionGift.Slug != unique.Slug { t.Fatalf("Layer %d unique action lost fields: %#v", profile, decodedAction) } diff --git a/internal/rpc/phone_register.go b/internal/rpc/phone_register.go index 10231c5d..39e5e5c9 100644 --- a/internal/rpc/phone_register.go +++ b/internal/rpc/phone_register.go @@ -4,55 +4,130 @@ import ( "context" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) // registerPhone 注册通话域 RPC。 // // 归属约定(跨任务协调,群聊 M0 落地时遵守):本文件是 phone.* 的唯一注册点; -// gotd ServerDispatcher 对同一 RPC 重复 On* 注册是静默 last-wins,群聊 stub +// tlprofile.Dispatcher 对同一 semantic method 重复注册会失败,群聊 stub // 清单不得覆盖此处已注册的真实现。messages.getDhConfig 属通话域(DH 参数下发), // 注册在这里而非 messages_register.go。 -func (r *Router) registerPhone(d *tg.ServerDispatcher) { - d.OnMessagesGetDhConfig(r.onMessagesGetDhConfig) +func (r *Router) registerPhone(d *tlprofile.Dispatcher) { + registerRPC[*tg.MessagesGetDhConfigRequest](d, tlprofile.SemanticMethodMessagesGetDhConfig, func(ctx context.Context, layerRequest *tg.MessagesGetDhConfigRequest) (any, error) { + return r.onMessagesGetDhConfig(ctx, layerRequest) + }) + registerRPC[*tg.PhoneRequestCallRequest](d, tlprofile.SemanticMethodPhoneRequestCall, func(ctx context.Context, layerRequest *tg.PhoneRequestCallRequest) (any, error) { + return r.onPhoneRequestCall(ctx, layerRequest) + }) + registerRPC[*tg.PhoneReceivedCallRequest](d, tlprofile.SemanticMethodPhoneReceivedCall, func(ctx context.Context, layerRequest *tg.PhoneReceivedCallRequest) (any, error) { + return r.onPhoneReceivedCall(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.PhoneAcceptCallRequest](d, tlprofile.SemanticMethodPhoneAcceptCall, func(ctx context.Context, layerRequest *tg.PhoneAcceptCallRequest) (any, error) { + return r.onPhoneAcceptCall(ctx, layerRequest) + }) + registerRPC[*tg.PhoneConfirmCallRequest](d, tlprofile.SemanticMethodPhoneConfirmCall, func(ctx context.Context, layerRequest *tg.PhoneConfirmCallRequest) (any, error) { + return r.onPhoneConfirmCall(ctx, layerRequest) + }) + registerRPC[*tg.PhoneDiscardCallRequest](d, tlprofile.SemanticMethodPhoneDiscardCall, func(ctx context.Context, layerRequest *tg.PhoneDiscardCallRequest) (any, error) { + return r.onPhoneDiscardCall(ctx, layerRequest) + }) + registerRPC[*tg.PhoneSendSignalingDataRequest](d, tlprofile.SemanticMethodPhoneSendSignalingData, func(ctx context.Context, layerRequest *tg.PhoneSendSignalingDataRequest) (any, error) { + return r.onPhoneSendSignalingData(ctx, layerRequest) + }) + registerRPC[*tg.PhoneSetCallRatingRequest](d, tlprofile.SemanticMethodPhoneSetCallRating, func(ctx context.Context, layerRequest *tg.PhoneSetCallRatingRequest) (any, error) { + return r.onPhoneSetCallRating(ctx, layerRequest) + }) + registerRPC[*tg.PhoneSaveCallDebugRequest](d, tlprofile.SemanticMethodPhoneSaveCallDebug, func(ctx context.Context, layerRequest *tg.PhoneSaveCallDebugRequest) (any, error) { + return r.onPhoneSaveCallDebug(ctx, layerRequest) + }) + registerRPC[*tg.PhoneGetCallConfigRequest](d, tlprofile.SemanticMethodPhoneGetCallConfig, func(ctx context.Context, layerRequest * + // tgcalls 对空配置走默认值;需要精调(audio_max_bitrate 等)时再填键值。 + tg.PhoneGetCallConfigRequest) (any, error) { - d.OnPhoneRequestCall(r.onPhoneRequestCall) - d.OnPhoneReceivedCall(r.onPhoneReceivedCall) - d.OnPhoneAcceptCall(r.onPhoneAcceptCall) - d.OnPhoneConfirmCall(r.onPhoneConfirmCall) - d.OnPhoneDiscardCall(r.onPhoneDiscardCall) - d.OnPhoneSendSignalingData(r.onPhoneSendSignalingData) - d.OnPhoneSetCallRating(r.onPhoneSetCallRating) - d.OnPhoneSaveCallDebug(r.onPhoneSaveCallDebug) - d.OnPhoneGetCallConfig(func(ctx context.Context) (*tg.DataJSON, error) { - // tgcalls 对空配置走默认值;需要精调(audio_max_bitrate 等)时再填键值。 return &tg.DataJSON{Data: "{}"}, nil }) + registerRPC[ // 超级群语音聊天(group call)。 - d.OnPhoneCreateGroupCall(r.onPhoneCreateGroupCall) - d.OnPhoneJoinGroupCall(r.onPhoneJoinGroupCall) - d.OnPhoneLeaveGroupCall(r.onPhoneLeaveGroupCall) - d.OnPhoneDiscardGroupCall(r.onPhoneDiscardGroupCall) - d.OnPhoneGetGroupCall(r.onPhoneGetGroupCall) - d.OnPhoneGetGroupParticipants(r.onPhoneGetGroupParticipants) - d.OnPhoneCheckGroupCall(r.onPhoneCheckGroupCall) - d.OnPhoneExportGroupCallInvite(r.onPhoneExportGroupCallInvite) - d.OnPhoneEditGroupCallParticipant(r.onPhoneEditGroupCallParticipant) - d.OnPhoneEditGroupCallTitle(r.onPhoneEditGroupCallTitle) - d.OnPhoneToggleGroupCallSettings(r.onPhoneToggleGroupCallSettings) - d.OnPhoneInviteToGroupCall(r.onPhoneInviteToGroupCall) - // 定时通话(scheduled video chat)。 - d.OnPhoneStartScheduledGroupCall(r.onPhoneStartScheduledGroupCall) - d.OnPhoneToggleGroupCallStartSubscription(r.onPhoneToggleGroupCallStartSubscription) - // Ad-hoc E2E conference call(P2P 通话升级/拉人路径)。 - d.OnPhoneCreateConferenceCall(r.onPhoneCreateConferenceCall) - d.OnPhoneInviteConferenceCallParticipant(r.onPhoneInviteConferenceCallParticipant) - d.OnPhoneDeleteConferenceCallParticipants(r.onPhoneDeleteConferenceCallParticipants) - d.OnPhoneSendConferenceCallBroadcast(r.onPhoneSendConferenceCallBroadcast) - d.OnPhoneDeclineConferenceCallInvite(r.onPhoneDeclineConferenceCallInvite) - d.OnPhoneGetGroupCallChainBlocks(r.onPhoneGetGroupCallChainBlocks) - // 屏幕共享(M4):同参与者第二媒体连接。 - d.OnPhoneJoinGroupCallPresentation(r.onPhoneJoinGroupCallPresentation) - d.OnPhoneLeaveGroupCallPresentation(r.onPhoneLeaveGroupCallPresentation) + *tg.PhoneCreateGroupCallRequest](d, tlprofile.SemanticMethodPhoneCreateGroupCall, func(ctx context.Context, layerRequest *tg.PhoneCreateGroupCallRequest) (any, error) { + return r.onPhoneCreateGroupCall(ctx, layerRequest) + }) + registerRPC[*tg.PhoneJoinGroupCallRequest](d, tlprofile.SemanticMethodPhoneJoinGroupCall, func(ctx context.Context, layerRequest *tg.PhoneJoinGroupCallRequest) (any, error) { + return r.onPhoneJoinGroupCall(ctx, layerRequest) + }) + registerRPC[*tg.PhoneLeaveGroupCallRequest](d, tlprofile.SemanticMethodPhoneLeaveGroupCall, func(ctx context.Context, layerRequest *tg.PhoneLeaveGroupCallRequest) (any, error) { + return r.onPhoneLeaveGroupCall(ctx, layerRequest) + }) + registerRPC[*tg.PhoneDiscardGroupCallRequest](d, tlprofile.SemanticMethodPhoneDiscardGroupCall, func(ctx context.Context, layerRequest *tg.PhoneDiscardGroupCallRequest) (any, error) { + return r.onPhoneDiscardGroupCall(ctx, layerRequest. + Call) + }) + registerRPC[*tg.PhoneGetGroupCallRequest](d, tlprofile.SemanticMethodPhoneGetGroupCall, func(ctx context.Context, layerRequest *tg.PhoneGetGroupCallRequest) (any, error) { + return r.onPhoneGetGroupCall(ctx, layerRequest) + }) + registerRPC[*tg.PhoneGetGroupParticipantsRequest](d, tlprofile.SemanticMethodPhoneGetGroupParticipants, func(ctx context.Context, layerRequest *tg.PhoneGetGroupParticipantsRequest) (any, error) { + return r.onPhoneGetGroupParticipants(ctx, layerRequest) + }) + registerRPC[*tg.PhoneCheckGroupCallRequest](d, tlprofile.SemanticMethodPhoneCheckGroupCall, func(ctx context.Context, layerRequest *tg.PhoneCheckGroupCallRequest) (any, error) { + return r.onPhoneCheckGroupCall(ctx, layerRequest) + }) + registerRPC[*tg.PhoneExportGroupCallInviteRequest](d, tlprofile.SemanticMethodPhoneExportGroupCallInvite, func(ctx context.Context, layerRequest *tg.PhoneExportGroupCallInviteRequest) (any, error) { + return r.onPhoneExportGroupCallInvite(ctx, layerRequest) + }) + registerRPC[*tg.PhoneEditGroupCallParticipantRequest](d, tlprofile.SemanticMethodPhoneEditGroupCallParticipant, func(ctx context.Context, layerRequest *tg.PhoneEditGroupCallParticipantRequest) (any, error) { + return r.onPhoneEditGroupCallParticipant(ctx, layerRequest) + }) + registerRPC[*tg.PhoneEditGroupCallTitleRequest](d, tlprofile.SemanticMethodPhoneEditGroupCallTitle, func(ctx context.Context, layerRequest *tg.PhoneEditGroupCallTitleRequest) (any, error) { + return r.onPhoneEditGroupCallTitle(ctx, layerRequest) + }) + registerRPC[*tg.PhoneToggleGroupCallSettingsRequest](d, tlprofile.SemanticMethodPhoneToggleGroupCallSettings, func(ctx context.Context, layerRequest *tg.PhoneToggleGroupCallSettingsRequest) ( + + // 定时通话(scheduled video chat)。 + any, error) { + return r.onPhoneToggleGroupCallSettings(ctx, layerRequest) + }) + registerRPC[*tg.PhoneInviteToGroupCallRequest](d, tlprofile.SemanticMethodPhoneInviteToGroupCall, func(ctx context.Context, layerRequest *tg.PhoneInviteToGroupCallRequest) (any, error) { + return r.onPhoneInviteToGroupCall(ctx, layerRequest) + }) + registerRPC[*tg.PhoneStartScheduledGroupCallRequest](d, tlprofile.SemanticMethodPhoneStartScheduledGroupCall, func(ctx context.Context, layerRequest *tg.PhoneStartScheduledGroupCallRequest) (any, error) { + return r.onPhoneStartScheduledGroupCall(ctx, layerRequest. + Call) + }) + registerRPC[*tg.PhoneToggleGroupCallStartSubscriptionRequest](d, tlprofile.SemanticMethodPhoneToggleGroupCallStartSubscription, func(ctx context.Context, + // Ad-hoc E2E conference call(P2P 通话升级/拉人路径)。 + layerRequest *tg.PhoneToggleGroupCallStartSubscriptionRequest) (any, error) { + return r.onPhoneToggleGroupCallStartSubscription(ctx, layerRequest) + }) + registerRPC[*tg.PhoneCreateConferenceCallRequest](d, tlprofile.SemanticMethodPhoneCreateConferenceCall, func(ctx context.Context, layerRequest *tg.PhoneCreateConferenceCallRequest) (any, error) { + return r.onPhoneCreateConferenceCall(ctx, layerRequest) + }) + registerRPC[*tg.PhoneInviteConferenceCallParticipantRequest](d, tlprofile.SemanticMethodPhoneInviteConferenceCallParticipant, func(ctx context.Context, layerRequest *tg.PhoneInviteConferenceCallParticipantRequest) (any, error) { + return r.onPhoneInviteConferenceCallParticipant(ctx, layerRequest) + }) + registerRPC[*tg.PhoneDeleteConferenceCallParticipantsRequest](d, tlprofile.SemanticMethodPhoneDeleteConferenceCallParticipants, func(ctx context.Context, layerRequest *tg.PhoneDeleteConferenceCallParticipantsRequest) (any, error) { + return r.onPhoneDeleteConferenceCallParticipants(ctx, layerRequest) + }) + registerRPC[*tg.PhoneSendConferenceCallBroadcastRequest](d, tlprofile.SemanticMethodPhoneSendConferenceCallBroadcast, func(ctx context.Context, layerRequest *tg.PhoneSendConferenceCallBroadcastRequest) (any, error) { + return r.onPhoneSendConferenceCallBroadcast(ctx, layerRequest) + }) + registerRPC[*tg.PhoneDeclineConferenceCallInviteRequest](d, tlprofile.SemanticMethodPhoneDeclineConferenceCallInvite, func(ctx context.Context, layerRequest *tg.PhoneDeclineConferenceCallInviteRequest) (any, error) { + + // 屏幕共享(M4):同参与者第二媒体连接。 + return r.onPhoneDeclineConferenceCallInvite(ctx, layerRequest. + MsgID) + }) + registerRPC[*tg.PhoneGetGroupCallChainBlocksRequest](d, tlprofile.SemanticMethodPhoneGetGroupCallChainBlocks, func(ctx context.Context, layerRequest *tg.PhoneGetGroupCallChainBlocksRequest) (any, error) { + return r.onPhoneGetGroupCallChainBlocks(ctx, layerRequest) + }) + registerRPC[*tg.PhoneJoinGroupCallPresentationRequest](d, tlprofile.SemanticMethodPhoneJoinGroupCallPresentation, func(ctx context.Context, layerRequest *tg.PhoneJoinGroupCallPresentationRequest) (any, error) { + return r.onPhoneJoinGroupCallPresentation(ctx, layerRequest) + }) + registerRPC[*tg.PhoneLeaveGroupCallPresentationRequest](d, tlprofile.SemanticMethodPhoneLeaveGroupCallPresentation, func(ctx context.Context, layerRequest *tg.PhoneLeaveGroupCallPresentationRequest) (any, error) { + return r.onPhoneLeaveGroupCallPresentation(ctx, layerRequest. + Call) + }) + r.registerPhoneStubs(d) } diff --git a/internal/rpc/phone_stubs.go b/internal/rpc/phone_stubs.go index 176d987c..65bfa64d 100644 --- a/internal/rpc/phone_stubs.go +++ b/internal/rpc/phone_stubs.go @@ -4,23 +4,38 @@ import ( "context" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" ) // 群通话范围外入口的被动 stub(防点崩)。未列出的 phone.*(conference 族 / // 通话内消息族 / scheduled / RTMP)走 router fallback:400/500 NOT_IMPLEMENTED + // 兼容矩阵日志,客户端不断连。 -func (r *Router) registerPhoneStubs(d *tg.ServerDispatcher) { +func (r *Router) registerPhoneStubs(d *tlprofile.Dispatcher) { + registerRPC[ // 入会身份候选:真实实现见 phone_group_call.go(self + admin 的频道身份)。 - d.OnPhoneGetGroupCallJoinAs(r.onPhoneGetGroupCallJoinAs) - // default join-as 偏好持久化仍是 stub(chatFull.groupcall_default_join_as 不回填)。 - d.OnPhoneSaveDefaultGroupCallJoinAs(func(ctx context.Context, req *tg.PhoneSaveDefaultGroupCallJoinAsRequest) (bool, error) { + *tg.PhoneGetGroupCallJoinAsRequest](d, tlprofile.SemanticMethodPhoneGetGroupCallJoinAs, func(ctx context. + // default join-as 偏好持久化仍是 stub(chatFull.groupcall_default_join_as 不回填)。 + Context, layerRequest *tg.PhoneGetGroupCallJoinAsRequest) (any, error) { + return r.onPhoneGetGroupCallJoinAs(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.PhoneSaveDefaultGroupCallJoinAsRequest](d, tlprofile.SemanticMethodPhoneSaveDefaultGroupCallJoinAs, func(ctx context.Context, req *tg.PhoneSaveDefaultGroupCallJoinAsRequest) (any, error) { return true, nil }) + registerRPC[ + // 录制范围外:客户端只看 record_start_date(恒不下发),打发掉即可。 - d.OnPhoneToggleGroupCallRecord(func(ctx context.Context, req *tg.PhoneToggleGroupCallRecordRequest) (tg.UpdatesClass, error) { + *tg.PhoneToggleGroupCallRecordRequest](d, tlprofile.SemanticMethodPhoneToggleGroupCallRecord, func(ctx context.Context, req *tg.PhoneToggleGroupCallRecordRequest) (any, error) { return tgEmptyUpdates(int(r.clock.Now().Unix())), nil }) + registerRPC[ + // RTMP 直播(Live Stream):真实 handler 见 phone_group_call_rtmp.go。 - d.OnPhoneGetGroupCallStreamChannels(r.onPhoneGetGroupCallStreamChannels) - d.OnPhoneGetGroupCallStreamRtmpURL(r.onPhoneGetGroupCallStreamRtmpURL) + *tg.PhoneGetGroupCallStreamChannelsRequest](d, tlprofile.SemanticMethodPhoneGetGroupCallStreamChannels, func(ctx context.Context, layerRequest *tg.PhoneGetGroupCallStreamChannelsRequest) (any, error) { + return r.onPhoneGetGroupCallStreamChannels(ctx, layerRequest. + Call) + }) + registerRPC[*tg.PhoneGetGroupCallStreamRtmpURLRequest](d, tlprofile.SemanticMethodPhoneGetGroupCallStreamRtmpURL, func(ctx context.Context, layerRequest *tg.PhoneGetGroupCallStreamRtmpURLRequest) (any, error) { + return r.onPhoneGetGroupCallStreamRtmpURL(ctx, layerRequest) + }) } diff --git a/internal/rpc/photos.go b/internal/rpc/photos.go index c7ca889d..033cba8a 100644 --- a/internal/rpc/photos.go +++ b/internal/rpc/photos.go @@ -9,16 +9,29 @@ import ( "github.com/iamxvbaba/td/tg" "go.uber.org/zap" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) // registerPhotos 注册 photos.* RPC handler(头像上传 / 切换 / 查询 / 删除)。 -func (r *Router) registerPhotos(d *tg.ServerDispatcher) { - d.OnPhotosUploadProfilePhoto(r.onPhotosUploadProfilePhoto) - d.OnPhotosUpdateProfilePhoto(r.onPhotosUpdateProfilePhoto) - d.OnPhotosUploadContactProfilePhoto(r.onPhotosUploadContactProfilePhoto) - d.OnPhotosGetUserPhotos(r.onPhotosGetUserPhotos) - d.OnPhotosDeletePhotos(r.onPhotosDeletePhotos) +func (r *Router) registerPhotos(d *tlprofile.Dispatcher) { + registerRPC[*tg.PhotosUploadProfilePhotoRequest](d, tlprofile.SemanticMethodPhotosUploadProfilePhoto, func(ctx context.Context, layerRequest *tg.PhotosUploadProfilePhotoRequest) (any, error) { + return r.onPhotosUploadProfilePhoto(ctx, layerRequest) + }) + registerRPC[*tg.PhotosUpdateProfilePhotoRequest](d, tlprofile.SemanticMethodPhotosUpdateProfilePhoto, func(ctx context.Context, layerRequest *tg.PhotosUpdateProfilePhotoRequest) (any, error) { + return r.onPhotosUpdateProfilePhoto(ctx, layerRequest) + }) + registerRPC[*tg.PhotosUploadContactProfilePhotoRequest](d, tlprofile.SemanticMethodPhotosUploadContactProfilePhoto, func(ctx context.Context, layerRequest *tg.PhotosUploadContactProfilePhotoRequest) (any, error) { + return r.onPhotosUploadContactProfilePhoto(ctx, layerRequest) + }) + registerRPC[*tg.PhotosGetUserPhotosRequest](d, tlprofile.SemanticMethodPhotosGetUserPhotos, func(ctx context.Context, layerRequest *tg.PhotosGetUserPhotosRequest) (any, error) { + return r.onPhotosGetUserPhotos(ctx, layerRequest) + }) + registerRPC[*tg.PhotosDeletePhotosRequest](d, tlprofile.SemanticMethodPhotosDeletePhotos, func(ctx context.Context, layerRequest *tg.PhotosDeletePhotosRequest) (any, error) { + return r.onPhotosDeletePhotos(ctx, layerRequest. + ID) + }) + } func (r *Router) onPhotosUploadProfilePhoto(ctx context.Context, req *tg.PhotosUploadProfilePhotoRequest) (*tg.PhotosPhoto, error) { diff --git a/internal/rpc/premium.go b/internal/rpc/premium.go index b4ead78b..a084b2ed 100644 --- a/internal/rpc/premium.go +++ b/internal/rpc/premium.go @@ -8,15 +8,27 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) -func (r *Router) registerPremium(d *tg.ServerDispatcher) { - d.OnPremiumGetBoostsStatus(r.onPremiumGetBoostsStatus) - d.OnPremiumGetBoostsList(r.onPremiumGetBoostsList) - d.OnPremiumGetMyBoosts(r.onPremiumGetMyBoosts) - d.OnPremiumApplyBoost(r.onPremiumApplyBoost) - d.OnPremiumGetUserBoosts(r.onPremiumGetUserBoosts) +func (r *Router) registerPremium(d *tlprofile.Dispatcher) { + registerRPC[*tg.PremiumGetBoostsStatusRequest](d, tlprofile.SemanticMethodPremiumGetBoostsStatus, func(ctx context.Context, layerRequest *tg.PremiumGetBoostsStatusRequest) (any, error) { + return r.onPremiumGetBoostsStatus(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.PremiumGetBoostsListRequest](d, tlprofile.SemanticMethodPremiumGetBoostsList, func(ctx context.Context, layerRequest *tg.PremiumGetBoostsListRequest) (any, error) { + return r.onPremiumGetBoostsList(ctx, layerRequest) + }) + registerRPC[*tg.PremiumGetMyBoostsRequest](d, tlprofile.SemanticMethodPremiumGetMyBoosts, func(ctx context.Context, layerRequest *tg.PremiumGetMyBoostsRequest) (any, error) { + return r.onPremiumGetMyBoosts(ctx) + }) + registerRPC[*tg.PremiumApplyBoostRequest](d, tlprofile.SemanticMethodPremiumApplyBoost, func(ctx context.Context, layerRequest *tg.PremiumApplyBoostRequest) (any, error) { + return r.onPremiumApplyBoost(ctx, layerRequest) + }) + registerRPC[*tg.PremiumGetUserBoostsRequest](d, tlprofile.SemanticMethodPremiumGetUserBoosts, func(ctx context.Context, layerRequest *tg.PremiumGetUserBoostsRequest) (any, error) { + return r.onPremiumGetUserBoosts(ctx, layerRequest) + }) } func (r *Router) onPremiumGetBoostsStatus(ctx context.Context, peer tg.InputPeerClass) (*tg.PremiumBoostsStatus, error) { diff --git a/internal/rpc/request_preflight.go b/internal/rpc/request_preflight.go index d0d625b0..43c6993e 100644 --- a/internal/rpc/request_preflight.go +++ b/internal/rpc/request_preflight.go @@ -7,6 +7,7 @@ import ( "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" appfiles "telesrv/internal/app/files" "telesrv/internal/domain" ) @@ -72,33 +73,33 @@ var requestVectorPolicies = map[uint32]requestVectorPolicy{ // dispatcher construction fail closed until an explicit conversion policy is // supplied. var layerRPCVectorPolicies = []struct { - fieldID tg.LayerRPCFieldID + fieldID tlprofile.FieldID 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}, + {tlprofile.FieldUsersGetUsersID, 100, inputRequestTooLongErr}, + {tlprofile.FieldUsersGetRequirementsToContactID, maxRequirementsToContactUsers, limitInvalidErr}, + {tlprofile.FieldContactsImportContactsContacts, maxContactImportBatch, limitInvalidErr}, + {tlprofile.FieldContactsDeleteContactsID, maxContactDeleteBatch, limitInvalidErr}, + {tlprofile.FieldContactsEditCloseFriendsID, maxCloseFriendsCount, limitInvalidErr}, + {tlprofile.FieldContactsSetBlockedID, maxContactSetBlocked, limitInvalidErr}, + {tlprofile.FieldMessagesGetMessagesID, maxGetMessagesIDs, limitInvalidErr}, + {tlprofile.FieldMessagesGetChatsID, maxGetMessagesIDs, limitInvalidErr}, + {tlprofile.FieldMessagesGetPeerDialogsPeers, maxDialogInputPeers, limitInvalidErr}, + {tlprofile.FieldMessagesReadMessageContentsID, maxGetMessagesIDs, limitInvalidErr}, + {tlprofile.FieldMessagesGetCustomEmojiDocumentsDocumentID, maxEmojiDocuments, limitInvalidErr}, + {tlprofile.FieldMessagesDeleteMessagesID, domain.MaxDeleteMessageIDs, limitInvalidErr}, + {tlprofile.FieldMessagesCreateChatUsers, 200, limitInvalidErr}, + {tlprofile.FieldChannelsGetChannelsID, maxGetMessagesIDs, limitInvalidErr}, } -func registerLayerRPCAdmissionFieldPreflights(d *tg.ServerDispatcher) error { +func registerLayerRPCAdmissionFieldPreflights(d *tlprofile.Dispatcher) 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 { + if err := d.OnFieldPreflight(policy.fieldID, func(view tlprofile.FieldView) error { length, ok := view.VectorLength() if !ok { return inputRequestInvalidErr() @@ -115,11 +116,11 @@ func registerLayerRPCAdmissionFieldPreflights(d *tg.ServerDispatcher) error { } } - for _, fieldID := range []tg.LayerRPCFieldID{ - tg.LayerRPCFieldUploadSaveFilePartBytes, - tg.LayerRPCFieldUploadSaveBigFilePartBytes, + for _, fieldID := range []tlprofile.FieldID{ + tlprofile.FieldUploadSaveFilePartBytes, + tlprofile.FieldUploadSaveBigFilePartBytes, } { - if err := d.OnLayerRPCAdmissionFieldPreflight(fieldID, func(view tg.LayerRPCAdmissionFieldView) error { + if err := d.OnFieldPreflight(fieldID, func(view tlprofile.FieldView) error { length, ok := view.BytesLength() if !ok { return inputRequestInvalidErr() @@ -133,9 +134,9 @@ func registerLayerRPCAdmissionFieldPreflights(d *tg.ServerDispatcher) error { } } - if err := d.OnLayerRPCAdmissionFieldPreflight( - tg.LayerRPCFieldUploadSaveBigFilePartFileTotalParts, - func(view tg.LayerRPCAdmissionFieldView) error { + if err := d.OnFieldPreflight( + tlprofile.FieldUploadSaveBigFilePartFileTotalParts, + func(view tlprofile.FieldView) error { totalParts, ok := view.Int32() if !ok { return inputRequestInvalidErr() diff --git a/internal/rpc/router.go b/internal/rpc/router.go index 5d20eb51..b90c31c4 100644 --- a/internal/rpc/router.go +++ b/internal/rpc/router.go @@ -16,6 +16,7 @@ import ( "github.com/iamxvbaba/td/proto" "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" compatandroid "telesrv/internal/compat/android" "telesrv/internal/domain" "telesrv/internal/observability/dbtrace" @@ -90,7 +91,7 @@ type Config struct { TempKeyResolveCacheMaxEntries int } -// Router 把解密后的 RPC 请求按 TypeID 路由到 typed handler(tg.ServerDispatcher)。 +// Router 把解密后的 RPC 请求按 semantic method 路由到 typed handler(tlprofile.Dispatcher)。 // // handler 输入输出均为 iamxvbaba/td/tg 类型,各业务域的 handler // 与注册见 help.go / auth.go / users.go / updates.go。Router 本身只负责协议外壳: @@ -100,7 +101,7 @@ type Router struct { log *zap.Logger clock clock.Clock deps Deps - dispatcher *tg.ServerDispatcher + dispatcher *tlprofile.Dispatcher clientInfoMu sync.RWMutex clientInfo map[clientInfoSessionKey]clientSessionInfo authInfo map[[8]byte]clientSessionInfo @@ -244,12 +245,12 @@ func New(cfg Config, deps Deps, log *zap.Logger, clk clock.Clock) *Router { if cfg.DC > 0 { groupCallStreamDCID = cfg.DC } - d := tg.NewServerDispatcher(r.fallback) + d := tlprofile.NewDispatcher() if err := registerLayerRPCAdmissionFieldPreflights(d); err != nil { panic(fmt.Sprintf("register exact layer RPC admission policy: %v", err)) } r.registerAndroidLayerRPCAdapter(d) - d.OnLayerRPCWrappers(r.consumeLayerRPCWrappers) + d.OnWrappers(r.consumeLayerRPCWrappers) r.registerHelp(d) r.registerAuth(d) @@ -278,6 +279,22 @@ func New(cfg Config, deps Deps, log *zap.Logger, clk clock.Clock) *Router { return r } +func registerRPC[T bin.Object](d *tlprofile.Dispatcher, method tlprofile.SemanticID, handler func(context.Context, T) (any, error)) { + if d == nil || handler == nil { + panic("rpc: register nil canonical RPC handler or dispatcher") + } + err := d.Register(method, func(ctx context.Context, object bin.Object) (any, error) { + request, ok := object.(T) + if !ok { + return nil, fmt.Errorf("rpc: semantic %#016x decoded unexpected canonical request %T", uint64(method), object) + } + return handler(ctx, request) + }) + if err != nil { + panic(fmt.Sprintf("rpc: register canonical RPC %#016x: %v", uint64(method), err)) + } +} + // 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 exact innermost method rather than an invoke wrapper. @@ -622,14 +639,14 @@ func (r *Router) dispatch(ctx context.Context, b *bin.Buffer, depth int, meta *r // 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. + profile := tlprofile.ProfileCanonical + if selected, ok := tlprofile.ResolveProfile(LayerFrom(ctx)); ok { + profile = selected + } if id != 0 { - profile := tg.LayerProfileCanonical - if selected, ok := tg.ResolveLayerProfile(LayerFrom(ctx)); ok { - profile = selected - } - _, official := tg.LayerSemanticForWireID(profile, id) + _, official := tlprofile.SemanticForWireID(profile, id) if !official { - if up, ok, err := compatandroid.UpgradePrivateLayerRPC(profile, b, tg.LayerDecodeLimits{}); ok { + if up, ok, err := compatandroid.UpgradePrivateLayerRPC(profile, b, tlprofile.Limits{}); ok { if err != nil { return nil, inputRequestInvalidErr() } @@ -648,15 +665,18 @@ func (r *Router) dispatch(ctx context.Context, b *bin.Buffer, depth int, meta *r if meta != nil { meta.method = tlTypeName(id) } - semantic, knownRequest := tg.LayerSemanticForWireID(tg.LayerProfileCanonical, id) + semantic, knownRequest := tlprofile.SemanticForWireID(tlprofile.ProfileCanonical, id) if knownRequest { - category, _, named := tg.LayerSemanticName(semantic) + category, _, named := tlprofile.SemanticName(semantic) knownRequest = named && category == "function" } if !knownRequest { // Unknown methods remain opaque and go to the compatibility trace. return r.fallback(ctx, b) } + if !r.dispatcher.Has(semantic) { + return r.fallback(ctx, b) + } if r.deps.Auth != nil { if _, ok := UserIDFrom(ctx); !ok && !rpcAllowedWithoutAuthorization(id) { fields := append([]zap.Field{ @@ -680,7 +700,17 @@ func (r *Router) dispatch(ctx context.Context, b *bin.Buffer, depth int, meta *r r.maybeMarkSessionReceivesUpdates(ctx) dbBefore := dbtrace.SnapshotFromContext(ctx) start := time.Now() - enc, err := r.dispatcher.Handle(ctx, b) + admission, err := r.dispatcher.Admit(profile, b, tlprofile.Limits{}) + if err != nil { + return nil, err + } + exact, err := r.dispatcher.Dispatch(ctx, admission) + var enc bin.Encoder = exact + if err == nil && exact != nil { + if canonical, ok := exact.CanonicalValue().(bin.Encoder); ok { + enc = canonical + } + } dur := time.Since(start) dbDelta := dbtrace.SnapshotFromContext(ctx).Sub(dbBefore) fields := append([]zap.Field{ @@ -1026,7 +1056,7 @@ func (r *Router) FreezeNegotiatedSessionLayerAt(authKeyID [8]byte, sessionID int if r == nil || authKeyID == ([8]byte{}) || sessionID == 0 { return false, errors.New("invalid exact session profile identity") } - profile, ok := tg.ResolveLayerProfile(layer) + profile, ok := tlprofile.ResolveProfile(layer) if !ok || int(profile) != layer { return false, fmt.Errorf("unsupported exact session profile %d", layer) } diff --git a/internal/rpc/router_auth_cache_test.go b/internal/rpc/router_auth_cache_test.go index c8e527e7..2a90ad0f 100644 --- a/internal/rpc/router_auth_cache_test.go +++ b/internal/rpc/router_auth_cache_test.go @@ -61,10 +61,8 @@ func TestDispatchPromotesNegativeSessionCacheFromPositiveAuthCache(t *testing.T) if err != nil { t.Fatalf("dispatch: %v", err) } - if box, ok := enc.(*tg.BoolBox); !ok { - t.Fatalf("dispatch result = %T, want *tg.BoolBox", enc) - } else if _, ok := box.Bool.(*tg.BoolTrue); !ok { - t.Fatalf("dispatch bool = %T, want BoolTrue", box.Bool) + if value, ok := dispatchCanonicalValue(enc).(bool); !ok || !value { + t.Fatalf("dispatch result = %#v (%T), want true", dispatchCanonicalValue(enc), enc) } gotSession := sessions.snapshot() if gotSession.userID != userID || !gotSession.userResolved { @@ -130,10 +128,8 @@ func TestDispatchRevalidatesCachedTempAuthKeyBinding(t *testing.T) { } if enc, err := r.Dispatch(context.Background(), tempAuthKeyID, 123, &first); err != nil { t.Fatalf("first dispatch: %v", err) - } else if box, ok := enc.(*tg.BoolBox); !ok { - t.Fatalf("first dispatch result = %T, want *tg.BoolBox", enc) - } else if _, ok := box.Bool.(*tg.BoolTrue); !ok { - t.Fatalf("first dispatch bool = %T, want BoolTrue", box.Bool) + } else if value, ok := dispatchCanonicalValue(enc).(bool); !ok || !value { + t.Fatalf("first dispatch result = %#v (%T), want true", dispatchCanonicalValue(enc), enc) } gotSession := sessions.snapshot() if gotSession.authKeyID != permAuthKeyID || gotSession.userID != 1000000001 { diff --git a/internal/rpc/router_dispatch_test.go b/internal/rpc/router_dispatch_test.go index 19f5ef05..5dcc4927 100644 --- a/internal/rpc/router_dispatch_test.go +++ b/internal/rpc/router_dispatch_test.go @@ -8,6 +8,7 @@ import ( "github.com/iamxvbaba/td/clock" "github.com/iamxvbaba/td/tg" "github.com/iamxvbaba/td/tgerr" + "github.com/iamxvbaba/td/tlprofile" "go.uber.org/zap" "go.uber.org/zap/zaptest" "go.uber.org/zap/zaptest/observer" @@ -1334,7 +1335,7 @@ func TestTDesktopStartupRPCsEncode(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := WithUserID(context.Background(), 1000000001) - result, method := dispatchExactLayerRPCTest(t, r, ctx, tg.LayerProfileCanonical, tt.req) + result, method := dispatchExactLayerRPCTest(t, r, ctx, tlprofile.ProfileCanonical, tt.req) if method != tt.name { t.Fatalf("dispatched method = %q, want %q", method, tt.name) } @@ -1353,12 +1354,12 @@ func dispatchExactLayerRPCTest( t *testing.T, r *Router, ctx context.Context, - profile tg.LayerProfile, + profile tlprofile.Profile, request bin.Object, -) (tg.LayerRPCResult, string) { +) (tlprofile.Result, string) { t.Helper() body := encodeExactLayerRPC(t, profile, request) - admitted, err := r.AdmitLayer(profile, &body, tg.LayerDecodeLimits{}) + admitted, err := r.AdmitLayer(profile, &body, tlprofile.Limits{}) if err != nil { t.Fatalf("admit exact Layer %d request: %v", profile, err) } @@ -1379,11 +1380,11 @@ 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 + profile tlprofile.Profile wireID uint32 }{ - {profile: tg.LayerProfile227, wireID: 0x4bc6589a}, - {profile: tg.LayerProfile228, wireID: 0x6126a43c}, + {profile: tlprofile.Profile227, wireID: 0x4bc6589a}, + {profile: tlprofile.Profile228, wireID: 0x6126a43c}, } { t.Run(fmt.Sprintf("layer_%d", tc.profile), func(t *testing.T) { request := &tg.MessagesSearchGlobalRequest{ @@ -1396,7 +1397,7 @@ func TestMessagesSearchGlobalExactLayerProfiles(t *testing.T) { 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{}) + admitted, err := r.AdmitLayer(tc.profile, &body, tlprofile.Limits{}) if err != nil { t.Fatalf("admit Layer %d searchGlobal: %v", tc.profile, err) } @@ -1404,7 +1405,7 @@ func TestMessagesSearchGlobalExactLayerProfiles(t *testing.T) { 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 { + if call.Profile() != tc.profile || call.WireID() != tc.wireID || call.Method() != tlprofile.SemanticMethodMessagesSearchGlobal { 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) @@ -1439,23 +1440,19 @@ func TestMessagesSearchGlobalCommunityProjectionFailsClosedForLayer227(t *testin 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) + body228 := encodeExactLayerRPC(t, tlprofile.Profile228, 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 { + if _, err := New(Config{}, Deps{}, zaptest.NewLogger(t), clock.System).AdmitLayer(tlprofile.Profile228, &body228, tlprofile.Limits{}); 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 { + if err := tlprofile.EncodeObject(tlprofile.Profile227, request, &body227); err == nil { t.Fatal("Layer 227 projection accepted a Layer 228-only community scope") } if body227.Len() != 0 { diff --git a/internal/rpc/rpc_testkit_helpers_test.go b/internal/rpc/rpc_testkit_helpers_test.go index 5592c241..ccf47b09 100644 --- a/internal/rpc/rpc_testkit_helpers_test.go +++ b/internal/rpc/rpc_testkit_helpers_test.go @@ -16,6 +16,17 @@ import ( "testing" ) +// dispatchCanonicalValue exposes the handler value behind tlprofile's exact +// result encoder. Object/class results already arrive as concrete tg values; +// primitive and Vector method results remain attached to the exact result +// plan because they are not bin.Object values. +func dispatchCanonicalValue(encoded bin.Encoder) any { + if result, ok := encoded.(interface{ CanonicalValue() any }); ok { + return result.CanonicalValue() + } + return encoded +} + type rpcChannelFixture struct { t *testing.T ctx context.Context @@ -111,8 +122,6 @@ func searchMessagesPayload(t *testing.T, enc bin.Encoder) ([]tg.MessageClass, [] return result.Messages, result.Chats, result.Users case *tg.MessagesChannelMessages: return result.Messages, result.Chats, result.Users - case *tg.MessagesMessagesBox: - return searchMessagesPayload(t, result.Messages) default: t.Fatalf("search result type = %T, want messages/messagesSlice", enc) return nil, nil, nil diff --git a/internal/rpc/stats.go b/internal/rpc/stats.go index 49a094fe..a8a4e754 100644 --- a/internal/rpc/stats.go +++ b/internal/rpc/stats.go @@ -6,6 +6,7 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) @@ -15,15 +16,31 @@ const ( maxStatsGraphTokenLength = 128 ) -func (r *Router) registerStats(d *tg.ServerDispatcher) { - d.OnStatsGetBroadcastStats(r.onStatsGetBroadcastStats) - d.OnStatsGetMegagroupStats(r.onStatsGetMegagroupStats) - d.OnStatsGetMessageStats(r.onStatsGetMessageStats) - d.OnStatsGetMessagePublicForwards(r.onStatsGetMessagePublicForwards) - d.OnStatsLoadAsyncGraph(r.onStatsLoadAsyncGraph) - d.OnStatsGetStoryStats(r.onStatsGetStoryStats) - d.OnStatsGetStoryPublicForwards(r.onStatsGetStoryPublicForwards) - d.OnStatsGetPollStats(r.onStatsGetPollStats) +func (r *Router) registerStats(d *tlprofile.Dispatcher) { + registerRPC[*tg.StatsGetBroadcastStatsRequest](d, tlprofile.SemanticMethodStatsGetBroadcastStats, func(ctx context.Context, layerRequest *tg.StatsGetBroadcastStatsRequest) (any, error) { + return r.onStatsGetBroadcastStats(ctx, layerRequest) + }) + registerRPC[*tg.StatsGetMegagroupStatsRequest](d, tlprofile.SemanticMethodStatsGetMegagroupStats, func(ctx context.Context, layerRequest *tg.StatsGetMegagroupStatsRequest) (any, error) { + return r.onStatsGetMegagroupStats(ctx, layerRequest) + }) + registerRPC[*tg.StatsGetMessageStatsRequest](d, tlprofile.SemanticMethodStatsGetMessageStats, func(ctx context.Context, layerRequest *tg.StatsGetMessageStatsRequest) (any, error) { + return r.onStatsGetMessageStats(ctx, layerRequest) + }) + registerRPC[*tg.StatsGetMessagePublicForwardsRequest](d, tlprofile.SemanticMethodStatsGetMessagePublicForwards, func(ctx context.Context, layerRequest *tg.StatsGetMessagePublicForwardsRequest) (any, error) { + return r.onStatsGetMessagePublicForwards(ctx, layerRequest) + }) + registerRPC[*tg.StatsLoadAsyncGraphRequest](d, tlprofile.SemanticMethodStatsLoadAsyncGraph, func(ctx context.Context, layerRequest *tg.StatsLoadAsyncGraphRequest) (any, error) { + return r.onStatsLoadAsyncGraph(ctx, layerRequest) + }) + registerRPC[*tg.StatsGetStoryStatsRequest](d, tlprofile.SemanticMethodStatsGetStoryStats, func(ctx context.Context, layerRequest *tg.StatsGetStoryStatsRequest) (any, error) { + return r.onStatsGetStoryStats(ctx, layerRequest) + }) + registerRPC[*tg.StatsGetStoryPublicForwardsRequest](d, tlprofile.SemanticMethodStatsGetStoryPublicForwards, func(ctx context.Context, layerRequest *tg.StatsGetStoryPublicForwardsRequest) (any, error) { + return r.onStatsGetStoryPublicForwards(ctx, layerRequest) + }) + registerRPC[*tg.StatsGetPollStatsRequest](d, tlprofile.SemanticMethodStatsGetPollStats, func(ctx context.Context, layerRequest *tg.StatsGetPollStatsRequest) (any, error) { + return r.onStatsGetPollStats(ctx, layerRequest) + }) } func (r *Router) onStatsGetBroadcastStats(ctx context.Context, req *tg.StatsGetBroadcastStatsRequest) (*tg.StatsBroadcastStats, error) { diff --git a/internal/rpc/sticker_link_smoke_test.go b/internal/rpc/sticker_link_smoke_test.go index 8fa64ac8..c8fc5cef 100644 --- a/internal/rpc/sticker_link_smoke_test.go +++ b/internal/rpc/sticker_link_smoke_test.go @@ -139,13 +139,9 @@ func TestCustomStickerPackLinkInstallAndSendSmoke(t *testing.T) { if err != nil { t.Fatalf("alice get history: %v", err) } - box, ok := enc.(*tg.MessagesMessagesBox) + messages, ok := enc.(*tg.MessagesMessages) if !ok { - t.Fatalf("history response = %T, want *tg.MessagesMessagesBox", enc) - } - messages, ok := box.Messages.(*tg.MessagesMessages) - if !ok { - t.Fatalf("history payload = %T, want *tg.MessagesMessages", box.Messages) + t.Fatalf("history response = %T, want *tg.MessagesMessages", enc) } if len(messages.Messages) != 1 { t.Fatalf("history messages = %d, want 1", len(messages.Messages)) diff --git a/internal/rpc/stickers_creator.go b/internal/rpc/stickers_creator.go index 2530330c..d63d3e15 100644 --- a/internal/rpc/stickers_creator.go +++ b/internal/rpc/stickers_creator.go @@ -6,18 +6,40 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) -func (r *Router) registerStickers(d *tg.ServerDispatcher) { - d.OnStickersCreateStickerSet(r.onStickersCreateStickerSet) - d.OnStickersCheckShortName(r.onStickersCheckShortName) - d.OnStickersSuggestShortName(r.onStickersSuggestShortName) - d.OnStickersAddStickerToSet(r.onStickersAddStickerToSet) - d.OnStickersRemoveStickerFromSet(r.onStickersRemoveStickerFromSet) - d.OnStickersChangeStickerPosition(r.onStickersChangeStickerPosition) - d.OnStickersRenameStickerSet(r.onStickersRenameStickerSet) - d.OnStickersDeleteStickerSet(r.onStickersDeleteStickerSet) +func (r *Router) registerStickers(d *tlprofile.Dispatcher) { + registerRPC[*tg.StickersCreateStickerSetRequest](d, tlprofile.SemanticMethodStickersCreateStickerSet, func(ctx context.Context, layerRequest *tg.StickersCreateStickerSetRequest) (any, error) { + return r.onStickersCreateStickerSet(ctx, layerRequest) + }) + registerRPC[*tg.StickersCheckShortNameRequest](d, tlprofile.SemanticMethodStickersCheckShortName, func(ctx context.Context, layerRequest *tg.StickersCheckShortNameRequest) (any, error) { + return r.onStickersCheckShortName(ctx, layerRequest. + ShortName) + }) + registerRPC[*tg.StickersSuggestShortNameRequest](d, tlprofile.SemanticMethodStickersSuggestShortName, func(ctx context.Context, layerRequest *tg.StickersSuggestShortNameRequest) (any, error) { + return r.onStickersSuggestShortName(ctx, layerRequest. + Title) + }) + registerRPC[*tg.StickersAddStickerToSetRequest](d, tlprofile.SemanticMethodStickersAddStickerToSet, func(ctx context.Context, layerRequest *tg.StickersAddStickerToSetRequest) (any, error) { + return r.onStickersAddStickerToSet(ctx, layerRequest) + }) + registerRPC[*tg.StickersRemoveStickerFromSetRequest](d, tlprofile.SemanticMethodStickersRemoveStickerFromSet, func(ctx context.Context, layerRequest *tg.StickersRemoveStickerFromSetRequest) (any, error) { + return r.onStickersRemoveStickerFromSet(ctx, layerRequest. + Sticker) + }) + registerRPC[*tg.StickersChangeStickerPositionRequest](d, tlprofile.SemanticMethodStickersChangeStickerPosition, func(ctx context.Context, layerRequest *tg.StickersChangeStickerPositionRequest) (any, error) { + return r.onStickersChangeStickerPosition(ctx, layerRequest) + }) + registerRPC[*tg.StickersRenameStickerSetRequest](d, tlprofile.SemanticMethodStickersRenameStickerSet, func(ctx context.Context, layerRequest *tg.StickersRenameStickerSetRequest) (any, error) { + return r.onStickersRenameStickerSet(ctx, layerRequest) + }) + registerRPC[*tg.StickersDeleteStickerSetRequest](d, tlprofile.SemanticMethodStickersDeleteStickerSet, func(ctx context.Context, layerRequest *tg.StickersDeleteStickerSetRequest) (any, error) { + return r.onStickersDeleteStickerSet(ctx, layerRequest. + Stickerset) + }) + } func (r *Router) onStickersCreateStickerSet(ctx context.Context, req *tg.StickersCreateStickerSetRequest) (tg.MessagesStickerSetClass, error) { diff --git a/internal/rpc/stories.go b/internal/rpc/stories.go index 7424d515..c4ab37d8 100644 --- a/internal/rpc/stories.go +++ b/internal/rpc/stories.go @@ -12,6 +12,7 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" ) @@ -27,40 +28,110 @@ const ( ) // registerStories 注册 TDesktop/Android 已发现的 stories.* RPC。 -func (r *Router) registerStories(d *tg.ServerDispatcher) { - d.OnStoriesGetAllStories(r.onStoriesGetAllStories) - d.OnStoriesGetPeerStories(r.onStoriesGetPeerStories) - d.OnStoriesGetStoriesByID(r.onStoriesGetStoriesByID) - d.OnStoriesGetStoriesArchive(r.onStoriesGetStoriesArchive) - d.OnStoriesGetPinnedStories(r.onStoriesGetPinnedStories) - d.OnStoriesExportStoryLink(r.onStoriesExportStoryLink) - d.OnStoriesReport(r.onStoriesReport) - d.OnStoriesActivateStealthMode(r.onStoriesActivateStealthMode) - d.OnStoriesSearchPosts(r.onStoriesSearchPosts) - d.OnStoriesSendStory(r.onStoriesSendStory) - d.OnStoriesEditStory(r.onStoriesEditStory) - d.OnStoriesDeleteStories(r.onStoriesDeleteStories) - d.OnStoriesTogglePinned(r.onStoriesTogglePinned) - d.OnStoriesTogglePinnedToTop(r.onStoriesTogglePinnedToTop) - d.OnStoriesToggleAllStoriesHidden(r.onStoriesToggleAllStoriesHidden) - d.OnStoriesCreateAlbum(r.onStoriesCreateAlbum) - d.OnStoriesUpdateAlbum(r.onStoriesUpdateAlbum) - d.OnStoriesReorderAlbums(r.onStoriesReorderAlbums) - d.OnStoriesDeleteAlbum(r.onStoriesDeleteAlbum) - d.OnStoriesGetAlbums(r.onStoriesGetAlbums) - d.OnStoriesGetAlbumStories(r.onStoriesGetAlbumStories) - d.OnStoriesGetAllReadPeerStories(r.onStoriesGetAllReadPeerStories) - d.OnStoriesGetPeerMaxIDs(r.onStoriesGetPeerMaxIDs) - d.OnStoriesReadStories(r.onStoriesReadStories) - d.OnStoriesIncrementStoryViews(r.onStoriesIncrementStoryViews) - d.OnStoriesGetStoriesViews(r.onStoriesGetStoriesViews) - d.OnStoriesGetStoryViewsList(r.onStoriesGetStoryViewsList) - d.OnStoriesGetStoryReactionsList(r.onStoriesGetStoryReactionsList) - d.OnStoriesTogglePeerStoriesHidden(r.onStoriesTogglePeerStoriesHidden) - d.OnStoriesCanSendStory(r.onStoriesCanSendStory) - d.OnStoriesGetChatsToSend(r.onStoriesGetChatsToSend) - d.OnStoriesSendReaction(r.onStoriesSendReaction) - d.OnStoriesStartLive(r.onStoriesStartLive) +func (r *Router) registerStories(d *tlprofile.Dispatcher) { + registerRPC[*tg.StoriesGetAllStoriesRequest](d, tlprofile.SemanticMethodStoriesGetAllStories, func(ctx context.Context, layerRequest *tg.StoriesGetAllStoriesRequest) (any, error) { + return r.onStoriesGetAllStories(ctx, layerRequest) + }) + registerRPC[*tg.StoriesGetPeerStoriesRequest](d, tlprofile.SemanticMethodStoriesGetPeerStories, func(ctx context.Context, layerRequest *tg.StoriesGetPeerStoriesRequest) (any, error) { + return r.onStoriesGetPeerStories(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.StoriesGetStoriesByIDRequest](d, tlprofile.SemanticMethodStoriesGetStoriesByID, func(ctx context.Context, layerRequest *tg.StoriesGetStoriesByIDRequest) (any, error) { + return r.onStoriesGetStoriesByID(ctx, layerRequest) + }) + registerRPC[*tg.StoriesGetStoriesArchiveRequest](d, tlprofile.SemanticMethodStoriesGetStoriesArchive, func(ctx context.Context, layerRequest *tg.StoriesGetStoriesArchiveRequest) (any, error) { + return r.onStoriesGetStoriesArchive(ctx, layerRequest) + }) + registerRPC[*tg.StoriesGetPinnedStoriesRequest](d, tlprofile.SemanticMethodStoriesGetPinnedStories, func(ctx context.Context, layerRequest *tg.StoriesGetPinnedStoriesRequest) (any, error) { + return r.onStoriesGetPinnedStories(ctx, layerRequest) + }) + registerRPC[*tg.StoriesExportStoryLinkRequest](d, tlprofile.SemanticMethodStoriesExportStoryLink, func(ctx context.Context, layerRequest *tg.StoriesExportStoryLinkRequest) (any, error) { + return r.onStoriesExportStoryLink(ctx, layerRequest) + }) + registerRPC[*tg.StoriesReportRequest](d, tlprofile.SemanticMethodStoriesReport, func(ctx context.Context, layerRequest *tg.StoriesReportRequest) (any, error) { + return r.onStoriesReport(ctx, layerRequest) + }) + registerRPC[*tg.StoriesActivateStealthModeRequest](d, tlprofile.SemanticMethodStoriesActivateStealthMode, func(ctx context.Context, layerRequest *tg.StoriesActivateStealthModeRequest) (any, error) { + return r.onStoriesActivateStealthMode(ctx, layerRequest) + }) + registerRPC[*tg.StoriesSearchPostsRequest](d, tlprofile.SemanticMethodStoriesSearchPosts, func(ctx context.Context, layerRequest *tg.StoriesSearchPostsRequest) (any, error) { + return r.onStoriesSearchPosts(ctx, layerRequest) + }) + registerRPC[*tg.StoriesSendStoryRequest](d, tlprofile.SemanticMethodStoriesSendStory, func(ctx context.Context, layerRequest *tg.StoriesSendStoryRequest) (any, error) { + return r.onStoriesSendStory(ctx, layerRequest) + }) + registerRPC[*tg.StoriesEditStoryRequest](d, tlprofile.SemanticMethodStoriesEditStory, func(ctx context.Context, layerRequest *tg.StoriesEditStoryRequest) (any, error) { + return r.onStoriesEditStory(ctx, layerRequest) + }) + registerRPC[*tg.StoriesDeleteStoriesRequest](d, tlprofile.SemanticMethodStoriesDeleteStories, func(ctx context.Context, layerRequest *tg.StoriesDeleteStoriesRequest) (any, error) { + return r.onStoriesDeleteStories(ctx, layerRequest) + }) + registerRPC[*tg.StoriesTogglePinnedRequest](d, tlprofile.SemanticMethodStoriesTogglePinned, func(ctx context.Context, layerRequest *tg.StoriesTogglePinnedRequest) (any, error) { + return r.onStoriesTogglePinned(ctx, layerRequest) + }) + registerRPC[*tg.StoriesTogglePinnedToTopRequest](d, tlprofile.SemanticMethodStoriesTogglePinnedToTop, func(ctx context.Context, layerRequest *tg.StoriesTogglePinnedToTopRequest) (any, error) { + return r.onStoriesTogglePinnedToTop(ctx, layerRequest) + }) + registerRPC[*tg.StoriesToggleAllStoriesHiddenRequest](d, tlprofile.SemanticMethodStoriesToggleAllStoriesHidden, func(ctx context.Context, layerRequest *tg.StoriesToggleAllStoriesHiddenRequest) (any, error) { + return r.onStoriesToggleAllStoriesHidden(ctx, layerRequest. + Hidden) + }) + registerRPC[*tg.StoriesCreateAlbumRequest](d, tlprofile.SemanticMethodStoriesCreateAlbum, func(ctx context.Context, layerRequest *tg.StoriesCreateAlbumRequest) (any, error) { + return r.onStoriesCreateAlbum(ctx, layerRequest) + }) + registerRPC[*tg.StoriesUpdateAlbumRequest](d, tlprofile.SemanticMethodStoriesUpdateAlbum, func(ctx context.Context, layerRequest *tg.StoriesUpdateAlbumRequest) (any, error) { + return r.onStoriesUpdateAlbum(ctx, layerRequest) + }) + registerRPC[*tg.StoriesReorderAlbumsRequest](d, tlprofile.SemanticMethodStoriesReorderAlbums, func(ctx context.Context, layerRequest *tg.StoriesReorderAlbumsRequest) (any, error) { + return r.onStoriesReorderAlbums(ctx, layerRequest) + }) + registerRPC[*tg.StoriesDeleteAlbumRequest](d, tlprofile.SemanticMethodStoriesDeleteAlbum, func(ctx context.Context, layerRequest *tg.StoriesDeleteAlbumRequest) (any, error) { + return r.onStoriesDeleteAlbum(ctx, layerRequest) + }) + registerRPC[*tg.StoriesGetAlbumsRequest](d, tlprofile.SemanticMethodStoriesGetAlbums, func(ctx context.Context, layerRequest *tg.StoriesGetAlbumsRequest) (any, error) { + return r.onStoriesGetAlbums(ctx, layerRequest) + }) + registerRPC[*tg.StoriesGetAlbumStoriesRequest](d, tlprofile.SemanticMethodStoriesGetAlbumStories, func(ctx context.Context, layerRequest *tg.StoriesGetAlbumStoriesRequest) (any, error) { + return r.onStoriesGetAlbumStories(ctx, layerRequest) + }) + registerRPC[*tg.StoriesGetAllReadPeerStoriesRequest](d, tlprofile.SemanticMethodStoriesGetAllReadPeerStories, func(ctx context.Context, layerRequest *tg.StoriesGetAllReadPeerStoriesRequest) (any, error) { + return r.onStoriesGetAllReadPeerStories(ctx) + }) + registerRPC[*tg.StoriesGetPeerMaxIDsRequest](d, tlprofile.SemanticMethodStoriesGetPeerMaxIDs, func(ctx context.Context, layerRequest *tg.StoriesGetPeerMaxIDsRequest) (any, error) { + return r.onStoriesGetPeerMaxIDs(ctx, layerRequest. + ID) + }) + registerRPC[*tg.StoriesReadStoriesRequest](d, tlprofile.SemanticMethodStoriesReadStories, func(ctx context.Context, layerRequest *tg.StoriesReadStoriesRequest) (any, error) { + return r.onStoriesReadStories(ctx, layerRequest) + }) + registerRPC[*tg.StoriesIncrementStoryViewsRequest](d, tlprofile.SemanticMethodStoriesIncrementStoryViews, func(ctx context.Context, layerRequest *tg.StoriesIncrementStoryViewsRequest) (any, error) { + return r.onStoriesIncrementStoryViews(ctx, layerRequest) + }) + registerRPC[*tg.StoriesGetStoriesViewsRequest](d, tlprofile.SemanticMethodStoriesGetStoriesViews, func(ctx context.Context, layerRequest *tg.StoriesGetStoriesViewsRequest) (any, error) { + return r.onStoriesGetStoriesViews(ctx, layerRequest) + }) + registerRPC[*tg.StoriesGetStoryViewsListRequest](d, tlprofile.SemanticMethodStoriesGetStoryViewsList, func(ctx context.Context, layerRequest *tg.StoriesGetStoryViewsListRequest) (any, error) { + return r.onStoriesGetStoryViewsList(ctx, layerRequest) + }) + registerRPC[*tg.StoriesGetStoryReactionsListRequest](d, tlprofile.SemanticMethodStoriesGetStoryReactionsList, func(ctx context.Context, layerRequest *tg.StoriesGetStoryReactionsListRequest) (any, error) { + return r.onStoriesGetStoryReactionsList(ctx, layerRequest) + }) + registerRPC[*tg.StoriesTogglePeerStoriesHiddenRequest](d, tlprofile.SemanticMethodStoriesTogglePeerStoriesHidden, func(ctx context.Context, layerRequest *tg.StoriesTogglePeerStoriesHiddenRequest) (any, error) { + return r.onStoriesTogglePeerStoriesHidden(ctx, layerRequest) + }) + registerRPC[*tg.StoriesCanSendStoryRequest](d, tlprofile.SemanticMethodStoriesCanSendStory, func(ctx context.Context, layerRequest *tg.StoriesCanSendStoryRequest) (any, error) { + return r.onStoriesCanSendStory(ctx, layerRequest. + Peer) + }) + registerRPC[*tg.StoriesGetChatsToSendRequest](d, tlprofile.SemanticMethodStoriesGetChatsToSend, func(ctx context.Context, layerRequest *tg.StoriesGetChatsToSendRequest) (any, error) { + return r.onStoriesGetChatsToSend(ctx) + }) + registerRPC[*tg.StoriesSendReactionRequest](d, tlprofile.SemanticMethodStoriesSendReaction, func(ctx context.Context, layerRequest *tg.StoriesSendReactionRequest) (any, error) { + return r.onStoriesSendReaction(ctx, layerRequest) + }) + registerRPC[*tg.StoriesStartLiveRequest](d, tlprofile.SemanticMethodStoriesStartLive, func(ctx context.Context, layerRequest *tg.StoriesStartLiveRequest) (any, error) { + return r.onStoriesStartLive(ctx, layerRequest) + }) } func (r *Router) onStoriesGetAllStories(ctx context.Context, req *tg.StoriesGetAllStoriesRequest) (tg.StoriesAllStoriesClass, error) { diff --git a/internal/rpc/story_peer_projection_rpc_test.go b/internal/rpc/story_peer_projection_rpc_test.go index f7faf087..0c050a79 100644 --- a/internal/rpc/story_peer_projection_rpc_test.go +++ b/internal/rpc/story_peer_projection_rpc_test.go @@ -1534,9 +1534,6 @@ func dispatchMessagesPayload(t *testing.T, r *Router, ctx context.Context, req b if err != nil { t.Fatalf("dispatch: %v", err) } - if box, ok := out.(*tg.MessagesMessagesBox); ok { - return box.Messages - } return out } diff --git a/internal/rpc/updates.go b/internal/rpc/updates.go index 9c6f7218..49bc8940 100644 --- a/internal/rpc/updates.go +++ b/internal/rpc/updates.go @@ -5,21 +5,28 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) // registerUpdates 注册 updates.* RPC handler。 -func (r *Router) registerUpdates(d *tg.ServerDispatcher) { - d.OnUpdatesGetState(r.onUpdatesGetState) - d.OnUpdatesGetDifference(r.onUpdatesGetDifference) +func (r *Router) registerUpdates(d *tlprofile.Dispatcher) { + registerRPC[*tg.UpdatesGetStateRequest](d, tlprofile.SemanticMethodUpdatesGetState, func(ctx context.Context, layerRequest *tg.UpdatesGetStateRequest) ( + + // onUpdatesGetState 处理 updates.getState。TDesktop 与 DrKLO 的启动路径把它当作 + // 「从当前快照开始同步」的显式 baseline:返回账号当前连续水位,并且只在 rpc_result + // 物理交付后原子推进该设备 confirmed + observed。对尚未审计 baseline 语义的客户端 + // 仍返回同一 current state,但交付后只推进 confirmed;这保留 observed/durable + // difference tail,避免把 TDesktop/DrKLO 的兼容例外扩散成所有客户端都能跨过未实际 + // 确认事件的 retention 后门。 + any, error) { + return r.onUpdatesGetState(ctx) + }) + registerRPC[*tg.UpdatesGetDifferenceRequest](d, tlprofile.SemanticMethodUpdatesGetDifference, func(ctx context.Context, layerRequest *tg.UpdatesGetDifferenceRequest) (any, error) { + return r.onUpdatesGetDifference(ctx, layerRequest) + }) } -// onUpdatesGetState 处理 updates.getState。TDesktop 与 DrKLO 的启动路径把它当作 -// 「从当前快照开始同步」的显式 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) { userID, _, err := r.currentUserID(ctx) if err != nil { diff --git a/internal/rpc/upload.go b/internal/rpc/upload.go index 1bf0b813..c6e2901a 100644 --- a/internal/rpc/upload.go +++ b/internal/rpc/upload.go @@ -9,6 +9,7 @@ import ( "github.com/iamxvbaba/td/tg" "go.uber.org/zap" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) @@ -17,11 +18,19 @@ import ( const maxUploadGetFileChunkLimit = 1 << 20 // registerUpload 注册 upload.* RPC handler(分片上传 + 文件下载 + 地图 webfile)。 -func (r *Router) registerUpload(d *tg.ServerDispatcher) { - d.OnUploadSaveFilePart(r.onUploadSaveFilePart) - d.OnUploadSaveBigFilePart(r.onUploadSaveBigFilePart) - d.OnUploadGetFile(r.onUploadGetFile) - d.OnUploadGetFileHashes(r.onUploadGetFileHashes) +func (r *Router) registerUpload(d *tlprofile.Dispatcher) { + registerRPC[*tg.UploadSaveFilePartRequest](d, tlprofile.SemanticMethodUploadSaveFilePart, func(ctx context.Context, layerRequest *tg.UploadSaveFilePartRequest) (any, error) { + return r.onUploadSaveFilePart(ctx, layerRequest) + }) + registerRPC[*tg.UploadSaveBigFilePartRequest](d, tlprofile.SemanticMethodUploadSaveBigFilePart, func(ctx context.Context, layerRequest *tg.UploadSaveBigFilePartRequest) (any, error) { + return r.onUploadSaveBigFilePart(ctx, layerRequest) + }) + registerRPC[*tg.UploadGetFileRequest](d, tlprofile.SemanticMethodUploadGetFile, func(ctx context.Context, layerRequest *tg.UploadGetFileRequest) (any, error) { + return r.onUploadGetFile(ctx, layerRequest) + }) + registerRPC[*tg.UploadGetFileHashesRequest](d, tlprofile.SemanticMethodUploadGetFileHashes, func(ctx context.Context, layerRequest *tg.UploadGetFileHashesRequest) (any, error) { + return r.onUploadGetFileHashes(ctx, layerRequest) + }) r.registerUploadWebFile(d) } diff --git a/internal/rpc/upload_webfile.go b/internal/rpc/upload_webfile.go index 6b7f4995..d1275e16 100644 --- a/internal/rpc/upload_webfile.go +++ b/internal/rpc/upload_webfile.go @@ -13,6 +13,7 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/domain" ) @@ -39,8 +40,10 @@ type inlineWebFileFetcher func(ctx context.Context, document domain.BotInlineWeb var fetchInlineWebFile inlineWebFileFetcher = defaultFetchInlineWebFile -func (r *Router) registerUploadWebFile(d *tg.ServerDispatcher) { - d.OnUploadGetWebFile(r.onUploadGetWebFile) +func (r *Router) registerUploadWebFile(d *tlprofile.Dispatcher) { + registerRPC[*tg.UploadGetWebFileRequest](d, tlprofile.SemanticMethodUploadGetWebFile, func(ctx context.Context, layerRequest *tg.UploadGetWebFileRequest) (any, error) { + return r.onUploadGetWebFile(ctx, layerRequest) + }) } func (r *Router) onUploadGetWebFile(ctx context.Context, req *tg.UploadGetWebFileRequest) (*tg.UploadWebFile, error) { diff --git a/internal/rpc/users.go b/internal/rpc/users.go index 2df0f6da..34f29418 100644 --- a/internal/rpc/users.go +++ b/internal/rpc/users.go @@ -6,6 +6,7 @@ import ( "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tlprofile" "telesrv/internal/app/users" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" @@ -15,15 +16,30 @@ const maxSavedMusicLimit = 100 const maxRequirementsToContactUsers = 100 // registerUsers 注册 users.* RPC handler。 -func (r *Router) registerUsers(d *tg.ServerDispatcher) { - d.OnUsersGetUsers(r.onUsersGetUsers) - d.OnUsersGetFullUser(r.onUsersGetFullUser) - d.OnUsersGetRequirementsToContact(r.onUsersGetRequirementsToContact) - d.OnUsersGetSavedMusic(r.onUsersGetSavedMusic) - d.OnUsersGetSavedMusicByID(r.onUsersGetSavedMusicByID) +func (r *Router) registerUsers(d *tlprofile.Dispatcher) { + registerRPC[*tg.UsersGetUsersRequest](d, tlprofile.SemanticMethodUsersGetUsers, func(ctx context.Context, layerRequest *tg.UsersGetUsersRequest) (any, error) { + return r.onUsersGetUsers(ctx, layerRequest. + ID) + }) + registerRPC[*tg.UsersGetFullUserRequest](d, tlprofile.SemanticMethodUsersGetFullUser, func(ctx context.Context, layerRequest *tg.UsersGetFullUserRequest) (any, error) { + return r.onUsersGetFullUser(ctx, layerRequest. + ID) + }) + registerRPC[*tg.UsersGetRequirementsToContactRequest](d, tlprofile.SemanticMethodUsersGetRequirementsToContact, func(ctx context.Context, layerRequest *tg.UsersGetRequirementsToContactRequest) (any, error) { + return r.onUsersGetRequirementsToContact(ctx, layerRequest. + ID) + }) + registerRPC[*tg.UsersGetSavedMusicRequest](d, tlprofile.SemanticMethodUsersGetSavedMusic, func(ctx context.Context, layerRequest *tg.UsersGetSavedMusicRequest) ( + + // onUsersGetUsers 处理 users.getUsers:支持 self 和已知 user peer(含 777000 官方账号)。 + any, error) { + return r.onUsersGetSavedMusic(ctx, layerRequest) + }) + registerRPC[*tg.UsersGetSavedMusicByIDRequest](d, tlprofile.SemanticMethodUsersGetSavedMusicByID, func(ctx context.Context, layerRequest *tg.UsersGetSavedMusicByIDRequest) (any, error) { + return r.onUsersGetSavedMusicByID(ctx, layerRequest) + }) } -// onUsersGetUsers 处理 users.getUsers:支持 self 和已知 user peer(含 777000 官方账号)。 func (r *Router) onUsersGetUsers(ctx context.Context, ids []tg.InputUserClass) ([]tg.UserClass, error) { currentUserID, authorized, err := r.currentUserID(ctx) if err != nil {