chore: refresh gramsrv public release

This commit is contained in:
A 2026-06-30 14:37:43 +08:00
parent 75cebe8dbf
commit 70b6820474
1274 changed files with 378751 additions and 59919 deletions

View file

@ -0,0 +1,296 @@
package memory
import (
"context"
"sort"
"sync"
"telesrv/internal/domain"
)
// SecretChatStore 是 store.SecretChatStore 的进程内实现rpc/app 单测 fixture 用)。
// 行为契约与 postgres 实现由 storetest 共享 contract test 钉死;凡动握手态迁移
// 语义两边必须同步。
type SecretChatStore struct {
mu sync.Mutex
chats map[int]domain.SecretChat
}
// NewSecretChatStore 创建内存实现。
func NewSecretChatStore() *SecretChatStore {
return &SecretChatStore{chats: make(map[int]domain.SecretChat)}
}
func cloneSecretChat(c domain.SecretChat) domain.SecretChat {
c.GA = append([]byte(nil), c.GA...)
c.GB = append([]byte(nil), c.GB...)
return c
}
func (s *SecretChatStore) CreateSecretChat(_ context.Context, chat domain.SecretChat) error {
if chat.ID == 0 {
return domain.ErrSecretChatNotFound
}
s.mu.Lock()
defer s.mu.Unlock()
if _, exists := s.chats[chat.ID]; exists {
return domain.ErrSecretChatIDConflict
}
if chat.State == "" {
chat.State = domain.SecretChatStateRequested
}
s.chats[chat.ID] = cloneSecretChat(chat)
return nil
}
func (s *SecretChatStore) GetSecretChat(_ context.Context, chatID int) (domain.SecretChat, bool, error) {
s.mu.Lock()
defer s.mu.Unlock()
c, ok := s.chats[chatID]
if !ok {
return domain.SecretChat{}, false, nil
}
return cloneSecretChat(c), true, nil
}
func (s *SecretChatStore) GetByAdminRandom(_ context.Context, adminAuthKeyID int64, randomID int32) (domain.SecretChat, bool, error) {
s.mu.Lock()
defer s.mu.Unlock()
// 仅返回非终态匹配(与部分唯一索引 WHERE state <> 'discarded' 一致)。
for _, c := range s.chats {
if c.AdminAuthKeyID == adminAuthKeyID && c.RandomID == randomID && !c.Terminal() {
return cloneSecretChat(c), true, nil
}
}
return domain.SecretChat{}, false, nil
}
func (s *SecretChatStore) AcceptSecretChat(_ context.Context, chatID int, participantAuthKeyID int64, gb []byte, keyFingerprint int64) (domain.SecretChat, error) {
s.mu.Lock()
defer s.mu.Unlock()
c, ok := s.chats[chatID]
if !ok {
return domain.SecretChat{}, domain.ErrSecretChatNotFound
}
switch c.State {
case domain.SecretChatStateNormal:
return domain.SecretChat{}, domain.ErrSecretChatAlreadyAccepted
case domain.SecretChatStateDiscarded:
return domain.SecretChat{}, domain.ErrSecretChatAlreadyDeclined
}
// requested 且未绑定接受设备CAS 成功。
if c.ParticipantAuthKeyID != 0 {
return domain.SecretChat{}, domain.ErrSecretChatAlreadyAccepted
}
c.State = domain.SecretChatStateNormal
c.ParticipantAuthKeyID = participantAuthKeyID
c.GB = append([]byte(nil), gb...)
c.KeyFingerprint = keyFingerprint
s.chats[chatID] = c
return cloneSecretChat(c), nil
}
func (s *SecretChatStore) DiscardSecretChat(_ context.Context, chatID int, historyDeleted bool) (domain.SecretChat, bool, error) {
s.mu.Lock()
defer s.mu.Unlock()
c, ok := s.chats[chatID]
if !ok {
return domain.SecretChat{}, false, domain.ErrSecretChatNotFound
}
if c.State == domain.SecretChatStateDiscarded {
return cloneSecretChat(c), true, nil
}
c.State = domain.SecretChatStateDiscarded
c.HistoryDeleted = historyDeleted
s.chats[chatID] = c
return cloneSecretChat(c), false, nil
}
func (s *SecretChatStore) ListActiveSecretChatsByAuthKey(_ context.Context, authKeyID int64) ([]domain.SecretChat, error) {
if authKeyID == 0 {
return nil, nil
}
s.mu.Lock()
defer s.mu.Unlock()
var out []domain.SecretChat
for _, c := range s.chats {
if c.Terminal() {
continue
}
if c.AdminAuthKeyID == authKeyID || c.ParticipantAuthKeyID == authKeyID {
out = append(out, cloneSecretChat(c))
}
}
// map 遍历无序:按 chat_id 升序与 postgres ORDER BY 对齐,确定性供测试断言。
sort.Slice(out, func(i, j int) bool { return out[i].ID < out[j].ID })
return out, nil
}
func (s *SecretChatStore) MaxSecretChatID(_ context.Context) (int, error) {
s.mu.Lock()
defer s.mu.Unlock()
max := 0
for id := range s.chats {
if id > max {
max = id
}
}
return max, nil
}
// EncryptedQueueStore 是 store.EncryptedQueueStore 的进程内实现。
type EncryptedQueueStore struct {
mu sync.Mutex
byDevice map[int64][]domain.SecretChatMessage // receiverAuthKeyID → qts 升序消息
reserved map[int64]int
confirmed map[int64]int
dedup map[emqDedupKey]int // → qts
stateEvents []domain.EncryptedStateEvent
delivered map[int64]map[int64]bool // eventID → deviceAuthKeyID → true
nextEventID int64
files map[int64]domain.EncryptedFileRef // file id → 快照
}
type emqDedupKey struct {
receiver int64
chat int
random int64
}
// NewEncryptedQueueStore 创建内存实现。
func NewEncryptedQueueStore() *EncryptedQueueStore {
return &EncryptedQueueStore{
byDevice: make(map[int64][]domain.SecretChatMessage),
reserved: make(map[int64]int),
confirmed: make(map[int64]int),
dedup: make(map[emqDedupKey]int),
delivered: make(map[int64]map[int64]bool),
}
}
func cloneSecretMessage(m domain.SecretChatMessage) domain.SecretChatMessage {
m.Bytes = append([]byte(nil), m.Bytes...)
if m.File != nil {
f := *m.File
m.File = &f
}
return m
}
func (s *EncryptedQueueStore) AppendEncryptedMessage(_ context.Context, msg domain.SecretChatMessage) (domain.SecretChatMessage, bool, error) {
s.mu.Lock()
defer s.mu.Unlock()
key := emqDedupKey{msg.ReceiverAuthKeyID, msg.ChatID, msg.RandomID}
if qts, ok := s.dedup[key]; ok {
for _, m := range s.byDevice[msg.ReceiverAuthKeyID] {
if m.Qts == qts {
return cloneSecretMessage(m), true, nil
}
}
}
s.reserved[msg.ReceiverAuthKeyID]++
msg.Qts = s.reserved[msg.ReceiverAuthKeyID]
stored := cloneSecretMessage(msg)
s.byDevice[msg.ReceiverAuthKeyID] = append(s.byDevice[msg.ReceiverAuthKeyID], stored)
s.dedup[key] = msg.Qts
return cloneSecretMessage(stored), false, nil
}
func (s *EncryptedQueueStore) ListEncryptedMessagesSince(_ context.Context, receiverAuthKeyID int64, sinceQts, limit int) ([]domain.SecretChatMessage, error) {
s.mu.Lock()
defer s.mu.Unlock()
if limit <= 0 {
limit = 1000
}
var out []domain.SecretChatMessage
for _, m := range s.byDevice[receiverAuthKeyID] {
if m.Qts > sinceQts {
out = append(out, cloneSecretMessage(m))
if len(out) >= limit {
break
}
}
}
return out, nil
}
func (s *EncryptedQueueStore) ReservedQts(_ context.Context, receiverAuthKeyID int64) (int, error) {
s.mu.Lock()
defer s.mu.Unlock()
return s.reserved[receiverAuthKeyID], nil
}
func (s *EncryptedQueueStore) AckEncryptedMessages(_ context.Context, receiverAuthKeyID int64, maxQts int) error {
s.mu.Lock()
defer s.mu.Unlock()
if maxQts > s.confirmed[receiverAuthKeyID] {
s.confirmed[receiverAuthKeyID] = maxQts
}
return nil
}
func (s *EncryptedQueueStore) AppendStateEvent(_ context.Context, ev domain.EncryptedStateEvent) (int64, error) {
s.mu.Lock()
defer s.mu.Unlock()
s.nextEventID++
ev.ID = s.nextEventID
s.stateEvents = append(s.stateEvents, ev)
return ev.ID, nil
}
func (s *EncryptedQueueStore) ListUndeliveredStateEvents(_ context.Context, targetUserID, deviceAuthKeyID int64, limit int) ([]domain.EncryptedStateEvent, error) {
s.mu.Lock()
defer s.mu.Unlock()
if limit <= 0 {
limit = 1000
}
var out []domain.EncryptedStateEvent
for _, ev := range s.stateEvents {
if ev.TargetUserID != targetUserID {
continue
}
if ev.TargetAuthKeyID != 0 && ev.TargetAuthKeyID != deviceAuthKeyID {
continue
}
if s.delivered[ev.ID][deviceAuthKeyID] {
continue
}
out = append(out, ev)
if len(out) >= limit {
break
}
}
return out, nil
}
func (s *EncryptedQueueStore) MarkStateEventsDelivered(_ context.Context, deviceAuthKeyID int64, eventIDs []int64) error {
s.mu.Lock()
defer s.mu.Unlock()
for _, id := range eventIDs {
if s.delivered[id] == nil {
s.delivered[id] = make(map[int64]bool)
}
s.delivered[id][deviceAuthKeyID] = true
}
return nil
}
func (s *EncryptedQueueStore) PutEncryptedFile(_ context.Context, _ int64, ref domain.EncryptedFileRef) error {
s.mu.Lock()
defer s.mu.Unlock()
if s.files == nil {
s.files = make(map[int64]domain.EncryptedFileRef)
}
s.files[ref.ID] = ref
return nil
}
func (s *EncryptedQueueStore) GetEncryptedFile(_ context.Context, id, accessHash int64) (domain.EncryptedFileRef, bool, error) {
s.mu.Lock()
defer s.mu.Unlock()
ref, ok := s.files[id]
if !ok || ref.AccessHash != accessHash {
return domain.EncryptedFileRef{}, false, nil
}
return ref, true, nil
}