chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
|
|
@ -1,5 +1,11 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
// MaxChannelDifferenceLimit limits a single updates.getChannelDifference page.
|
||||
MaxChannelDifferenceLimit = 100
|
||||
|
|
@ -14,9 +20,18 @@ const (
|
|||
// MaxChannelInviteUsers limits a single inviteToChannel/createChat member batch.
|
||||
MaxChannelInviteUsers = 200
|
||||
// MaxChannelRealtimeFanout caps best-effort realtime channel pushes until a presence/subscription index exists.
|
||||
MaxChannelRealtimeFanout = 500
|
||||
MaxChannelRealtimeFanout = 2000
|
||||
// MaxSynchronousChannelDialogFanout bounds per-member channel_dialogs writes in the send transaction.
|
||||
MaxSynchronousChannelDialogFanout = 1000
|
||||
// MaxDialogUnreadCount 钳制对话未读消息 COUNT 的上界(设计 fan-out epic Phase 2 / P1-v)。
|
||||
// 广播/大群走动态 COUNT(*),积压巨大时既下发天文数字角标、又让 nudge 风暴下每个被 nudge
|
||||
// 成员的 getChannelDifference/getPeerDialogs 触发 O(积压) 扫描打爆 PG。store 层一律把未读
|
||||
// COUNT 用 LIMIT 子查询(PG)/提前 break(memory) 钳到本上界——既限定扫描工作量也限定下发数值。
|
||||
// 只影响角标显示数,不影响 read 水位/pts 真值与 hasUnread(EXISTS) 判定。
|
||||
// 取 99(角标显示上限“99+”惯例):上界即扫描上界,越低单次未读 COUNT 扫描越浅——
|
||||
// 相比旧值 1000,积压 >99 的成员每次未读 COUNT(大群读路径 + fan-out 写 + forum 话题)
|
||||
// 扫描行数约降一个数量级。值可按客户端角标显示习惯调整。
|
||||
MaxDialogUnreadCount = 99
|
||||
// MaxChannelTypingFanout caps transient typing fanout.
|
||||
MaxChannelTypingFanout = MaxChannelRealtimeFanout
|
||||
// MaxChannelAdminRankLength limits custom admin rank text.
|
||||
|
|
@ -31,6 +46,9 @@ const (
|
|||
MaxChannelPendingJoinRecentRequesters = 5
|
||||
// MaxAdminedPublicChannels limits channels.getAdminedPublicChannels payload size.
|
||||
MaxAdminedPublicChannels = 200
|
||||
// MaxSendAsChannels bounds the broadcast channels offered as channels.getSendAs candidates
|
||||
// (the user's own channels they can post groups as).
|
||||
MaxSendAsChannels = 100
|
||||
// MaxChannelAdminLogLimit limits one channels.getAdminLog page.
|
||||
MaxChannelAdminLogLimit = 100
|
||||
// MaxChannelAdminLogAdmins limits admin filter fan-in.
|
||||
|
|
@ -47,12 +65,36 @@ const (
|
|||
MaxPublicChannelSearchLimit = 50
|
||||
// MaxPublicChannelSearchQueryLength bounds public channel peer search strings.
|
||||
MaxPublicChannelSearchQueryLength = 256
|
||||
// MaxChannelReactionItems limits one channel reaction policy payload.
|
||||
MaxChannelReactionItems = 64
|
||||
// MaxChannelReactionTypes bounds how many distinct reaction types a chat may
|
||||
// allow via chatReactionsSome. DrKLO sends "enable all standard reactions" on
|
||||
// a broadcast channel as an explicit chatReactionsSome list (megagroups use
|
||||
// chatReactionsAll instead), so this MUST stay >= the advertised available
|
||||
// reactions catalog (messages.getAvailableReactions, currently ~74 entries) or
|
||||
// that legitimate "select all" payload is wrongly rejected with LIMIT_INVALID.
|
||||
// 100 leaves headroom for catalog growth while still bounding abusive payloads.
|
||||
MaxChannelReactionTypes = 100
|
||||
// MaxChannelReactionsLimit bounds the per-message distinct-reaction cap carried
|
||||
// by messages.setChatAvailableReactions.reactions_limit. Clients constrain it to
|
||||
// appConfig reactions_uniq_max (11); this wider server bound only rejects abuse
|
||||
// and must never be smaller than the reaction type count to keep the cap sane.
|
||||
MaxChannelReactionsLimit = 100
|
||||
// MaxChannelReactionEmoticonLength limits one emoji reaction string.
|
||||
MaxChannelReactionEmoticonLength = 32
|
||||
// MaxChannelMessageReactionsPerUser limits one user's reactions on one channel message.
|
||||
// MaxChannelMessageReactionsPerUser bounds the accepted sendReaction vector before trimming.
|
||||
MaxChannelMessageReactionsPerUser = 16
|
||||
// MaxMessageReactionsPerUser is the effective per-user cap on one message, matching the
|
||||
// advertised appConfig reactions_user_max_default.
|
||||
// Longer vectors keep the newest entries: official clients are told to drop older
|
||||
// reactions, so the tail of the vector wins.
|
||||
MaxMessageReactionsPerUser = 1
|
||||
// MaxMessageReactionsPerUserPremium 是会员档每用户上限,对齐 appConfig
|
||||
// reactions_user_max_premium(官方值 3)。客户端按 self premium flag 选档,
|
||||
// 服务端档位必须 ≥ 客户端宣告档位,否则 premium 用户的多 reaction 会被
|
||||
// 静默裁剪、双端视图错乱。
|
||||
MaxMessageReactionsPerUserPremium = 3
|
||||
// DefaultMessageReactionsUniqMax caps distinct reaction emojis on one message, matching the
|
||||
// advertised appConfig reactions_uniq_max. ChannelReactionPolicy.Limit overrides it per chat.
|
||||
DefaultMessageReactionsUniqMax = 11
|
||||
// MaxChannelMessageReactionRecent limits recent reactors embedded in messageReactions.
|
||||
MaxChannelMessageReactionRecent = 3
|
||||
// MaxChannelMessageReactionListLimit limits one messages.getMessageReactionsList page.
|
||||
|
|
@ -99,6 +141,9 @@ const (
|
|||
MaxChannelForumTopicTitleLength = 128
|
||||
// DefaultForumTopicIconColor is Telegram Desktop's General-topic fallback blue.
|
||||
DefaultForumTopicIconColor = 0x6FB9F0
|
||||
// ForumGeneralTopicID 是 General 话题的固定 id(Telegram 协议;客户端 readDiscussion General 用 msg_id=1)。
|
||||
// General 内消息 reply_to_top_id=1,开 forum 前的历史消息 reply_to_top_id=0,二者都归 General。
|
||||
ForumGeneralTopicID = 1
|
||||
// MaxChannelReadMentionsBatch limits one messages.readMentions clearing batch.
|
||||
MaxChannelReadMentionsBatch = 1000
|
||||
// MaxChannelReadReactionsBatch limits one messages.readReactions clearing batch.
|
||||
|
|
@ -144,12 +189,19 @@ type ChannelAdminRights struct {
|
|||
PostMessages bool
|
||||
EditMessages bool
|
||||
DeleteMessages bool
|
||||
PostStories bool
|
||||
EditStories bool
|
||||
DeleteStories bool
|
||||
BanUsers bool
|
||||
InviteUsers bool
|
||||
PinMessages bool
|
||||
AddAdmins bool
|
||||
ManageCall bool
|
||||
Anonymous bool
|
||||
ManageRanks bool
|
||||
// ManageDirectMessages 对应 TL ChatAdminRights.manage_direct_messages(flags.17)。母广播频道的
|
||||
// 管理员据此被客户端授予 monoforum(频道私信)容器的 MonoforumAdmin 身份;creator 走 amCreator 旁路。
|
||||
ManageDirectMessages bool
|
||||
}
|
||||
|
||||
// ChannelBannedRights is a domain-only representation of Telegram banned rights.
|
||||
|
|
@ -166,6 +218,7 @@ type ChannelBannedRights struct {
|
|||
ChangeInfo bool
|
||||
InviteUsers bool
|
||||
PinMessages bool
|
||||
EditRank bool
|
||||
UntilDate int
|
||||
}
|
||||
|
||||
|
|
@ -189,6 +242,83 @@ type ChannelReactionPolicy struct {
|
|||
PaidEnabled bool
|
||||
}
|
||||
|
||||
// AllowsReaction reports whether the policy accepts one message reaction.
|
||||
// The zero policy (Default) behaves like chatReactionsAll without allow_custom:
|
||||
// ordinary emoji reactions are accepted, custom emoji reactions require an
|
||||
// explicit chatReactionsSome entry or chatReactionsAll.allow_custom.
|
||||
func (p ChannelReactionPolicy) AllowsReaction(reaction MessageReaction) bool {
|
||||
if !reaction.Valid() {
|
||||
return false
|
||||
}
|
||||
switch p.Type {
|
||||
case ChannelReactionPolicyNone:
|
||||
return false
|
||||
case ChannelReactionPolicySome:
|
||||
switch reaction.Type {
|
||||
case MessageReactionEmoji:
|
||||
for _, emoticon := range p.Emoticons {
|
||||
if strings.TrimSpace(emoticon) == reaction.Value() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case MessageReactionCustomEmoji:
|
||||
for _, documentID := range p.CustomEmojiIDs {
|
||||
if documentID == reaction.DocumentID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
case ChannelReactionPolicyAll:
|
||||
if reaction.Type == MessageReactionCustomEmoji {
|
||||
return p.AllowCustom
|
||||
}
|
||||
return reaction.Type == MessageReactionEmoji
|
||||
default:
|
||||
return reaction.Type == MessageReactionEmoji
|
||||
}
|
||||
}
|
||||
|
||||
// UniqueReactionsLimit returns the per-message distinct emoji cap for the chat:
|
||||
// channelFull.reactions_limit when set, otherwise the appConfig reactions_uniq_max default.
|
||||
func (p ChannelReactionPolicy) UniqueReactionsLimit() int {
|
||||
if p.Limit > 0 {
|
||||
return p.Limit
|
||||
}
|
||||
return DefaultMessageReactionsUniqMax
|
||||
}
|
||||
|
||||
// MessageReactionsUserMax 返回 viewer 的每用户 reaction 上限档位。
|
||||
func MessageReactionsUserMax(premium bool) int {
|
||||
if premium {
|
||||
return MaxMessageReactionsPerUserPremium
|
||||
}
|
||||
return MaxMessageReactionsPerUser
|
||||
}
|
||||
|
||||
// NormalizeReactionsPerUserMax 把请求携带的档位约束到合法区间:
|
||||
// <=0(旧调用方未填)回退默认档,上限封顶 premium 档。
|
||||
func NormalizeReactionsPerUserMax(perUserMax int) int {
|
||||
if perUserMax <= 0 {
|
||||
return MaxMessageReactionsPerUser
|
||||
}
|
||||
if perUserMax > MaxMessageReactionsPerUserPremium {
|
||||
return MaxMessageReactionsPerUserPremium
|
||||
}
|
||||
return perUserMax
|
||||
}
|
||||
|
||||
// TrimMessageReactionsToUserMax enforces the per-user reaction cap by keeping the newest
|
||||
// entries (clients append new reactions at the end of the vector and drop older ones).
|
||||
// perUserMax 经 NormalizeReactionsPerUserMax 约束;premium viewer 传 premium 档。
|
||||
func TrimMessageReactionsToUserMax(reactions []MessageReaction, perUserMax int) []MessageReaction {
|
||||
perUserMax = NormalizeReactionsPerUserMax(perUserMax)
|
||||
if len(reactions) <= perUserMax {
|
||||
return reactions
|
||||
}
|
||||
return reactions[len(reactions)-perUserMax:]
|
||||
}
|
||||
|
||||
// ChannelPeerColor is a domain-only representation of PeerColor.
|
||||
type ChannelPeerColor struct {
|
||||
HasColor bool
|
||||
|
|
@ -220,6 +350,7 @@ type Channel struct {
|
|||
Title string
|
||||
About string
|
||||
Username string
|
||||
Verified bool
|
||||
Broadcast bool
|
||||
Megagroup bool
|
||||
Forum bool
|
||||
|
|
@ -235,29 +366,52 @@ type Channel struct {
|
|||
PreHistoryHidden bool
|
||||
ParticipantsHidden bool
|
||||
AntiSpam bool
|
||||
LinkedChatID int64
|
||||
SlowmodeSeconds int
|
||||
DefaultBannedRights ChannelBannedRights
|
||||
ReactionPolicy ChannelReactionPolicy
|
||||
Color ChannelPeerColor
|
||||
ProfileColor ChannelPeerColor
|
||||
EmojiStatus ChannelEmojiStatus
|
||||
ParticipantsCount int
|
||||
AdminsCount int
|
||||
KickedCount int
|
||||
BannedCount int
|
||||
TopMessageID int
|
||||
PinnedMessageID int
|
||||
Pts int
|
||||
TTLPeriod int
|
||||
Date int
|
||||
Deleted bool
|
||||
// HasLink 表示频道/群存在未撤销的导出邀请链接。Android send-as 入口会用
|
||||
// megagroup && (public || has_geo || has_link) 判定是否拉取候选列表。
|
||||
HasLink bool
|
||||
LinkedChatID int64
|
||||
// Monoforum 标记本频道是「频道私信(Direct Messages)」的 monoforum 虚拟频道。
|
||||
// LinkedMonoforumID:母频道指向其 monoforum;monoforum 反向指向母频道(双向)。
|
||||
Monoforum bool
|
||||
LinkedMonoforumID int64
|
||||
SlowmodeSeconds int
|
||||
BoostsUnrestrict int
|
||||
DefaultBannedRights ChannelBannedRights
|
||||
ReactionPolicy ChannelReactionPolicy
|
||||
Color ChannelPeerColor
|
||||
ProfileColor ChannelPeerColor
|
||||
EmojiStatus ChannelEmojiStatus
|
||||
Wallpaper *Wallpaper
|
||||
ParticipantsCount int
|
||||
AdminsCount int
|
||||
KickedCount int
|
||||
BannedCount int
|
||||
TopMessageID int
|
||||
PinnedMessageID int
|
||||
Pts int
|
||||
TTLPeriod int
|
||||
Date int
|
||||
Deleted bool
|
||||
// 活跃群通话关联(channel.call_active/call_not_empty flag 与 channelFull.call
|
||||
// 的数据源;客户端拉 dialogs/getFullChannel 时凭它重建 banner)。
|
||||
ActiveCallID int64
|
||||
ActiveCallAccessHash int64
|
||||
ActiveCallNotEmpty bool
|
||||
// 当前头像(反范式存于 channels 表)。PhotoID==0 表示无头像。
|
||||
PhotoID int64
|
||||
PhotoDCID int
|
||||
PhotoStripped []byte
|
||||
}
|
||||
|
||||
// MembersListAdminOnly 表示该频道的成员/订阅者列表仅管理员可查看。广播频道(非
|
||||
// megagroup)的订阅者列表在官方语义里恒为管理员专属——普通订阅者看不到 Subscribers/
|
||||
// Administrators/Channel Settings 等行,也不能枚举订阅者;此外成员被隐藏
|
||||
// (ParticipantsHidden) 时对非管理员同样不可见。超级群(megagroup)默认成员可见。
|
||||
// 该判定只看频道本身,是否放行还需叠加 viewer 是否管理员。
|
||||
func (c Channel) MembersListAdminOnly() bool {
|
||||
return c.ParticipantsHidden || (c.Broadcast && !c.Megagroup)
|
||||
}
|
||||
|
||||
// ChannelMember is one user's channel membership and read state.
|
||||
type ChannelMember struct {
|
||||
ChannelID int64
|
||||
|
|
@ -295,6 +449,7 @@ type ChannelDialog struct {
|
|||
PinnedOrder int
|
||||
UnreadMark bool
|
||||
ViewForumAsMessages bool
|
||||
HasScheduled bool
|
||||
DefaultSendAs *Peer
|
||||
}
|
||||
|
||||
|
|
@ -307,9 +462,32 @@ const (
|
|||
ChannelActionChatAddUser ChannelMessageActionType = "chat_add_user"
|
||||
ChannelActionChatDelete ChannelMessageActionType = "chat_delete_user"
|
||||
ChannelActionChatJoined ChannelMessageActionType = "chat_joined"
|
||||
ChannelActionEditTitle ChannelMessageActionType = "chat_edit_title"
|
||||
ChannelActionTopicCreate ChannelMessageActionType = "topic_create"
|
||||
ChannelActionTopicEdit ChannelMessageActionType = "topic_edit"
|
||||
// ChannelActionChatJoinedByLink 是经邀请链接加入的服务消息,
|
||||
// 渲染为 "X joined the group via invite link"。
|
||||
ChannelActionChatJoinedByLink ChannelMessageActionType = "chat_joined_by_link"
|
||||
ChannelActionEditTitle ChannelMessageActionType = "chat_edit_title"
|
||||
ChannelActionTopicCreate ChannelMessageActionType = "topic_create"
|
||||
ChannelActionTopicEdit ChannelMessageActionType = "topic_edit"
|
||||
// ChannelActionTodoCompletions / ChannelActionTodoAppendTasks 映射
|
||||
// messageActionTodoCompletions / messageActionTodoAppendTasks:超级群
|
||||
// checklist 协作生成的服务消息,经 reply_to 指向原 checklist 消息。
|
||||
ChannelActionTodoCompletions ChannelMessageActionType = "todo_completions"
|
||||
ChannelActionTodoAppendTasks ChannelMessageActionType = "todo_append_tasks"
|
||||
// ChannelActionGroupCall 映射 messageActionGroupCall:started(CallDuration=0)
|
||||
// 与 ended(CallDuration>0)共用同一构造器,官方语义即如此。
|
||||
ChannelActionGroupCall ChannelMessageActionType = "group_call"
|
||||
// ChannelActionInviteToGroupCall 映射 messageActionInviteToGroupCall(被邀请
|
||||
// 者通过频道消息收到可点击的入会卡片,UserIDs 为受邀人)。
|
||||
ChannelActionInviteToGroupCall ChannelMessageActionType = "invite_to_group_call"
|
||||
// ChannelActionBoostApply 映射 messageActionBoostApply。
|
||||
ChannelActionBoostApply ChannelMessageActionType = "boost_apply"
|
||||
// ChannelActionPaidMessagesPrice 映射 messageActionPaidMessagesPrice:
|
||||
// 广播频道 Direct Messages 开关/价格变更的服务消息。
|
||||
ChannelActionPaidMessagesPrice ChannelMessageActionType = "paid_messages_price"
|
||||
// ChannelActionStarGift 映射 messageActionStarGift:频道礼物的 admin-log 快照。
|
||||
ChannelActionStarGift ChannelMessageActionType = "star_gift"
|
||||
// ChannelActionSetChatWallpaper 映射 messageActionSetChatWallPaper:频道外观页设置 wallpaper。
|
||||
ChannelActionSetChatWallpaper ChannelMessageActionType = "set_chat_wallpaper"
|
||||
)
|
||||
|
||||
// ChannelMessageAction describes a service action without depending on tg.*.
|
||||
|
|
@ -323,6 +501,25 @@ type ChannelMessageAction struct {
|
|||
Closed *bool
|
||||
Hidden *bool
|
||||
UserIDs []int64
|
||||
// InviterUserID 仅 chat_joined_by_link 使用(messageActionChatJoinedByLink.inviter_id)。
|
||||
InviterUserID int64
|
||||
// CallID/CallAccessHash/CallDuration 仅 group_call / invite_to_group_call 使用。
|
||||
CallID int64
|
||||
CallAccessHash int64
|
||||
CallDuration int
|
||||
// Boosts 仅 boost_apply 服务消息使用。
|
||||
Boosts int
|
||||
// BroadcastMessagesAllowed/Stars 仅 paid_messages_price 服务消息使用。
|
||||
BroadcastMessagesAllowed bool
|
||||
Stars int64
|
||||
// Completed/Incompleted/TodoItems 仅 todo_* 服务消息使用。
|
||||
Completed []int
|
||||
Incompleted []int
|
||||
TodoItems []MessageTodoItem
|
||||
// StarGift 仅 star_gift 服务消息使用。
|
||||
StarGift *MessageStarGiftAction
|
||||
// Wallpaper 仅 set_chat_wallpaper 服务消息使用。
|
||||
Wallpaper *Wallpaper
|
||||
}
|
||||
|
||||
// ChannelMessage is a single stored message in a channel/supergroup.
|
||||
|
|
@ -333,38 +530,107 @@ type ChannelMessage struct {
|
|||
SenderUserID int64
|
||||
From Peer
|
||||
SendAs *Peer
|
||||
Date int
|
||||
EditDate int
|
||||
Post bool
|
||||
Silent bool
|
||||
NoForwards bool
|
||||
Body string
|
||||
Entities []MessageEntity
|
||||
ReplyTo *MessageReply
|
||||
Forward *MessageForward
|
||||
Discussion *ChannelDiscussionRef
|
||||
Replies *ChannelMessageReplies
|
||||
Reactions *ChannelMessageReactions
|
||||
Action *ChannelMessageAction
|
||||
Media *MessageMedia
|
||||
Pinned bool
|
||||
Mentioned bool
|
||||
MediaUnread bool
|
||||
Pts int
|
||||
Deleted bool
|
||||
// SavedPeer 是 monoforum 私信子会话分组键(按订阅者分组);普通频道消息为零值。
|
||||
SavedPeer Peer
|
||||
Date int
|
||||
EditDate int
|
||||
Post bool
|
||||
Silent bool
|
||||
NoForwards bool
|
||||
Body string
|
||||
Entities []MessageEntity
|
||||
ReplyTo *MessageReply
|
||||
Forward *MessageForward
|
||||
ViaBotID int64
|
||||
// GroupedID 相册分组 id(sendMultiMedia 同组共享非零值,非相册恒 0)。
|
||||
GroupedID int64
|
||||
ReplyMarkup *MessageReplyMarkup
|
||||
Discussion *ChannelDiscussionRef
|
||||
Replies *ChannelMessageReplies
|
||||
Reactions *ChannelMessageReactions
|
||||
Action *ChannelMessageAction
|
||||
Media *MessageMedia
|
||||
// FromBoostsApplied 是发送时的 sender boost 数快照(message.from_boosts_applied)。
|
||||
FromBoostsApplied int
|
||||
TTLPeriod int
|
||||
ExpiresAt int
|
||||
Pinned bool
|
||||
Mentioned bool
|
||||
MediaUnread bool
|
||||
// Views 是 broadcast post 的浏览数聚合;PostAuthor 是 signatures
|
||||
// 开启时的作者展示名快照。
|
||||
ViewsCount int
|
||||
PostAuthor string
|
||||
Pts int
|
||||
Deleted bool
|
||||
}
|
||||
|
||||
// MessageReactionType identifies one stored reaction constructor without depending on TL types.
|
||||
type MessageReactionType string
|
||||
|
||||
const (
|
||||
MessageReactionEmoji MessageReactionType = "emoji"
|
||||
MessageReactionEmoji MessageReactionType = "emoji"
|
||||
MessageReactionCustomEmoji MessageReactionType = "custom_emoji"
|
||||
)
|
||||
|
||||
// MessageReaction describes one supported message reaction value.
|
||||
type MessageReaction struct {
|
||||
Type MessageReactionType
|
||||
Emoticon string
|
||||
Type MessageReactionType
|
||||
Emoticon string
|
||||
DocumentID int64
|
||||
}
|
||||
|
||||
// Value returns the canonical persisted value for a reaction constructor.
|
||||
func (r MessageReaction) Value() string {
|
||||
switch r.Type {
|
||||
case MessageReactionEmoji:
|
||||
return strings.TrimSpace(r.Emoticon)
|
||||
case MessageReactionCustomEmoji:
|
||||
if r.DocumentID <= 0 {
|
||||
return ""
|
||||
}
|
||||
return strconv.FormatInt(r.DocumentID, 10)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// Key returns a stable identity key for de-duplication and aggregation.
|
||||
func (r MessageReaction) Key() string {
|
||||
return string(r.Type) + "\x00" + r.Value()
|
||||
}
|
||||
|
||||
// Valid reports whether a reaction can be persisted as a message reaction.
|
||||
func (r MessageReaction) Valid() bool {
|
||||
switch r.Type {
|
||||
case MessageReactionEmoji:
|
||||
value := r.Value()
|
||||
return value != "" && utf8.RuneCountInString(value) <= MaxChannelReactionEmoticonLength
|
||||
case MessageReactionCustomEmoji:
|
||||
return r.DocumentID > 0
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// MessageReactionFromValue rebuilds a domain reaction from the persisted
|
||||
// reaction_type/reaction_value pair used by stores.
|
||||
func MessageReactionFromValue(reactionType MessageReactionType, value string) (MessageReaction, bool) {
|
||||
switch reactionType {
|
||||
case MessageReactionEmoji:
|
||||
value = strings.TrimSpace(value)
|
||||
reaction := MessageReaction{Type: MessageReactionEmoji, Emoticon: value}
|
||||
return reaction, reaction.Valid()
|
||||
case MessageReactionCustomEmoji:
|
||||
documentID, err := strconv.ParseInt(strings.TrimSpace(value), 10, 64)
|
||||
if err != nil {
|
||||
return MessageReaction{}, false
|
||||
}
|
||||
reaction := MessageReaction{Type: MessageReactionCustomEmoji, DocumentID: documentID}
|
||||
return reaction, reaction.Valid()
|
||||
default:
|
||||
return MessageReaction{}, false
|
||||
}
|
||||
}
|
||||
|
||||
// ChannelMessageReactionCount is an aggregated reaction counter for one message.
|
||||
|
|
@ -393,6 +659,9 @@ type ChannelMessageReactions struct {
|
|||
CanSeeList bool
|
||||
Results []ChannelMessageReactionCount
|
||||
Recent []ChannelMessagePeerReaction
|
||||
// Paid 是付费 reaction(Stars)聚合(nil = 无);读路径从 channel_message_paid_reactions
|
||||
// 填充、tg 转换注入 ReactionPaid 计数 + top reactors。与普通 reaction 分表存储。
|
||||
Paid *ChannelMessagePaidReactions
|
||||
}
|
||||
|
||||
// SetChannelMessageReactionsRequest replaces the current user's reactions for one message.
|
||||
|
|
@ -404,6 +673,9 @@ type SetChannelMessageReactionsRequest struct {
|
|||
Big bool
|
||||
AddToRecent bool
|
||||
Date int
|
||||
// ReactionsPerUserMax 是 viewer 的每用户上限档位(premium 双档);
|
||||
// 0 表示未填,store 侧按默认档裁剪。
|
||||
ReactionsPerUserMax int
|
||||
}
|
||||
|
||||
// ChannelMessageReactionsResult describes one reaction update.
|
||||
|
|
@ -516,7 +788,11 @@ const (
|
|||
ChannelUpdateDeleteMessages ChannelUpdateEventType = "delete_channel_messages"
|
||||
ChannelUpdateParticipant ChannelUpdateEventType = "channel_participant"
|
||||
ChannelUpdatePinnedMessages ChannelUpdateEventType = "pinned_channel_messages"
|
||||
ChannelUpdateNoop ChannelUpdateEventType = "noop"
|
||||
// ChannelUpdateWebPage 映射 updateChannelWebPage:频道消息的 pending 链接预览异步解析后
|
||||
// 就地替换为已解析卡片(按 webPage id 关联,不标记「已编辑」)。与 edit_channel_message
|
||||
// 同构(携频道 pts + 消息快照),difference/fan-out 复用,仅 tg 投影构造器不同。
|
||||
ChannelUpdateWebPage ChannelUpdateEventType = "channel_web_page"
|
||||
ChannelUpdateNoop ChannelUpdateEventType = "noop"
|
||||
)
|
||||
|
||||
// ChannelUpdateEvent is the channel-scoped durable update log entry.
|
||||
|
|
@ -582,6 +858,7 @@ const (
|
|||
ChannelAdminLogParticipantLeave ChannelAdminLogEventType = "participant_leave"
|
||||
ChannelAdminLogParticipantPromote ChannelAdminLogEventType = "participant_promote"
|
||||
ChannelAdminLogParticipantDemote ChannelAdminLogEventType = "participant_demote"
|
||||
ChannelAdminLogParticipantEditRank ChannelAdminLogEventType = "participant_edit_rank"
|
||||
ChannelAdminLogParticipantBan ChannelAdminLogEventType = "participant_ban"
|
||||
ChannelAdminLogParticipantUnban ChannelAdminLogEventType = "participant_unban"
|
||||
ChannelAdminLogParticipantKick ChannelAdminLogEventType = "participant_kick"
|
||||
|
|
@ -664,9 +941,14 @@ type ChannelAdminLogResult struct {
|
|||
|
||||
// ChannelView contains channel data personalized for a viewer.
|
||||
type ChannelView struct {
|
||||
Channel Channel
|
||||
Self ChannelMember
|
||||
Dialog ChannelDialog
|
||||
Channel Channel
|
||||
Self ChannelMember
|
||||
Dialog ChannelDialog
|
||||
SelfBoostsApplied int
|
||||
ExportedInvite *ChannelInvite
|
||||
// Forbidden 表示当前 viewer 被踢/被禁止查看:查询响应必须呈现
|
||||
// channelForbidden 形态而不是省略,客户端靠它感知自己已离开会话。
|
||||
Forbidden bool
|
||||
}
|
||||
|
||||
// ChannelParticipantList is a paged participant response.
|
||||
|
|
@ -730,7 +1012,7 @@ type ChannelRecommendationsRequest struct {
|
|||
Limit int
|
||||
}
|
||||
|
||||
// ChannelRecommendationsResult contains public broadcast channel recommendations and total count.
|
||||
// ChannelRecommendationsResult contains public broadcast recommendations and a bounded count hint.
|
||||
type ChannelRecommendationsResult struct {
|
||||
Count int
|
||||
Channels []Channel
|
||||
|
|
@ -876,6 +1158,23 @@ type EditChannelTitleResult struct {
|
|||
Recipients []int64
|
||||
}
|
||||
|
||||
// SetChannelWallpaperRequest sets or clears a channel wallpaper and may emit a service message.
|
||||
type SetChannelWallpaperRequest struct {
|
||||
UserID int64
|
||||
ChannelID int64
|
||||
Wallpaper *Wallpaper
|
||||
Date int
|
||||
}
|
||||
|
||||
// SetChannelWallpaperResult describes a channel wallpaper change.
|
||||
type SetChannelWallpaperResult struct {
|
||||
Channel Channel
|
||||
Message ChannelMessage
|
||||
Event ChannelUpdateEvent
|
||||
Recipients []int64
|
||||
Changed bool
|
||||
}
|
||||
|
||||
// EditChannelAboutRequest modifies a channel/supergroup description.
|
||||
type EditChannelAboutRequest struct {
|
||||
UserID int64
|
||||
|
|
@ -904,6 +1203,16 @@ type EditChannelAdminResult struct {
|
|||
Date int
|
||||
}
|
||||
|
||||
// EditChannelMemberRankRequest sets or clears a participant's member tag (rank)
|
||||
// without touching their role or admin rights.
|
||||
type EditChannelMemberRankRequest struct {
|
||||
UserID int64
|
||||
ChannelID int64
|
||||
MemberID int64
|
||||
Rank string
|
||||
Date int
|
||||
}
|
||||
|
||||
// EditChannelBannedRequest modifies a participant's banned rights.
|
||||
type EditChannelBannedRequest struct {
|
||||
UserID int64
|
||||
|
|
@ -929,6 +1238,10 @@ type EditChannelBannedResult struct {
|
|||
Event ChannelUpdateEvent
|
||||
Recipients []int64
|
||||
Date int
|
||||
// Message/ServiceEvent 是 megagroup 踢人产生的 "X removed Y" 服务
|
||||
// 消息及其 channel pts 事件;纯禁言/解禁不生成。
|
||||
Message ChannelMessage
|
||||
ServiceEvent ChannelUpdateEvent
|
||||
}
|
||||
|
||||
// DeleteChannelRequest deletes a channel/supergroup. Only the creator may do this.
|
||||
|
|
@ -949,24 +1262,88 @@ type UpdateChannelUsernameRequest struct {
|
|||
type DeleteChannelResult struct {
|
||||
Channel Channel
|
||||
Recipients []int64
|
||||
// LinkedMonoforum 是随母广播频道一并软删的关联 monoforum(频道私信容器)。删父频道必须连带删它,
|
||||
// 否则会留下 monoforum=true 但 linked_monoforum_id 指向已删父频道的孤儿(客户端渲染会崩)。
|
||||
// 仅删带 Direct Messages 的母频道时非 nil;普通频道为 nil。
|
||||
LinkedMonoforum *Channel
|
||||
}
|
||||
|
||||
// SendChannelMessageRequest sends one channel/supergroup message.
|
||||
type SendChannelMessageRequest struct {
|
||||
UserID int64
|
||||
ChannelID int64
|
||||
RandomID int64
|
||||
Message string
|
||||
Entities []MessageEntity
|
||||
Media *MessageMedia
|
||||
MentionUserIDs []int64
|
||||
Silent bool
|
||||
NoForwards bool
|
||||
ReplyTo *MessageReply
|
||||
Forward *MessageForward
|
||||
SendAs *Peer
|
||||
Action *ChannelMessageAction
|
||||
Date int
|
||||
UserID int64
|
||||
ChannelID int64
|
||||
RandomID int64
|
||||
Message string
|
||||
Entities []MessageEntity
|
||||
Media *MessageMedia
|
||||
MentionUserIDs []int64
|
||||
SkipDeliveryUserIDs []int64
|
||||
// SkipRecipientLookup lets high-level realtime fan-out use the online member
|
||||
// read model instead of forcing store.SendChannelMessage to synchronously
|
||||
// return an active-member recipient list after commit.
|
||||
SkipRecipientLookup bool
|
||||
// PostAuthor 是 signatures 开启的 broadcast post 上快照的作者展示名。
|
||||
PostAuthor string
|
||||
Silent bool
|
||||
NoForwards bool
|
||||
ReplyTo *MessageReply
|
||||
Forward *MessageForward
|
||||
ViaBotID int64
|
||||
// GroupedID 相册分组 id(sendMultiMedia 同组共享非零值,非相册恒 0)。
|
||||
GroupedID int64
|
||||
ReplyMarkup *MessageReplyMarkup
|
||||
SendAs *Peer
|
||||
Action *ChannelMessageAction
|
||||
Date int
|
||||
TTLPeriod int
|
||||
}
|
||||
|
||||
// SendMonoforumMessageRequest 向频道私信(monoforum)发送一条消息。MonoforumID 是 monoforum
|
||||
// 虚拟频道 id;SavedPeer 是订阅者子会话分组键(订阅者发=自己,管理员回复=目标订阅者);
|
||||
// SenderUserID 是实际发件人。发件权限(订阅者身份/管理员)在 RPC 层校验,store 只校验 monoforum 存在。
|
||||
type SendMonoforumMessageRequest struct {
|
||||
MonoforumID int64
|
||||
SenderUserID int64
|
||||
SavedPeer Peer
|
||||
RandomID int64
|
||||
Message string
|
||||
Entities []MessageEntity
|
||||
Date int
|
||||
}
|
||||
|
||||
// MonoforumHistoryFilter 按订阅者子会话拉取 monoforum 私信历史。
|
||||
type MonoforumHistoryFilter struct {
|
||||
MonoforumID int64
|
||||
SavedPeer Peer
|
||||
Limit int
|
||||
OffsetID int
|
||||
}
|
||||
|
||||
// MonoforumDialog 是频道私信(monoforum)中一个订阅者子会话的摘要。读水位/未读由后续 P0
|
||||
// 切片补齐,当前置 0。
|
||||
type MonoforumDialog struct {
|
||||
SavedPeer Peer
|
||||
TopMessageID int
|
||||
TopMessageDate int
|
||||
UnreadCount int
|
||||
ReadInboxMaxID int
|
||||
ReadOutboxMaxID int
|
||||
}
|
||||
|
||||
// MonoforumDialogList 是 monoforum 订阅者子会话列表(按各子会话 top 消息 id 倒序)。
|
||||
type MonoforumDialogList struct {
|
||||
MonoforumID int64
|
||||
Channel Channel
|
||||
Dialogs []MonoforumDialog
|
||||
Messages []ChannelMessage
|
||||
Count int
|
||||
}
|
||||
|
||||
// MonoforumDialogsFilter 分页拉取 monoforum 订阅者子会话列表(按 top 消息 id 倒序 seek)。
|
||||
type MonoforumDialogsFilter struct {
|
||||
MonoforumID int64
|
||||
Limit int
|
||||
OffsetID int
|
||||
}
|
||||
|
||||
// SaveChannelDefaultSendAsRequest stores the current user's default send-as peer for a channel dialog.
|
||||
|
|
@ -985,9 +1362,13 @@ type ChannelMessageViewsRequest struct {
|
|||
Date int
|
||||
}
|
||||
|
||||
// ChannelMessageViewsResult returns current view counters by visible message id.
|
||||
// ChannelMessageViewsResult returns current view counters and lightweight reply
|
||||
// counters by visible message id.
|
||||
type ChannelMessageViewsResult struct {
|
||||
Views map[int]int
|
||||
Channel Channel
|
||||
Views map[int]int
|
||||
Replies map[int]*ChannelMessageReplies
|
||||
Peers []Peer
|
||||
}
|
||||
|
||||
// ReadChannelMessageContentsRequest marks channel/supergroup content-read hints for one viewer.
|
||||
|
|
@ -1002,6 +1383,10 @@ type ReadChannelMessageContentsResult struct {
|
|||
Channel Channel
|
||||
Messages []ChannelMessage
|
||||
ClearedUnreadReactionMessageIDs []int
|
||||
// ClearedUnreadMentionMessageIDs 是本次内容已读翻转为已读的 mention
|
||||
// 消息;客户端视口看到 @ 消息即发 readMessageContents,服务端必须
|
||||
// 同步清除否则角标在下一次 getDialogs 复活。
|
||||
ClearedUnreadMentionMessageIDs []int
|
||||
}
|
||||
|
||||
// GetChannelMessageAuthorRequest resolves the original user author of one channel message.
|
||||
|
|
@ -1018,6 +1403,13 @@ type GetChannelMessageAuthorResult struct {
|
|||
SenderUserID int64
|
||||
}
|
||||
|
||||
// ChannelPaidMessagesPriceResult describes a paid/direct-message price setting change.
|
||||
type ChannelPaidMessagesPriceResult struct {
|
||||
Channel Channel
|
||||
ServiceMessage *SendChannelMessageResult
|
||||
ServiceMessages []SendChannelMessageResult
|
||||
}
|
||||
|
||||
// SendChannelMessageResult describes a channel message send.
|
||||
type SendChannelMessageResult struct {
|
||||
Channel Channel
|
||||
|
|
@ -1026,6 +1418,13 @@ type SendChannelMessageResult struct {
|
|||
Recipients []int64
|
||||
Duplicate bool
|
||||
Discussion *SendChannelDiscussionResult
|
||||
// MentionUserIDs 是本条消息解析出的被 @ 成员;在线 fanout 按它为
|
||||
// 每个接收者投影 message.mentioned/media_unread。
|
||||
MentionUserIDs []int64
|
||||
// SkipDeliveryUserIDs 是本条消息按 bot privacy 规则被排除投递的成员(隐私 bot 对
|
||||
// 命令/@/回复以外的消息不可见)。Recipients 已扣除它们;在线 fanout 还须据此跳过这些
|
||||
// 成员的直接推送,否则在线 bot 仍能实时收到群里全部消息(持久 history/difference 已隐藏)。
|
||||
SkipDeliveryUserIDs []int64
|
||||
}
|
||||
|
||||
// SendChannelDiscussionResult describes the discussion megagroup root created for a broadcast post.
|
||||
|
|
@ -1034,6 +1433,9 @@ type SendChannelDiscussionResult struct {
|
|||
Message ChannelMessage
|
||||
Event ChannelUpdateEvent
|
||||
Recipients []int64
|
||||
// MentionUserIDs 透传 post 的 @ 目标:讨论组联动消息的实时推送也要
|
||||
// 按接收者投影 mentioned/media_unread。
|
||||
MentionUserIDs []int64
|
||||
}
|
||||
|
||||
// CreateChannelForumTopicRequest creates one forum topic root service message.
|
||||
|
|
@ -1121,21 +1523,44 @@ type DeleteChannelForumTopicHistoryRequest struct {
|
|||
}
|
||||
|
||||
// EditChannelMessageRequest edits one text message in a channel/supergroup.
|
||||
// Media 非 nil 时整体替换消息媒体快照(当前唯一调用方是 live location 续报/停止)。
|
||||
type EditChannelMessageRequest struct {
|
||||
UserID int64
|
||||
ChannelID int64
|
||||
ID int
|
||||
Message string
|
||||
Entities []MessageEntity
|
||||
EditDate int
|
||||
Media *MessageMedia
|
||||
// SetReplyMarkup 置位时替换 reply_markup(ReplyMarkup 为 nil/空 = 清空键盘)。
|
||||
SetReplyMarkup bool
|
||||
ReplyMarkup *MessageReplyMarkup
|
||||
// ViaBotEditBotID 非零时要求目标消息 via_bot_id 匹配对应 bot。
|
||||
ViaBotEditBotID int64
|
||||
// AllowTodoParticipantMutation 允许非作者普通成员在 checklist 的
|
||||
// others_can_* 授权下仅替换 todo media 快照;不放开普通文本/媒体编辑。
|
||||
AllowTodoParticipantMutation bool
|
||||
// TodoServiceAction 非 nil 时,编辑同事务追加一条 reply 到原 checklist
|
||||
// 的 todo 服务消息,并生成独立 channel pts。
|
||||
TodoServiceAction *ChannelMessageAction
|
||||
// MentionUserIDs 是编辑后文本解析出的 @ 目标:新增者补未读提及、
|
||||
// 被移除者清除(reply 隐式提及不受影响)。
|
||||
MentionUserIDs []int64
|
||||
EditDate int
|
||||
// WebPageResolve 置位时为服务端内部「频道链接预览就地替换」:仅换 media(不碰 body/
|
||||
// entities/edit_date),生成 ChannelUpdateWebPage 而非 edit_channel_message。幂等守卫:
|
||||
// 仅当目标当前 media 仍是 ID==ExpectedWebPageID 的 pending 链接预览才替换。
|
||||
WebPageResolve bool
|
||||
ExpectedWebPageID int64
|
||||
}
|
||||
|
||||
// EditChannelMessageResult describes one channel edit update.
|
||||
type EditChannelMessageResult struct {
|
||||
Channel Channel
|
||||
Message ChannelMessage
|
||||
Event ChannelUpdateEvent
|
||||
Recipients []int64
|
||||
Channel Channel
|
||||
Message ChannelMessage
|
||||
Event ChannelUpdateEvent
|
||||
ServiceMessage ChannelMessage
|
||||
ServiceEvent ChannelUpdateEvent
|
||||
Recipients []int64
|
||||
}
|
||||
|
||||
// DeleteChannelMessagesRequest deletes a bounded set of channel/supergroup messages.
|
||||
|
|
@ -1152,6 +1577,16 @@ type DeleteChannelMessagesResult struct {
|
|||
Event ChannelUpdateEvent
|
||||
DeletedIDs []int
|
||||
Recipients []int64
|
||||
// DiscussionDeletes 是被删 broadcast post 在 linked 讨论组里的转发根
|
||||
// 级联删除(官方删 post 同时删除讨论根)。
|
||||
DiscussionDeletes []ChannelCascadeDelete
|
||||
}
|
||||
|
||||
// ChannelCascadeDelete 描述一次跨频道的级联删除(如讨论根随 post 删除)。
|
||||
type ChannelCascadeDelete struct {
|
||||
Channel Channel
|
||||
Event ChannelUpdateEvent
|
||||
Recipients []int64
|
||||
}
|
||||
|
||||
// DeleteChannelHistoryRequest clears or deletes a bounded channel/supergroup history page.
|
||||
|
|
@ -1192,12 +1627,23 @@ type UpdateChannelPinnedMessageRequest struct {
|
|||
}
|
||||
|
||||
// UpdateChannelPinnedMessageResult describes one pinned-message update.
|
||||
// 多置顶模型:pin/unpin 互不影响其它置顶,Event.MessageIDs 仅含本次操作的
|
||||
// 消息(unpinAll 时为本批全部清除的 id)。
|
||||
type UpdateChannelPinnedMessageResult struct {
|
||||
Channel Channel
|
||||
Event ChannelUpdateEvent
|
||||
Channel Channel
|
||||
Event ChannelUpdateEvent
|
||||
// UnpinEvent 携带单置顶替换时旧置顶的 unpin 事件(无则 Pts=0)。
|
||||
UnpinEvent ChannelUpdateEvent
|
||||
Recipients []int64
|
||||
}
|
||||
|
||||
// UnpinAllChannelMessagesRequest clears every pinned message in one channel.
|
||||
type UnpinAllChannelMessagesRequest struct {
|
||||
UserID int64
|
||||
ChannelID int64
|
||||
Date int
|
||||
}
|
||||
|
||||
// ChannelInvite is an exported invite link without TL dependencies.
|
||||
type ChannelInvite struct {
|
||||
ChannelID int64
|
||||
|
|
@ -1379,6 +1825,7 @@ type ChannelHistoryFilter struct {
|
|||
Query string
|
||||
SenderUserID int64
|
||||
PinnedOnly bool
|
||||
MusicOnly bool
|
||||
OffsetID int
|
||||
OffsetDate int
|
||||
AddOffset int
|
||||
|
|
@ -1406,6 +1853,7 @@ type ChannelGlobalSearchRequest struct {
|
|||
Query string
|
||||
BroadcastsOnly bool
|
||||
GroupsOnly bool
|
||||
MusicOnly bool
|
||||
HasFolderID bool
|
||||
FolderID int
|
||||
OffsetRate int
|
||||
|
|
@ -1523,8 +1971,32 @@ type ReadChannelHistoryResult struct {
|
|||
StillUnreadCount int
|
||||
Changed bool
|
||||
Pts int
|
||||
Dialog ChannelDialog
|
||||
OutboxUpdates []ChannelReadOutboxUpdate
|
||||
// Forum 标记该频道是否为话题群。RPC 层据此在频道级 readHistory 后顺带推进
|
||||
// General(topic 1) 的话题级已读水位(General 消息即频道根历史,被频道级已读覆盖)。
|
||||
Forum bool
|
||||
Dialog ChannelDialog
|
||||
OutboxUpdates []ChannelReadOutboxUpdate
|
||||
}
|
||||
|
||||
// ReadChannelTopicHistoryRequest 推进 forum 单个话题的 per-viewer 已读水位(messages.readDiscussion)。
|
||||
// TopicID = 话题根消息 id(General=1)。不碰频道级 channel_members.read_inbox_max_id。
|
||||
type ReadChannelTopicHistoryRequest struct {
|
||||
UserID int64
|
||||
ChannelID int64
|
||||
TopicID int
|
||||
MaxID int
|
||||
Date int
|
||||
}
|
||||
|
||||
// ReadChannelTopicHistoryResult 描述一次 per-topic 已读推进结果。OutboxUpdates 每条 UserID 是
|
||||
// 该话题内待收已读回执的发送者,MaxID 为其消息被读到的水位;话题 id 即 Result.TopicID。
|
||||
type ReadChannelTopicHistoryResult struct {
|
||||
Channel Channel
|
||||
TopicID int
|
||||
MaxID int
|
||||
Changed bool
|
||||
Pts int
|
||||
OutboxUpdates []ChannelReadOutboxUpdate
|
||||
}
|
||||
|
||||
// ChannelReadOutboxUpdate advances one sender's channel outbox read watermark.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue