feat: sync multilayer td integration

This commit is contained in:
A 2026-07-15 13:32:06 +08:00
parent 20a310f6ca
commit 766c5db992
491 changed files with 26235 additions and 35340 deletions

View file

@ -5,7 +5,7 @@ import (
"errors"
"strings"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
ioscompat "telesrv/internal/compat/ios"
"telesrv/internal/compat/tdesktop"

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,8 +10,8 @@ import (
"go.uber.org/zap"
"github.com/gotd/td/proto"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/proto"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/app/auth"
"telesrv/internal/domain"
@ -54,6 +54,12 @@ func (r *Router) registerAuth(d *tg.ServerDispatcher) {
// onAuthBindTempAuthKey 记录 TDesktop 的 PFS temp→perm auth key 绑定。
func (r *Router) onAuthBindTempAuthKey(ctx context.Context, req *tg.AuthBindTempAuthKeyRequest) (bool, error) {
if !layerRPCProfileEvidenceFresh(ctx) {
// The inner request is outside MTProto's mutable msg_id window. It may be
// decoded request-locally, but acknowledging it would mutate the durable
// temp→perm identity and every live session from stale replay evidence.
return false, bindTempAuthKeyErr(auth.ErrTempAuthKeyEmpty)
}
if r.deps.Auth == nil {
return true, nil
}
@ -71,23 +77,95 @@ func (r *Router) onAuthBindTempAuthKey(ctx context.Context, req *tg.AuthBindTemp
}); err != nil {
return false, bindTempAuthKeyErr(err)
}
permID := authKeyIDFromInt64(req.PermAuthKeyID)
// temp key (re)bind 后立即作废其 temp→perm 解析缓存,确保下一帧按新绑定重新解析,
// 不被 TTL 内的旧 perm 缓存命中(防跨账号串号)。
if id != ([8]byte{}) {
r.tempKeyResolveCache.Delete(id)
}
// Save atomically merged raw/permanent Layer observations. Both identities
// must now re-read that durable permanent primary; pre-bind process caches
// are not ordering evidence and cannot overwrite the transaction's winner.
r.invalidateAuthUserCache(id)
r.invalidateAuthUserCache(permID)
unlockLayerCommit := r.lockAuthLayerCommit(id, permID)
defer unlockLayerCommit()
r.invalidateBoundAuthKeyLayerResolution(id, permID)
if r.deps.Sessions != nil {
permID := authKeyIDFromInt64(req.PermAuthKeyID)
if all, ok := r.deps.Sessions.(RawAuthKeySessionBinder); ok {
all.BindAuthKeyForRawAuthKey(id, permID)
} else {
r.deps.Sessions.BindAuthKeyForSession(id, sessionID, permID)
}
}
r.invalidateAuthUserCache(id)
layer, _, err := r.resolveAuthKeyLayerDefault(ctx, permID)
if err != nil {
if clearer, ok := r.deps.Sessions.(AuthKeyInheritedLayerClearer); ok {
clearer.ClearInheritedLayerForRawAuthKey(id)
}
if r.log != nil {
r.log.Warn("reload merged permanent layer after temp auth key bind failed",
zap.String("raw_auth_key_id", fmt.Sprintf("%x", id[:])),
zap.String("perm_auth_key_id", fmt.Sprintf("%x", permID[:])),
zap.Error(err))
}
return false, internalErr()
}
r.cacheBoundAuthKeyLayerResolution(id, permID)
if isSupportedLayer(layer) {
if refresher, ok := r.deps.Sessions.(AuthKeyLayerRefresher); ok {
refresher.RefreshInheritedLayerForRawAuthKey(id, layer)
} else if binder, ok := r.deps.Sessions.(AuthKeyLayerBinder); ok {
binder.SeedInheritedLayerForRawAuthKey(id, layer)
}
} else if clearer, ok := r.deps.Sessions.(AuthKeyInheritedLayerClearer); ok {
clearer.ClearInheritedLayerForRawAuthKey(id)
}
return true, nil
}
func (r *Router) invalidateBoundAuthKeyLayerResolution(authKeyIDs ...[8]byte) {
r.clientInfoMu.Lock()
defer r.clientInfoMu.Unlock()
for _, authKeyID := range authKeyIDs {
if info, ok := r.authInfo[authKeyID]; ok {
info.layer = 0
info.layerObservationID = 0
info.layerAdmissionSeq = 0
info.authKeyInfoChecked = false
info.authorizationChecked = false
info.layerBlocked = false
info.layerBlockedByAuthKey = false
r.authInfo[authKeyID] = info
}
}
}
func (r *Router) cacheBoundAuthKeyLayerResolution(rawAuthKeyID, permAuthKeyID [8]byte) {
r.clientInfoMu.Lock()
defer r.clientInfoMu.Unlock()
if r.authInfo == nil {
r.authInfo = make(map[[8]byte]clientSessionInfo)
}
if _, exists := r.authInfo[rawAuthKeyID]; !exists {
evictMapEntryIfFullLocked(r.authInfo, maxAuthInfoEntries)
}
canonical := r.authInfo[permAuthKeyID]
info := r.authInfo[rawAuthKeyID]
// The bind transaction made the permanent row authoritative for both
// identities. Copy its complete resolution tuple: a Layer without the same
// observation token (or a stale blocked bit) would let later cache merging
// manufacture an ordering state that never existed durably.
info.layer = canonical.layer
info.layerObservationID = canonical.layerObservationID
info.layerAdmissionSeq = canonical.layerAdmissionSeq
info.layerBlocked = canonical.layerBlocked
info.layerBlockedByAuthKey = canonical.layerBlockedByAuthKey
info.authKeyInfoChecked = canonical.authKeyInfoChecked
info.authorizationChecked = canonical.authorizationChecked
r.authInfo[rawAuthKeyID] = info
}
// onAuthExportLoginToken 给 QR 登录请求方返回短期 token扫码端接受后同一目标
// session 后续 export 会升级为 auth.loginTokenSuccess。
func (r *Router) onAuthExportLoginToken(ctx context.Context, req *tg.AuthExportLoginTokenRequest) (tg.AuthLoginTokenClass, error) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,10 +2,10 @@ package rpc
import (
"context"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap/zaptest"
"strconv"
"strings"

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,10 +2,10 @@ package rpc
import (
"context"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/proto"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/proto"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"strconv"
"strings"

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
package rpc
import (
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
)
// registerChannels 注册超级群/频道相关 RPC。messages.createChat 在这里注册,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -7,7 +7,7 @@ import (
"strings"
"unicode/utf8"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap"
"telesrv/internal/app/contacts"

View file

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

View file

@ -2,9 +2,9 @@ package rpc
import (
"context"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"reflect"
"strings"

View file

@ -4,6 +4,8 @@ import (
"context"
"regexp"
"strings"
"github.com/iamxvbaba/td/tg"
)
type ctxKey int
@ -31,7 +33,7 @@ func inboundRPCBytesFrom(ctx context.Context) int {
return v
}
const currentClientLayer = 227
const currentClientLayer = tg.Layer
var androidSDKVersionRE = regexp.MustCompile(`\bsdk\s+\d+\b`)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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