Initial open source release
This commit is contained in:
commit
74992e893f
377 changed files with 118084 additions and 0 deletions
114
internal/mtprotoedge/conn.go
Normal file
114
internal/mtprotoedge/conn.go
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
package mtprotoedge
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/gotd/td/bin"
|
||||
"github.com/gotd/td/crypto"
|
||||
"github.com/gotd/td/proto"
|
||||
"github.com/gotd/td/transport"
|
||||
)
|
||||
|
||||
// Conn 是一个已识别 session 的客户端连接,持有向其加密发送消息所需的全部上下文。
|
||||
// 由 SessionManager 管理,供请求响应与主动 push 共用。
|
||||
//
|
||||
// Send 并发安全:所有出站消息先进 per-Conn outbound actor,由它串行分配 msg_id/seq_no、
|
||||
// 加密并写 transport,避免高并发 RPC 响应与 push 交错造成 MTProto 顺序错误。
|
||||
type outboundWriter interface {
|
||||
Send(context.Context, *bin.Buffer) error
|
||||
}
|
||||
|
||||
type Conn struct {
|
||||
transport transport.Conn
|
||||
writer outboundWriter
|
||||
cipher crypto.Cipher
|
||||
msgID *proto.MessageIDGen
|
||||
writeTimeout time.Duration
|
||||
metrics Metrics
|
||||
|
||||
authKeyID [8]byte
|
||||
sessionID int64
|
||||
salt int64
|
||||
key crypto.AuthKey
|
||||
|
||||
outbound chan outboundOp
|
||||
outboundControl chan outboundOp
|
||||
outboundStop chan struct{}
|
||||
outboundDone chan struct{}
|
||||
outboundClose sync.Once
|
||||
|
||||
rpcQueue chan inboundRPC
|
||||
rpcStop chan struct{}
|
||||
rpcCancel context.CancelFunc
|
||||
rpcClose sync.Once
|
||||
rpcWG sync.WaitGroup
|
||||
rpcTimeout time.Duration
|
||||
// inflightRPCBytes 跟踪已入队未完成的 inbound RPC body 总字节,配合 maxInflightRPCBytes
|
||||
// 给 RPC 队列设字节预算(不止限条数),防对抗客户端发大请求撑内存。
|
||||
inflightRPCBytes atomic.Int64
|
||||
// RPC worker 懒启动:首个 RPC 入队时才起 worker(ensureInboundRPCWorkers),
|
||||
// 避免握手后静默 / 纯推送目标连接白白钉住 rpcMaxInflight 个 goroutine。
|
||||
rpcRootCtx context.Context
|
||||
rpcMaxInflight int
|
||||
rpcWorkersOnce sync.Once
|
||||
|
||||
// sentContentMessages 只由 outbound actor 访问,用于生成 MTProto seq_no。
|
||||
sentContentMessages int32
|
||||
|
||||
identityMu sync.RWMutex
|
||||
businessAuthKeyID [8]byte
|
||||
businessAuthKeyResolved bool
|
||||
userID atomic.Int64
|
||||
userIDResolved atomic.Bool
|
||||
receivesUpdates atomic.Bool
|
||||
}
|
||||
|
||||
// AuthKeyID 返回连接的 auth_key_id。
|
||||
func (c *Conn) AuthKeyID() [8]byte { return c.authKeyID }
|
||||
|
||||
// BusinessAuthKeyID 返回业务视角的 auth_key_id。
|
||||
//
|
||||
// temp auth_key 绑定后解析为 perm auth_key;第二个返回值表示本连接是否已完成解析,
|
||||
// 即便解析结果等于原始 auth_key_id 也会返回 true,以避免每个 RPC 重复查绑定表。
|
||||
func (c *Conn) BusinessAuthKeyID() ([8]byte, bool) {
|
||||
c.identityMu.RLock()
|
||||
defer c.identityMu.RUnlock()
|
||||
return c.businessAuthKeyID, c.businessAuthKeyResolved
|
||||
}
|
||||
|
||||
// SetBusinessAuthKeyID 缓存业务视角 auth_key_id。
|
||||
func (c *Conn) SetBusinessAuthKeyID(id [8]byte) {
|
||||
c.identityMu.Lock()
|
||||
changed := !c.businessAuthKeyResolved || c.businessAuthKeyID != id
|
||||
c.businessAuthKeyID = id
|
||||
c.businessAuthKeyResolved = true
|
||||
c.identityMu.Unlock()
|
||||
if changed {
|
||||
c.userID.Store(0)
|
||||
c.userIDResolved.Store(false)
|
||||
}
|
||||
}
|
||||
|
||||
// SessionID 返回连接的 session_id。
|
||||
func (c *Conn) SessionID() int64 { return c.sessionID }
|
||||
|
||||
// UserID 返回绑定的用户 id;未登录为 0。
|
||||
func (c *Conn) UserID() int64 { return c.userID.Load() }
|
||||
|
||||
// UserIDResolved 返回 user_id 授权状态是否已为当前连接解析过。
|
||||
//
|
||||
// resolved=true 且 userID=0 表示该 auth_key 当前未登录;这样登录前的多次 RPC
|
||||
// 不会反复查询授权表,后续登录成功会由 BindUser 覆盖为真实用户。
|
||||
func (c *Conn) UserIDResolved() (userID int64, resolved bool) {
|
||||
return c.userID.Load(), c.userIDResolved.Load()
|
||||
}
|
||||
|
||||
// ReceivesUpdates 报告该连接是否接收主动推送的 updates。
|
||||
func (c *Conn) ReceivesUpdates() bool { return c.receivesUpdates.Load() }
|
||||
|
||||
// SetReceivesUpdates 设置该连接是否接收主动推送的 updates。
|
||||
// 登录后的主连接在 updates.getState/getDifference 建立同步基线后置为 true。
|
||||
func (c *Conn) SetReceivesUpdates(v bool) { c.receivesUpdates.Store(v) }
|
||||
Loading…
Add table
Add a link
Reference in a new issue