chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
227
internal/store/memory/message_send.go
Normal file
227
internal/store/memory/message_send.go
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
package memory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"telesrv/internal/domain"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (s *MessageStore) Create(_ context.Context, msg domain.Message) (domain.Message, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
msg.ID = s.nextBoxIDLocked(msg.OwnerUserID)
|
||||
msg.UID = s.nextUID
|
||||
s.nextUID++
|
||||
msg.Entities = append([]domain.MessageEntity(nil), msg.Entities...)
|
||||
s.m[msg.OwnerUserID] = append(s.m[msg.OwnerUserID], msg)
|
||||
if s.dialogs != nil {
|
||||
s.dialogs.mu.Lock()
|
||||
list := s.dialogs.m[msg.OwnerUserID]
|
||||
list.Messages = append(list.Messages, msg)
|
||||
if msg.Peer.Type == domain.PeerTypeUser && !hasUser(list.Users, msg.Peer.ID) {
|
||||
if u, ok := domain.SystemUserByID(msg.Peer.ID); ok {
|
||||
list.Users = append(list.Users, u)
|
||||
}
|
||||
}
|
||||
s.dialogs.m[msg.OwnerUserID] = list
|
||||
s.dialogs.mu.Unlock()
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
func (s *MessageStore) SendPrivateText(_ context.Context, req domain.SendPrivateTextRequest) (domain.SendPrivateTextResult, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for _, msg := range s.m[req.SenderUserID] {
|
||||
if msg.RandomID != 0 && msg.RandomID == req.RandomID {
|
||||
recipient := domain.Message{}
|
||||
if req.SenderUserID != req.RecipientUserID {
|
||||
for _, peerMsg := range s.m[req.RecipientUserID] {
|
||||
if peerMsg.UID == msg.UID {
|
||||
recipient = peerMsg
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
recipient = msg
|
||||
}
|
||||
return domain.SendPrivateTextResult{
|
||||
SenderMessage: cloneMessage(msg),
|
||||
RecipientMessage: cloneMessage(recipient),
|
||||
SenderEvent: newMessageEvent(msg),
|
||||
RecipientEvent: newMessageEvent(recipient),
|
||||
Duplicate: true,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
if req.Date == 0 {
|
||||
req.Date = int(time.Now().Unix())
|
||||
}
|
||||
senderReply, recipientReply, err := s.resolveMemoryReplyLocked(req)
|
||||
if err != nil {
|
||||
return domain.SendPrivateTextResult{}, err
|
||||
}
|
||||
uid := s.nextUID
|
||||
s.nextUID++
|
||||
sender := domain.Message{
|
||||
ID: s.nextBoxIDLocked(req.SenderUserID),
|
||||
UID: uid,
|
||||
RandomID: req.RandomID,
|
||||
OwnerUserID: req.SenderUserID,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: req.RecipientUserID},
|
||||
From: domain.Peer{Type: domain.PeerTypeUser, ID: req.SenderUserID},
|
||||
Date: req.Date,
|
||||
Out: true,
|
||||
Silent: req.Silent,
|
||||
NoForwards: req.NoForwards,
|
||||
Body: req.Message,
|
||||
Entities: append([]domain.MessageEntity(nil), req.Entities...),
|
||||
Media: req.Media,
|
||||
ViaBotID: req.ViaBotID,
|
||||
GroupedID: req.GroupedID,
|
||||
Effect: req.Effect,
|
||||
ReplyMarkup: cloneReplyMarkup(req.ReplyMarkup),
|
||||
RichMessage: cloneRichMessage(req.RichMessage),
|
||||
ReplyTo: cloneMessageReply(senderReply),
|
||||
Forward: cloneMessageForward(req.Forward),
|
||||
Pts: s.nextPtsLocked(req.SenderUserID),
|
||||
// voice/round 在发送者副本上同样保持"未听",由对端内容已读清除。
|
||||
MediaUnread: req.Media.HasUnreadPayload() && req.SenderUserID != req.RecipientUserID,
|
||||
}
|
||||
if req.SenderUserID == req.RecipientUserID {
|
||||
sender.SavedPeer = domain.SavedPeerForSelfChat(req.SenderUserID, req.Forward)
|
||||
}
|
||||
recipient := domain.Message{}
|
||||
if req.SenderUserID == req.RecipientUserID {
|
||||
recipient = sender
|
||||
}
|
||||
if req.SenderUserID != req.RecipientUserID && !req.RecipientBlocked {
|
||||
recipient = sender
|
||||
recipient.ID = s.nextBoxIDLocked(req.RecipientUserID)
|
||||
recipient.OwnerUserID = req.RecipientUserID
|
||||
recipient.Peer = domain.Peer{Type: domain.PeerTypeUser, ID: req.SenderUserID}
|
||||
recipient.Out = false
|
||||
recipient.ReplyTo = cloneMessageReply(recipientReply)
|
||||
// recipient = sender 是值拷贝,共享 sender.ReplyMarkup 指针/Data 切片——深拷
|
||||
// 让双盒各持独立快照(与 postgres 每盒独立 decode 对齐,I3/I2)。
|
||||
recipient.ReplyMarkup = cloneReplyMarkup(sender.ReplyMarkup)
|
||||
recipient.RichMessage = cloneRichMessage(sender.RichMessage)
|
||||
recipient.Pts = s.nextPtsLocked(req.RecipientUserID)
|
||||
recipient.MediaUnread = req.Media.HasUnreadPayload()
|
||||
}
|
||||
s.m[req.SenderUserID] = append(s.m[req.SenderUserID], sender)
|
||||
if req.SenderUserID != req.RecipientUserID && !req.RecipientBlocked {
|
||||
s.m[req.RecipientUserID] = append(s.m[req.RecipientUserID], recipient)
|
||||
}
|
||||
if s.dialogs != nil {
|
||||
if recipient.ID != 0 {
|
||||
s.upsertMemoryDialogsLocked(sender, recipient)
|
||||
} else {
|
||||
s.upsertMemoryDialogsLocked(sender, sender)
|
||||
}
|
||||
}
|
||||
return domain.SendPrivateTextResult{
|
||||
SenderMessage: cloneMessage(sender),
|
||||
RecipientMessage: cloneMessage(recipient),
|
||||
SenderEvent: newMessageEvent(sender),
|
||||
RecipientEvent: newMessageEvent(recipient),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *MessageStore) resolveMemoryReplyLocked(req domain.SendPrivateTextRequest) (*domain.MessageReply, *domain.MessageReply, error) {
|
||||
if req.ReplyTo == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
if err := domain.ValidateMessageReplyBounds(req.ReplyTo); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if req.ReplyTo.StoryID > 0 {
|
||||
// story 回复(评论):无源消息可查;story 作者就是会话对端,双盒同持。
|
||||
reply := &domain.MessageReply{
|
||||
StoryID: req.ReplyTo.StoryID,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: req.RecipientUserID},
|
||||
}
|
||||
return cloneMessageReply(reply), cloneMessageReply(reply), nil
|
||||
}
|
||||
peer := req.ReplyTo.Peer
|
||||
if peer.ID == 0 {
|
||||
peer = domain.Peer{Type: domain.PeerTypeUser, ID: req.RecipientUserID}
|
||||
}
|
||||
if peer.Type != domain.PeerTypeUser || peer.ID != req.RecipientUserID {
|
||||
return nil, nil, domain.ErrReplyMessageIDInvalid
|
||||
}
|
||||
var target domain.Message
|
||||
for _, msg := range s.m[req.SenderUserID] {
|
||||
if msg.Peer == peer && msg.ID == req.ReplyTo.MessageID {
|
||||
target = msg
|
||||
break
|
||||
}
|
||||
}
|
||||
if target.ID == 0 {
|
||||
return nil, nil, domain.ErrReplyMessageIDInvalid
|
||||
}
|
||||
senderReply := cloneMessageReply(req.ReplyTo)
|
||||
senderReply.MessageID = target.ID
|
||||
senderReply.Peer = peer
|
||||
if req.SenderUserID == req.RecipientUserID {
|
||||
return senderReply, cloneMessageReply(senderReply), nil
|
||||
}
|
||||
for _, msg := range s.m[req.RecipientUserID] {
|
||||
if msg.UID == target.UID {
|
||||
recipientReply := cloneMessageReply(senderReply)
|
||||
recipientReply.MessageID = msg.ID
|
||||
recipientReply.Peer = domain.Peer{Type: domain.PeerTypeUser, ID: req.SenderUserID}
|
||||
return senderReply, recipientReply, nil
|
||||
}
|
||||
}
|
||||
return senderReply, nil, nil
|
||||
}
|
||||
|
||||
func (s *MessageStore) upsertMemoryDialogsLocked(sender, recipient domain.Message) {
|
||||
s.dialogs.mu.Lock()
|
||||
defer s.dialogs.mu.Unlock()
|
||||
list := s.dialogs.m[sender.OwnerUserID]
|
||||
list = upsertMemoryDialog(list, domain.Dialog{Peer: sender.Peer, TopMessage: sender.ID, TopMessageDate: sender.Date})
|
||||
// 发送方向清手动未读标记(对齐 postgres UpsertOutboxDialog 与
|
||||
// channel 发送路径:向会话发出消息即视为已知晓内容)。
|
||||
for i := range list.Dialogs {
|
||||
if list.Dialogs[i].Peer == sender.Peer {
|
||||
list.Dialogs[i].UnreadMark = false
|
||||
break
|
||||
}
|
||||
}
|
||||
list.Messages = append(list.Messages, sender)
|
||||
s.dialogs.m[sender.OwnerUserID] = list
|
||||
if recipient.OwnerUserID != sender.OwnerUserID {
|
||||
peerList := s.dialogs.m[recipient.OwnerUserID]
|
||||
peerList = upsertMemoryDialog(peerList, domain.Dialog{
|
||||
Peer: recipient.Peer,
|
||||
TopMessage: recipient.ID,
|
||||
TopMessageDate: recipient.Date,
|
||||
UnreadCount: s.privateUnreadCountLocked(recipient.OwnerUserID, recipient.Peer),
|
||||
})
|
||||
peerList.Messages = append(peerList.Messages, recipient)
|
||||
s.dialogs.m[recipient.OwnerUserID] = peerList
|
||||
}
|
||||
}
|
||||
|
||||
func (s *MessageStore) privateUnreadCountLocked(ownerUserID int64, peer domain.Peer) int {
|
||||
readMax := 0
|
||||
if s.dialogs != nil {
|
||||
if list, ok := s.dialogs.m[ownerUserID]; ok {
|
||||
for _, dialog := range list.Dialogs {
|
||||
if dialog.Peer == peer {
|
||||
readMax = dialog.ReadInboxMaxID
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unread := 0
|
||||
for _, msg := range s.m[ownerUserID] {
|
||||
if msg.Peer == peer && !msg.Out && msg.ID > readMax {
|
||||
unread++
|
||||
}
|
||||
}
|
||||
return unread
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue