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

@ -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 话题的固定 idTelegram 协议;客户端 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 映射 messageActionGroupCallstartedCallDuration=0
// 与 endedCallDuration>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 相册分组 idsendMultiMedia 同组共享非零值,非相册恒 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 是付费 reactionStars聚合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 相册分组 idsendMultiMedia 同组共享非零值,非相册恒 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_markupReplyMarkup 为 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 = 话题根消息 idGeneral=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.