owpengram-server/internal/rpc/rpc_testkit_sessions_test.go

307 lines
7.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rpc
import (
"context"
"sync"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/proto"
"github.com/iamxvbaba/td/tg"
)
type captureSessions struct {
mu sync.Mutex
rawAuthKeyID [8]byte
sessionID int64
userID int64
userResolved bool
authKeyID [8]byte
authKeyResolved bool
receives bool
receivesCalls int
messageType proto.MessageType
message bin.Encoder
userMessage bin.Encoder // 最近一次 PushToUser* 的消息(与 message 区分message 也被 PushToSession 覆盖)
pushUserIDs []int64
onlineUserIDs []int64
channelViewers map[int64][]int64
channelMembers map[int64][]int64
// channelViewersLimit 记录最近一次 OnlineChannelUserIDs 收到的 limit验证 fan-out 封顶传参。
channelViewersLimit int
}
type captureSessionsSnapshot struct {
sessionID int64
userID int64
userResolved bool
authKeyID [8]byte
authKeyResolved bool
receives bool
receivesCalls int
messageType proto.MessageType
message bin.Encoder
}
func (s *captureSessions) snapshot() captureSessionsSnapshot {
s.mu.Lock()
defer s.mu.Unlock()
return captureSessionsSnapshot{
sessionID: s.sessionID,
userID: s.userID,
userResolved: s.userResolved,
authKeyID: s.authKeyID,
authKeyResolved: s.authKeyResolved,
receives: s.receives,
receivesCalls: s.receivesCalls,
messageType: s.messageType,
message: s.message,
}
}
func (s *captureSessions) pushedUserIDs() []int64 {
s.mu.Lock()
defer s.mu.Unlock()
return append([]int64(nil), s.pushUserIDs...)
}
// onlineChannelMemberIDs 返回当前登记的频道在线成员索引快照(测试断言用)。
func (s *captureSessions) onlineChannelMemberIDs(channelID int64) []int64 {
s.mu.Lock()
defer s.mu.Unlock()
return append([]int64(nil), s.channelMembers[channelID]...)
}
// lastUserPush 返回最近一次 PushToUser* 的消息,独立于 message后者也会被
// pushOnlinePeerStatusesToCurrentSession 经 PushToSession 覆盖成对端状态)。
func (s *captureSessions) lastUserPush() bin.Encoder {
s.mu.Lock()
defer s.mu.Unlock()
return s.userMessage
}
func (s *captureSessions) clearMessages() {
s.mu.Lock()
defer s.mu.Unlock()
s.message = nil
s.userMessage = nil
s.pushUserIDs = nil
}
func (s *captureSessions) BindAuthKeyForSession(rawAuthKeyID [8]byte, sessionID int64, authKeyID [8]byte) {
s.mu.Lock()
defer s.mu.Unlock()
if s.authKeyResolved && s.authKeyID != authKeyID {
s.userID = 0
s.userResolved = false
}
s.rawAuthKeyID = rawAuthKeyID
s.sessionID = sessionID
s.authKeyID = authKeyID
s.authKeyResolved = true
}
func (s *captureSessions) AuthKeyIDForSession([8]byte, int64) ([8]byte, bool) {
s.mu.Lock()
defer s.mu.Unlock()
return s.authKeyID, s.authKeyResolved
}
// captureSessions models an ordinary permanent-key connection unless a test
// wraps/overrides it with temporary-key metadata.
func (s *captureSessions) AuthKeyExpiresAtForSession([8]byte, int64) (int, bool) {
return 0, true
}
func (s *captureSessions) BindUserForAuthKey(rawAuthKeyID [8]byte, sessionID, userID int64) {
s.mu.Lock()
defer s.mu.Unlock()
s.rawAuthKeyID = rawAuthKeyID
s.sessionID = sessionID
s.userID = userID
s.userResolved = true
}
func (s *captureSessions) UserIDResolvedForAuthKey([8]byte, int64) (int64, bool) {
s.mu.Lock()
defer s.mu.Unlock()
return s.userID, s.userResolved
}
func (s *captureSessions) UnbindAuthKey(authKeyID [8]byte) int {
s.mu.Lock()
defer s.mu.Unlock()
if s.authKeyID == authKeyID {
s.userID = 0
s.userResolved = true
return 1
}
return 0
}
func (s *captureSessions) SetReceivesUpdatesForAuthKey(rawAuthKeyID [8]byte, sessionID int64, receives bool) {
s.mu.Lock()
defer s.mu.Unlock()
s.rawAuthKeyID = rawAuthKeyID
s.sessionID = sessionID
s.receives = receives
s.receivesCalls++
}
func (s *captureSessions) PushToSessionForAuthKey(_ context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg tg.UpdatesClass) error {
s.mu.Lock()
defer s.mu.Unlock()
s.rawAuthKeyID = rawAuthKeyID
s.sessionID = sessionID
s.messageType = t
s.message = msg
return nil
}
func (s *captureSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) {
s.mu.Lock()
defer s.mu.Unlock()
s.userID = userID
s.rawAuthKeyID = excludeAuthKeyID
s.sessionID = excludeSessionID
s.messageType = t
s.message = msg
s.userMessage = msg
s.pushUserIDs = append(s.pushUserIDs, userID)
return 1, nil
}
func (s *captureSessions) IsUserOnline(userID int64) bool {
s.mu.Lock()
defer s.mu.Unlock()
for _, id := range s.onlineUserIDs {
if id == userID {
return true
}
}
return false
}
func (s *captureSessions) OnlineUserIDsForCandidates(candidateUserIDs []int64, limit int) []int64 {
s.mu.Lock()
defer s.mu.Unlock()
online := make(map[int64]struct{}, len(s.onlineUserIDs))
for _, id := range s.onlineUserIDs {
online[id] = struct{}{}
}
out := make([]int64, 0, len(candidateUserIDs))
seen := map[int64]struct{}{}
for _, id := range candidateUserIDs {
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
if _, ok := online[id]; !ok {
continue
}
out = append(out, id)
if limit > 0 && len(out) >= limit {
break
}
}
return out
}
func (s *captureSessions) TrackChannelInterest(_ [8]byte, _ int64, userID int64, channelIDs []int64) {
s.mu.Lock()
defer s.mu.Unlock()
if s.channelViewers == nil {
s.channelViewers = make(map[int64][]int64)
}
for channelID, viewers := range s.channelViewers {
out := viewers[:0]
for _, viewerID := range viewers {
if viewerID != userID {
out = append(out, viewerID)
}
}
if len(out) == 0 {
delete(s.channelViewers, channelID)
continue
}
s.channelViewers[channelID] = out
}
for _, channelID := range channelIDs {
if channelID == 0 {
continue
}
s.channelViewers[channelID] = append(s.channelViewers[channelID], userID)
}
}
func (s *captureSessions) ClearChannelInterest(_ [8]byte, _ int64, userID int64) {
s.mu.Lock()
defer s.mu.Unlock()
for channelID, viewers := range s.channelViewers {
out := viewers[:0]
for _, viewerID := range viewers {
if viewerID != userID {
out = append(out, viewerID)
}
}
if len(out) == 0 {
delete(s.channelViewers, channelID)
continue
}
s.channelViewers[channelID] = out
}
}
func (s *captureSessions) OnlineChannelUserIDs(channelID int64, limit int) []int64 {
s.mu.Lock()
defer s.mu.Unlock()
s.channelViewersLimit = limit
return limitIDs(s.channelViewers[channelID], limit)
}
func (s *captureSessions) ChannelMembershipGeneration(_ [8]byte, _ int64) int64 { return 0 }
func (s *captureSessions) SetSessionChannelMemberships(_ [8]byte, _ int64, userID int64, channelIDs []int64, _ int64) {
s.mu.Lock()
defer s.mu.Unlock()
if s.channelMembers == nil {
s.channelMembers = make(map[int64][]int64)
}
for _, channelID := range channelIDs {
if channelID == 0 {
continue
}
s.channelMembers[channelID] = append(s.channelMembers[channelID], userID)
}
}
func (s *captureSessions) AddUserChannelMembership(userID, channelID int64) {
s.mu.Lock()
defer s.mu.Unlock()
if s.channelMembers == nil {
s.channelMembers = make(map[int64][]int64)
}
s.channelMembers[channelID] = append(s.channelMembers[channelID], userID)
}
func (s *captureSessions) RemoveUserChannelMembership(userID, channelID int64) {
s.mu.Lock()
defer s.mu.Unlock()
members := s.channelMembers[channelID]
out := members[:0]
for _, id := range members {
if id != userID {
out = append(out, id)
}
}
if len(out) == 0 {
delete(s.channelMembers, channelID)
return
}
s.channelMembers[channelID] = out
}
func (s *captureSessions) OnlineChannelMemberUserIDs(channelID int64, limit int) []int64 {
s.mu.Lock()
defer s.mu.Unlock()
return limitIDs(s.channelMembers[channelID], limit)
}