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,115 @@
package memory
import (
"context"
"sort"
"telesrv/internal/domain"
"time"
)
func (s *MessageStore) EditMessage(_ context.Context, req domain.EditMessageRequest) (domain.EditMessageResult, error) {
res := domain.EditMessageResult{OwnerUserID: req.OwnerUserID}
if req.OwnerUserID == 0 || req.Peer.ID == 0 || req.ID <= 0 || req.ID > domain.MaxMessageBoxID {
return res, domain.ErrMessageIDInvalid
}
if req.EditDate == 0 {
req.EditDate = int(time.Now().Unix())
}
s.mu.Lock()
defer s.mu.Unlock()
targetIndex := -1
var target domain.Message
for i, msg := range s.m[req.OwnerUserID] {
if msg.ID == req.ID && msg.Peer == req.Peer {
targetIndex = i
target = msg
break
}
}
if targetIndex < 0 {
return res, domain.ErrMessageIDInvalid
}
authorEdit := target.Out && target.From.ID == req.OwnerUserID
viaBotEdit := req.ViaBotEditBotID != 0 && target.ViaBotID == req.ViaBotEditBotID
if !authorEdit && !viaBotEdit && !req.WebPageResolve && !validMemoryTodoParticipantEdit(req, target) {
return res, domain.ErrMessageAuthorRequired
}
// WebPageResolve服务端内部链接预览就地替换。幂等——仅当目标当前 media 仍是匹配 id 的
// pending 占位才替换;只换 media、不碰 body/entities/edit_date事件为 web_page。
if req.WebPageResolve {
if req.Media == nil || !domain.IsPendingWebPageMedia(target.Media, req.ExpectedWebPageID) {
return res, domain.ErrMessageNotModified
}
}
if req.Message == "" && req.Media == nil && target.Media.IsZero() {
return res, domain.ErrMessageEmpty
}
if req.Media == nil && !req.SetReplyMarkup && target.Body == req.Message && equalMessageEntities(target.Entities, req.Entities) {
return res, domain.ErrMessageNotModified
}
messageSenderID := target.From.ID
for userID, messages := range s.m {
for i, msg := range messages {
if msg.UID == target.UID && msg.From.ID == messageSenderID {
if req.WebPageResolve {
media := *req.Media
msg.Media = &media
msg.Pts = s.nextPtsLocked(userID)
s.m[userID][i] = msg
res.Edited = append(res.Edited, domain.EditedMessageForUser{
UserID: userID,
Message: cloneMessage(msg),
Event: webPageEvent(msg),
})
continue
}
msg.Body = req.Message
msg.Entities = append([]domain.MessageEntity(nil), req.Entities...)
if req.Media != nil {
media := *req.Media
msg.Media = &media
}
if req.SetReplyMarkup {
// 替换 markupnil/空 = 清空键盘);双盒一致。
msg.ReplyMarkup = cloneReplyMarkup(req.ReplyMarkup)
}
msg.EditDate = req.EditDate
msg.Pts = s.nextPtsLocked(userID)
s.m[userID][i] = msg
event := editMessageEvent(msg)
res.Edited = append(res.Edited, domain.EditedMessageForUser{
UserID: userID,
Message: cloneMessage(msg),
Event: event,
})
}
}
}
if s.dialogs != nil {
s.dialogs.mu.Lock()
for userID := range s.dialogs.m {
list := s.dialogs.m[userID]
list.Messages = cloneMessages(s.m[userID])
s.dialogs.m[userID] = list
}
s.dialogs.mu.Unlock()
}
sort.Slice(res.Edited, func(i, j int) bool { return res.Edited[i].UserID < res.Edited[j].UserID })
return res, nil
}
func validMemoryTodoParticipantEdit(req domain.EditMessageRequest, target domain.Message) bool {
if !req.AllowTodoParticipantMutation || req.SetReplyMarkup || req.Media == nil || req.Media.Kind != domain.MessageMediaKindTodo || req.Media.Todo == nil {
return false
}
if target.From.ID == req.OwnerUserID {
return false
}
if target.Body != req.Message || !equalMessageEntities(target.Entities, req.Entities) {
return false
}
if target.Media == nil || target.Media.Kind != domain.MessageMediaKindTodo || target.Media.Todo == nil {
return false
}
return true
}