chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
201
internal/store/memory/updates.go
Normal file
201
internal/store/memory/updates.go
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
package memory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
// UpdateStateStore 是 store.UpdateStateStore 的内存实现。
|
||||
type UpdateStateStore struct {
|
||||
mu sync.RWMutex
|
||||
states map[updateStateKey]domain.UpdateState
|
||||
}
|
||||
|
||||
// UpdateEventStore 是 store.UpdateEventStore 的内存实现。
|
||||
type UpdateEventStore struct {
|
||||
mu sync.RWMutex
|
||||
events map[int64][]domain.UpdateEvent
|
||||
}
|
||||
|
||||
type updateStateKey struct {
|
||||
authKeyID [8]byte
|
||||
userID int64
|
||||
}
|
||||
|
||||
// NewUpdateEventStore 创建内存 UpdateEventStore。
|
||||
func NewUpdateEventStore() *UpdateEventStore {
|
||||
return &UpdateEventStore{events: make(map[int64][]domain.UpdateEvent)}
|
||||
}
|
||||
|
||||
func (s *UpdateEventStore) Append(_ context.Context, userID int64, event domain.UpdateEvent) error {
|
||||
_, err := s.append(userID, event, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *UpdateEventStore) AppendAllocated(_ context.Context, userID int64, event domain.UpdateEvent) (domain.UpdateEvent, error) {
|
||||
return s.append(userID, event, true)
|
||||
}
|
||||
|
||||
func (s *UpdateEventStore) AppendAllocatedWithDispatch(_ context.Context, userID int64, event domain.UpdateEvent, _ [8]byte, _ int64) (domain.UpdateEvent, error) {
|
||||
return s.append(userID, event, true)
|
||||
}
|
||||
|
||||
func (s *UpdateEventStore) append(userID int64, event domain.UpdateEvent, allocate bool) (domain.UpdateEvent, error) {
|
||||
if event.PtsCount <= 0 {
|
||||
event.PtsCount = 1
|
||||
}
|
||||
event.UserID = userID
|
||||
event.Message = cloneMessage(event.Message)
|
||||
event.Story = cloneUpdateStory(event.Story)
|
||||
event.MessageIDs = append([]int(nil), event.MessageIDs...)
|
||||
event.Peers = append([]domain.Peer(nil), event.Peers...)
|
||||
event.Users = append([]domain.User(nil), event.Users...)
|
||||
event.Channels = append([]domain.Channel(nil), event.Channels...)
|
||||
event.Reaction = cloneUpdateReaction(event.Reaction)
|
||||
event.QuickReplies = cloneUpdateQuickReplies(event.QuickReplies)
|
||||
event.QuickReplyMessage = cloneUpdateQuickReplyMessage(event.QuickReplyMessage)
|
||||
s.mu.Lock()
|
||||
if allocate {
|
||||
current := 0
|
||||
for _, item := range s.events[userID] {
|
||||
if item.Pts > current {
|
||||
current = item.Pts
|
||||
}
|
||||
}
|
||||
event.Pts = current + event.PtsCount
|
||||
}
|
||||
s.events[userID] = append(s.events[userID], event)
|
||||
s.mu.Unlock()
|
||||
return event, nil
|
||||
}
|
||||
|
||||
func (s *UpdateEventStore) ListAfter(_ context.Context, userID int64, pts, limit int) ([]domain.UpdateEvent, error) {
|
||||
s.mu.RLock()
|
||||
items := append([]domain.UpdateEvent(nil), s.events[userID]...)
|
||||
s.mu.RUnlock()
|
||||
out := make([]domain.UpdateEvent, 0, len(items))
|
||||
for _, event := range items {
|
||||
if event.Pts <= pts {
|
||||
continue
|
||||
}
|
||||
event.Message = cloneMessage(event.Message)
|
||||
event.Story = cloneUpdateStory(event.Story)
|
||||
event.MessageIDs = append([]int(nil), event.MessageIDs...)
|
||||
event.Peers = append([]domain.Peer(nil), event.Peers...)
|
||||
event.Users = append([]domain.User(nil), event.Users...)
|
||||
event.Channels = append([]domain.Channel(nil), event.Channels...)
|
||||
event.Reaction = cloneUpdateReaction(event.Reaction)
|
||||
event.QuickReplies = cloneUpdateQuickReplies(event.QuickReplies)
|
||||
event.QuickReplyMessage = cloneUpdateQuickReplyMessage(event.QuickReplyMessage)
|
||||
out = append(out, event)
|
||||
if limit > 0 && len(out) >= limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func cloneUpdateStory(story domain.Story) domain.Story {
|
||||
story.Entities = append([]domain.MessageEntity(nil), story.Entities...)
|
||||
story.Views.Reactions = append([]domain.ChannelMessageReactionCount(nil), story.Views.Reactions...)
|
||||
story.Views.RecentViewers = append([]int64(nil), story.Views.RecentViewers...)
|
||||
story.SentReaction = cloneUpdateReaction(story.SentReaction)
|
||||
return story
|
||||
}
|
||||
|
||||
func cloneUpdateReaction(in *domain.MessageReaction) *domain.MessageReaction {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := *in
|
||||
return &out
|
||||
}
|
||||
|
||||
func cloneUpdateQuickReplies(in []domain.QuickReply) []domain.QuickReply {
|
||||
return append([]domain.QuickReply(nil), in...)
|
||||
}
|
||||
|
||||
func cloneUpdateQuickReplyMessage(in domain.QuickReplyMessage) domain.QuickReplyMessage {
|
||||
out := in
|
||||
out.Entities = append([]domain.MessageEntity(nil), in.Entities...)
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
// MaxContiguousPts 返回从 1 起无空洞的最大 pts(内存版按 pts_count 连续扫描)。
|
||||
func (s *UpdateEventStore) MaxContiguousPts(_ context.Context, userID int64) (int, error) {
|
||||
s.mu.RLock()
|
||||
nextByStart := make(map[int]int, len(s.events[userID]))
|
||||
for _, event := range s.events[userID] {
|
||||
count := event.PtsCount
|
||||
if count <= 0 {
|
||||
count = 1
|
||||
}
|
||||
nextByStart[event.Pts-count] = event.Pts
|
||||
}
|
||||
s.mu.RUnlock()
|
||||
contiguous := 0
|
||||
for {
|
||||
next, ok := nextByStart[contiguous]
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
contiguous = next
|
||||
}
|
||||
return contiguous, nil
|
||||
}
|
||||
|
||||
// NewUpdateStateStore 创建内存 UpdateStateStore。
|
||||
func NewUpdateStateStore() *UpdateStateStore {
|
||||
return &UpdateStateStore{states: make(map[updateStateKey]domain.UpdateState)}
|
||||
}
|
||||
|
||||
func (s *UpdateStateStore) Get(_ context.Context, id [8]byte, userID int64) (domain.UpdateState, bool, error) {
|
||||
s.mu.RLock()
|
||||
st, ok := s.states[updateStateKey{authKeyID: id, userID: userID}]
|
||||
s.mu.RUnlock()
|
||||
return st, ok, nil
|
||||
}
|
||||
|
||||
func (s *UpdateStateStore) Save(_ context.Context, id [8]byte, userID int64, st domain.UpdateState) error {
|
||||
s.mu.Lock()
|
||||
key := updateStateKey{authKeyID: id, userID: userID}
|
||||
// 确认水位只增不减(与 PG 的 GREATEST upsert 对齐):一个旧 from(较小 pts)
|
||||
// 的 getDifference 不得把设备已确认水位回退,否则 getPeerDialogs.state 会下发
|
||||
// 倒退的 pts 基线。
|
||||
prev := s.states[key]
|
||||
if st.Pts < prev.Pts {
|
||||
st.Pts = prev.Pts
|
||||
}
|
||||
if st.Qts < prev.Qts {
|
||||
st.Qts = prev.Qts
|
||||
}
|
||||
if st.Date < prev.Date {
|
||||
st.Date = prev.Date
|
||||
}
|
||||
if st.Seq < prev.Seq {
|
||||
st.Seq = prev.Seq
|
||||
}
|
||||
s.states[key] = st
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *UpdateStateStore) Delete(_ context.Context, id [8]byte, userID int64) error {
|
||||
s.mu.Lock()
|
||||
delete(s.states, updateStateKey{authKeyID: id, userID: userID})
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *UpdateStateStore) DeleteAuthKey(_ context.Context, id [8]byte) error {
|
||||
s.mu.Lock()
|
||||
for k := range s.states {
|
||||
if k.authKeyID == id {
|
||||
delete(s.states, k)
|
||||
}
|
||||
}
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue