internal/domain/update_event.go
Rama main · réplica de lectura del repositorio original.
package domain
// UpdateEventType identifies the update queue event type.
type UpdateEventType string
const (
UpdateEventNewMessage UpdateEventType = "new_message"
UpdateEventReadHistoryInbox UpdateEventType = "read_history_inbox"
UpdateEventReadHistoryOutbox UpdateEventType = "read_history_outbox"
// Forum topic-level read: sent after messages.readDiscussion advances the per-topic watermark.
UpdateEventReadChannelDiscussionInbox UpdateEventType = "read_channel_discussion_inbox"
UpdateEventReadChannelDiscussionOutbox UpdateEventType = "read_channel_discussion_outbox"
UpdateEventReadMessageContents UpdateEventType = "read_message_contents"
UpdateEventEditMessage UpdateEventType = "edit_message"
// UpdateEventBotCallbackQuery is used only for the Bot API-specific update_id queue projection; it does not write account
// pts/difference/outbox.
UpdateEventBotCallbackQuery UpdateEventType = "bot_callback_query"
// UpdateEventBotPreCheckoutQuery, like callback, only serves the Bot API queue projection;
// it does not write account pts/difference/outbox. The payer waits in the payment RPC for the bot's answer, see
// precheckout_registry.go.
UpdateEventBotPreCheckoutQuery UpdateEventType = "bot_pre_checkout_query"
// UpdateEventWebPage maps updateWebPage: after async parsing completes it replaces the pending link preview
// placeholder in the message in place with the resolved card. It carries account pts (not LacksWirePts), and the message snapshot is rebuilt via a box JOIN,
// so difference/dispatch follows the generic message event path like edit_message, differing only in the tg projection constructor.
UpdateEventWebPage UpdateEventType = "web_page"
// UpdateEventMessageWidgetData maps updateMessageWidgetData (Layer 233): a
// bot web widget's public/chat data changed in place (body/entities/edit_date
// untouched, so the message is not marked edited). It carries account pts.
UpdateEventMessageWidgetData UpdateEventType = "message_widget_data"
// UpdateEventMessagePoll maps updateMessagePoll (poll state changes after a vote/close;
// Message is the message from that owner's perspective, and the media is re-enriched per viewer when difference replays it).
// The current history implementation still treats poll as a to-be-reviewed LacksWirePts event.
UpdateEventMessagePoll UpdateEventType = "message_poll"
UpdateEventContactsReset UpdateEventType = "contacts_reset"
UpdateEventDialogPinned UpdateEventType = "dialog_pinned"
UpdateEventPinnedDialogs UpdateEventType = "pinned_dialogs"
UpdateEventDialogUnreadMark UpdateEventType = "dialog_unread_mark"
UpdateEventPeerSettings UpdateEventType = "peer_settings"
UpdateEventPeerStoryBlocked UpdateEventType = "peer_story_blocked"
// UpdateEventUserPhone is used only to read updateUserPhone events persisted by historical versions.
// The TL constructor carries no pts, and the current write path must no longer produce this event.
UpdateEventUserPhone UpdateEventType = "user_phone"
// UpdateEventUserEmojiStatus carries the exact immutable status snapshot.
// It consumes account pts even though updateUserEmojiStatus has no pts.
UpdateEventUserEmojiStatus UpdateEventType = "user_emoji_status"
UpdateEventDeleteMessages UpdateEventType = "delete_messages"
// UpdateEventPinnedMessages maps updatePinnedMessages (private-chat pin/unpin;
// MessageIDs are the box ids from that owner's own perspective, and Bool is pinned).
// The TL constructor carries its own account pts/pts_count and is not LacksWirePts.
UpdateEventPinnedMessages UpdateEventType = "pinned_messages"
UpdateEventDialogFilter UpdateEventType = "dialog_filter"
UpdateEventDialogFilterOrder UpdateEventType = "dialog_filter_order"
UpdateEventDialogFilters UpdateEventType = "dialog_filters"
UpdateEventFolderPeers UpdateEventType = "folder_peers"
UpdateEventChannelViewForum UpdateEventType = "channel_view_forum_as_messages"
UpdateEventStory UpdateEventType = "story"
UpdateEventReadStories UpdateEventType = "read_stories"
UpdateEventSentStoryReaction UpdateEventType = "sent_story_reaction"
UpdateEventNewStoryReaction UpdateEventType = "new_story_reaction"
UpdateEventQuickReplies UpdateEventType = "quick_replies"
UpdateEventNewQuickReply UpdateEventType = "new_quick_reply"
UpdateEventDeleteQuickReply UpdateEventType = "delete_quick_reply"
UpdateEventQuickReplyMessage UpdateEventType = "quick_reply_message"
UpdateEventDeleteQuickReplyMessages UpdateEventType = "delete_quick_reply_messages"
// UpdateEventChannelState means the current account's membership in a channel changed
// (leave/kick); an offline device receiving updateChannel via difference re-fetches
// the channel state and removes the chat.
UpdateEventChannelState UpdateEventType = "channel_state"
// UpdateEventDraftMessage maps updateDraftMessage (cloud draft change; Peer is the chat and
// MaxID is reused as the forum top_msg_id). The event is only a marker that "this chat's draft changed" — a draft is
// absolute state, not a delta, so a difference/outbox replay reloads the current draft by Peer to fill the Draft
// field (or sends draftMessageEmpty if deleted), not freezing a content snapshot in the event row.
UpdateEventDraftMessage UpdateEventType = "draft_message"
// UpdateEventSavedDialogPinned maps updateSavedDialogPinned (a saved-messages
// sub-chat pin flip; Peer is the sub-chat grouping key and Bool is pinned).
UpdateEventSavedDialogPinned UpdateEventType = "saved_dialog_pinned"
// UpdateEventPinnedSavedDialogs maps updatePinnedSavedDialogs
// (the full saved-messages pin order table; Peers is the new order).
UpdateEventPinnedSavedDialogs UpdateEventType = "pinned_saved_dialogs"
UpdateEventNoop UpdateEventType = "noop"
)
// UpdateEvent is an account-perspective incremental event, persisted in user_id + pts order.
type UpdateEvent struct {
UserID int64
Type UpdateEventType
Pts int
PtsCount int
Date int
Message Message
Story Story
Peer Peer
Peers []Peer
Bool bool
Phone string
EmojiStatus UserEmojiStatus
Settings PeerSettings
MessageIDs []int
MaxID int
StillUnreadCount int
ChannelPts int
// TopMsgID is used only by the forum per-topic read events (read_channel_discussion_*): it carries the topic id
// (General=1), mapping updateReadChannelDiscussionInbox/Outbox together with MaxID(=read_max_id).
TopMsgID int
Users []User
Channels []Channel
FilterID int
// FolderID is the physical folder the chat was in when the read-class event occurred (0 main list/1 archive),
// filled into updateReadChannelInbox.folder_id.
FolderID int
DialogFilter *DialogFolder
// Draft is used only by draft_message events: not persisted, it is filled by reloading the current draft by
// Peer (+MaxID=top_msg_id) during a difference/outbox replay; nil means the draft was deleted (sends empty).
Draft *DialogDraft
FilterOrder []int
FolderPeers []FolderPeerUpdate
TagsEnabled bool
Reaction *MessageReaction
QuickReplies []QuickReply
QuickReply QuickReply
QuickReplyMessage QuickReplyMessage
BotCallbackQuery *BotCallbackQuery
// BotPreCheckout carries the pre-checkout query itself; this event has no message and Peer/MessageID are zero.
BotPreCheckout *BotPreCheckoutQuery
// BotAPIUpdateID is the HTTP Bot API update_id. It is intentionally separate
// from MTProto Pts: Bot API ephemeral envelopes never advance account state.
BotAPIUpdateID int64
EphemeralMessage *EphemeralMessage
}
// LacksWirePts means the event consumed account pts, but its corresponding TL update constructor has no
// account pts field (reaction, channel read, dialog/folder/settings state classes).
// Online delivery of such events must carry explicit pts bookkeeping, or the client watermark drifts from the server's
// and the next genuinely pts-bearing update is judged a gap.
func (e UpdateEvent) LacksWirePts() bool {
switch e.Type {
case UpdateEventMessagePoll,
UpdateEventDraftMessage,
UpdateEventChannelState,
UpdateEventContactsReset,
UpdateEventDialogPinned,
UpdateEventPinnedDialogs,
UpdateEventSavedDialogPinned,
UpdateEventPinnedSavedDialogs,
UpdateEventDialogUnreadMark,
UpdateEventPeerSettings,
UpdateEventPeerStoryBlocked,
UpdateEventUserPhone,
UpdateEventUserEmojiStatus,
UpdateEventDialogFilter,
UpdateEventDialogFilterOrder,
UpdateEventDialogFilters,
UpdateEventChannelViewForum,
UpdateEventStory,
UpdateEventReadStories,
UpdateEventSentStoryReaction,
UpdateEventNewStoryReaction,
UpdateEventQuickReplies,
UpdateEventNewQuickReply,
UpdateEventDeleteQuickReply,
UpdateEventQuickReplyMessage,
UpdateEventDeleteQuickReplyMessages:
// updateFolderPeers carries its own pts/pts_count and is not in this list.
return true
case UpdateEventReadChannelDiscussionInbox, UpdateEventReadChannelDiscussionOutbox:
// Forum topic read maps updateReadChannelDiscussionInbox/Outbox and has no account pts field.
return true
case UpdateEventReadHistoryInbox, UpdateEventReadHistoryOutbox:
// A channel peer maps updateReadChannelInbox/Outbox and has no account pts field;
// the private-chat form carries its own pts/pts_count.
return e.Peer.Type == PeerTypeChannel
default:
return false
}
}
// UpdateDifference is the business-layer result of updates.getDifference.
type UpdateDifference struct {
State UpdateState
Events []UpdateEvent
ChannelNudges []ChannelDifferenceNudge
// Partial being true means the continuous events were truncated by the limit and more remain (maps updates.differenceSlice,
// and the client keeps paging from State); false means the current continuous end was reached (updates.difference).
Partial bool
}
// ChannelDifferenceNudge is a computed account-level hint that a channel diff is dirty.
type ChannelDifferenceNudge struct {
ChannelID int64
Pts int
ChannelUpdatesDirty bool
AvailableMinID int
HistoryClearDate int
Channel *ChannelView
}