owpengram-server/internal/domain/message.go
A d84fa6e126 fix: align private and channel update semantics
(cherry picked from commit c65f76f56278f74082c4fa792ed49104d5d33c38)
2026-06-10 22:06:48 +08:00

360 lines
10 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 domain
// MessageEntityType 标识消息实体类型。
type MessageEntityType string
const (
MessageEntityBold MessageEntityType = "bold"
)
const (
// MaxMessageTextLength matches the first-stage text message limit exposed to Telegram clients.
MaxMessageTextLength = 4096
// MaxMessageReplyQuoteLength matches TDesktop's quote_length_max app config default.
MaxMessageReplyQuoteLength = 1024
// MaxMessageReplyQuoteOffset bounds quote_offset, which is an offset inside message text, not a message id.
MaxMessageReplyQuoteOffset = MaxMessageTextLength
// MaxMessageEntityCount limits styled text entity vectors in message text and quotes.
MaxMessageEntityCount = 256
// MaxMessageBoxID 是 TL int / PostgreSQL int4 可安全表达的最大 message id。
MaxMessageBoxID = 1<<31 - 1
// MaxDeleteMessageIDs 限制单次 deleteMessages/updateDeleteMessages 的 owner 视角 id 数量。
// 大批量历史清理走 deleteHistory 分批推进,避免单个 RPC 构造超大数组或 durable payload。
MaxDeleteMessageIDs = 1000
// MaxGetMessageIDs 限制 getMessages / channels.getMessages 精确 ID 批量。
MaxGetMessageIDs = 100
// MaxDeleteHistoryBatch 限制单次 deleteHistory 实际清理的 message box 数量。
// affectedHistory.Offset > 0 时客户端可继续调用,服务端不一次性 RETURNING 全历史。
MaxDeleteHistoryBatch = 1000
// MaxForwardMessageIDs 限制单次 forwardMessages 的 owner 视角 id 数量。
MaxForwardMessageIDs = 100
// MaxMessageHistoryAddOffset 限制 history/search 的 add_offset 绝对值。
// TDesktop 正常只使用小窗口偏移;服务端必须拒绝把客户端传入的超大值变成 SQL OFFSET 或 slice capacity。
MaxMessageHistoryAddOffset = 100
)
// ClampMessageHistoryAddOffset bounds Telegram history/search add_offset to a small local window.
func ClampMessageHistoryAddOffset(v int) int {
if v > MaxMessageHistoryAddOffset {
return MaxMessageHistoryAddOffset
}
if v < -MaxMessageHistoryAddOffset {
return -MaxMessageHistoryAddOffset
}
return v
}
// ValidateMessageReplyBounds validates reply fields that are independent of peer visibility.
func ValidateMessageReplyBounds(reply *MessageReply) error {
if reply == nil {
return nil
}
if reply.MessageID < 0 || reply.MessageID > MaxMessageBoxID {
return ErrReplyMessageIDInvalid
}
if reply.TopMessageID < 0 || reply.TopMessageID > MaxMessageBoxID {
return ErrReplyMessageIDInvalid
}
if reply.MessageID == 0 && reply.TopMessageID == 0 {
return ErrReplyMessageIDInvalid
}
if reply.QuoteOffset < 0 || reply.QuoteOffset > MaxMessageReplyQuoteOffset {
return ErrReplyMessageIDInvalid
}
return nil
}
// MessageEntity 是业务层消息实体,不依赖 TL 类型。
type MessageEntity struct {
Type MessageEntityType
Offset int
Length int
}
// Message 是账号视角下的一条私聊消息。
type Message struct {
ID int // 当前 owner 视角下的 message box id暴露给 Telegram 客户端。
UID int64 // 共享私聊消息主体 id不暴露给客户端。
RandomID int64
OwnerUserID int64
Peer Peer
From Peer
Date int
EditDate int
Out bool
Silent bool
NoForwards bool
Body string
Entities []MessageEntity
ReplyTo *MessageReply
Forward *MessageForward
Reactions *ChannelMessageReactions
Pts int
Media *MessageMedia
MediaUnread bool
ReactionUnread bool
}
// MessageReply describes a message reply/thread header without depending on TL types.
type MessageReply struct {
MessageID int
Peer Peer
TopMessageID int
ForumTopic bool
QuoteText string
QuoteEntities []MessageEntity
QuoteOffset int
}
// MessageForward 描述一条转发消息的原始作者信息。
type MessageForward struct {
From Peer
FromName string
Date int
ChannelPost int
SavedFrom Peer
SavedFromMsgID int
}
// MessageList 是账号视角下的消息查询结果。
type MessageList struct {
Messages []Message
Users []User
Count int
Hash int64
}
// MessageFilter 描述历史/搜索查询条件。
type MessageFilter struct {
HasPeer bool
Peer Peer
Query string
OffsetID int
OffsetDate int
AddOffset int
Limit int
MaxID int
MinID int
Hash int64
NeedTotalCount bool
}
// SendPrivateTextRequest 是私聊文本/媒体发送命令。
type SendPrivateTextRequest struct {
SenderUserID int64
RecipientUserID int64
RandomID int64
Message string
Entities []MessageEntity
Media *MessageMedia
Silent bool
NoForwards bool
ReplyTo *MessageReply
Forward *MessageForward
Date int
OriginAuthKeyID [8]byte
OriginSessionID int64
RecipientBlocked bool
}
// SendPrivateTextResult 描述一次私聊文本发送的双端结果。
type SendPrivateTextResult struct {
SenderMessage Message
RecipientMessage Message
SenderEvent UpdateEvent
RecipientEvent UpdateEvent
Duplicate bool
}
// SetPrivateMessageReactionsRequest replaces the current user's reactions for one private message.
type SetPrivateMessageReactionsRequest struct {
UserID int64
Peer Peer
MessageID int
Reactions []MessageReaction
Big bool
AddToRecent bool
Date int
}
// PrivateMessageReactionsRequest fetches reaction summaries for exact private message ids.
type PrivateMessageReactionsRequest struct {
OwnerUserID int64
Peer Peer
IDs []int
}
// PrivateMessageReactionsResult describes private reaction updates in owner-visible boxes.
type PrivateMessageReactionsResult struct {
Messages []Message
Reactions ChannelMessageReactions
}
// ForwardPrivateMessagesRequest 是私聊文本消息转发命令。
type ForwardPrivateMessagesRequest struct {
OwnerUserID int64
FromPeer Peer
ToUserID int64
MessageIDs []int
RandomIDs []int64
Silent bool
NoForwards bool
DropAuthor bool
ReplyTo *MessageReply
Date int
OriginAuthKeyID [8]byte
OriginSessionID int64
RecipientBlocked bool
}
// ForwardPrivateMessagesResult 描述一次私聊转发的 owner 维度结果。
type ForwardPrivateMessagesResult struct {
OwnerUserID int64
SenderMessages []Message
RecipientMessages []Message
SenderEvents []UpdateEvent
RecipientEvents []UpdateEvent
Duplicates []bool
}
// ReadHistoryRequest 是账号视角的 messages.readHistory 命令。
type ReadHistoryRequest struct {
OwnerUserID int64
Peer Peer
MaxID int
Date int
OriginAuthKeyID [8]byte
OriginSessionID int64
}
// ReadHistoryResult 描述一次会话已读操作的业务结果。
type ReadHistoryResult struct {
OwnerUserID int64
Peer Peer
MaxID int
StillUnreadCount int
Changed bool
InboxEvent UpdateEvent
OutboxChanged bool
OutboxUserID int64
OutboxEvent UpdateEvent
}
// ReadMessageContentsRequest marks media/mention contents as read for exact owner-visible messages.
type ReadMessageContentsRequest struct {
OwnerUserID int64
IDs []int
Date int
OriginAuthKeyID [8]byte
OriginSessionID int64
}
// ReadMessageContentsResult contains owner-visible message IDs whose content unread state changed.
type ReadMessageContentsResult struct {
OwnerUserID int64
MessageIDs []int
Event UpdateEvent
}
// OutboxReadDateRequest 是 messages.getOutboxReadDate 查询。
type OutboxReadDateRequest struct {
OwnerUserID int64
Peer Peer
ID int
}
// EditMessageRequest 是账号视角下编辑一条已发送私聊文本消息的命令。
type EditMessageRequest struct {
OwnerUserID int64
Peer Peer
ID int
Message string
Entities []MessageEntity
EditDate int
OriginAuthKeyID [8]byte
OriginSessionID int64
}
// EditedMessageForUser 描述一次编辑对某个 owner 视角造成的影响。
type EditedMessageForUser struct {
UserID int64
Message Message
Event UpdateEvent
}
// EditMessageResult 描述消息编辑后的 owner 维度结果。
type EditMessageResult struct {
OwnerUserID int64
Edited []EditedMessageForUser
}
// Self 返回当前请求账号的编辑结果。
func (r EditMessageResult) Self() EditedMessageForUser {
for _, item := range r.Edited {
if item.UserID == r.OwnerUserID {
return item
}
}
return EditedMessageForUser{UserID: r.OwnerUserID}
}
// Changed 表示本次编辑是否实际影响了任何 owner 视角。
func (r EditMessageResult) Changed() bool {
return len(r.Edited) > 0
}
// DeleteMessagesRequest 是账号视角下按消息 ID 删除消息的命令。
type DeleteMessagesRequest struct {
OwnerUserID int64
IDs []int
Revoke bool
Date int
OriginAuthKeyID [8]byte
OriginSessionID int64
}
// DeleteHistoryRequest 是账号视角下清空某个 peer 历史的命令。
type DeleteHistoryRequest struct {
OwnerUserID int64
Peer Peer
MaxID int
JustClear bool
Revoke bool
Date int
OriginAuthKeyID [8]byte
OriginSessionID int64
}
// DeletedMessagesForUser 描述一次删除对某个 owner 视角造成的影响。
type DeletedMessagesForUser struct {
UserID int64
MessageIDs []int
Event UpdateEvent
}
// DeleteMessagesResult 描述消息删除后的 owner 维度结果。
type DeleteMessagesResult struct {
OwnerUserID int64
Deleted []DeletedMessagesForUser
Offset int
}
// Self 返回当前请求账号的删除结果。
func (r DeleteMessagesResult) Self() DeletedMessagesForUser {
for _, item := range r.Deleted {
if item.UserID == r.OwnerUserID {
return item
}
}
return DeletedMessagesForUser{UserID: r.OwnerUserID}
}
// Changed 表示本次删除是否实际影响了任何 owner 视角。
func (r DeleteMessagesResult) Changed() bool {
for _, item := range r.Deleted {
if len(item.MessageIDs) > 0 {
return true
}
}
return false
}