chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
595
internal/rpc/convert_updates.go
Normal file
595
internal/rpc/convert_updates.go
Normal file
|
|
@ -0,0 +1,595 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/gotd/td/tg"
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
func tgUpdateState(st domain.UpdateState) tg.UpdatesState {
|
||||
return tg.UpdatesState{Pts: st.Pts, Qts: st.Qts, Date: st.Date, Seq: st.Seq}
|
||||
}
|
||||
|
||||
func tgUpdatesDifference(viewerUserID int64, diff domain.UpdateDifference) tg.UpdatesDifferenceClass {
|
||||
out := &tg.UpdatesDifference{
|
||||
NewMessages: make([]tg.MessageClass, 0, len(diff.Events)),
|
||||
OtherUpdates: make([]tg.UpdateClass, 0, len(diff.Events)),
|
||||
Users: make([]tg.UserClass, 0, 1),
|
||||
Chats: make([]tg.ChatClass, 0, 1),
|
||||
}
|
||||
seenUsers := make(map[int64]struct{})
|
||||
seenChats := make(map[int64]struct{})
|
||||
for _, event := range diff.Events {
|
||||
addUsers(out, seenUsers, viewerUserID, event.Users)
|
||||
addChannels(out, seenChats, event.UserID, event.Channels)
|
||||
switch event.Type {
|
||||
case domain.UpdateEventNewMessage:
|
||||
if msg := tgMessage(event.Message); msg != nil {
|
||||
out.NewMessages = append(out.NewMessages, msg)
|
||||
addMessageUsers(out, seenUsers, event.Message)
|
||||
}
|
||||
case domain.UpdateEventReadHistoryInbox:
|
||||
if update := tgReadHistoryInboxUpdate(event); update != nil {
|
||||
out.OtherUpdates = append(out.OtherUpdates, update)
|
||||
}
|
||||
case domain.UpdateEventReadHistoryOutbox:
|
||||
if update := tgReadHistoryOutboxUpdate(event); update != nil {
|
||||
out.OtherUpdates = append(out.OtherUpdates, update)
|
||||
}
|
||||
case domain.UpdateEventMessageReactions, domain.UpdateEventMessagePoll:
|
||||
// 同时下发消息快照(含最新聚合)与对应通知 update;事件无 TL pts,
|
||||
// pts 推进靠 difference state 本身。
|
||||
if msg := tgMessage(event.Message); msg != nil {
|
||||
out.NewMessages = append(out.NewMessages, msg)
|
||||
addMessageUsers(out, seenUsers, event.Message)
|
||||
}
|
||||
if update := tgOtherUpdateFromEvent(event); update != nil {
|
||||
out.OtherUpdates = append(out.OtherUpdates, update)
|
||||
}
|
||||
default:
|
||||
if update := tgOtherUpdateFromEvent(event); update != nil {
|
||||
out.OtherUpdates = append(out.OtherUpdates, update)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, nudge := range diff.ChannelNudges {
|
||||
if nudge.ChannelID == 0 {
|
||||
continue
|
||||
}
|
||||
update := &tg.UpdateChannelTooLong{ChannelID: nudge.ChannelID}
|
||||
if nudge.Pts > 0 {
|
||||
update.SetPts(nudge.Pts)
|
||||
}
|
||||
out.OtherUpdates = append(out.OtherUpdates, update)
|
||||
if nudge.Channel != nil && nudge.Channel.Channel.ID != 0 {
|
||||
addChannelNudgeChat(out, seenChats, tgChannelChatForView(viewerUserID, *nudge.Channel))
|
||||
}
|
||||
}
|
||||
// Partial:连续事件被 limit 截断、后面还有 → updates.differenceSlice,客户端据 IntermediateState 续拉。
|
||||
if diff.Partial {
|
||||
return &tg.UpdatesDifferenceSlice{
|
||||
NewMessages: out.NewMessages,
|
||||
OtherUpdates: out.OtherUpdates,
|
||||
Chats: out.Chats,
|
||||
Users: out.Users,
|
||||
IntermediateState: tgUpdateState(diff.State),
|
||||
}
|
||||
}
|
||||
out.State = tgUpdateState(diff.State)
|
||||
return out
|
||||
}
|
||||
|
||||
func tgChannelDifference(viewerUserID int64, diff domain.ChannelDifference) tg.UpdatesChannelDifferenceClass {
|
||||
if diff.TooLong {
|
||||
messages := make([]tg.MessageClass, 0, len(diff.NewMessages))
|
||||
for _, msg := range diff.NewMessages {
|
||||
if item := tgChannelMessage(viewerUserID, msg); item != nil {
|
||||
messages = append(messages, item)
|
||||
}
|
||||
}
|
||||
dialog := tgDialog(domain.Dialog{
|
||||
Peer: domain.Peer{Type: domain.PeerTypeChannel, ID: diff.Channel.ID},
|
||||
TopMessage: diff.Dialog.TopMessageID,
|
||||
TopMessageDate: diff.Dialog.TopMessageDate,
|
||||
ReadInboxMaxID: diff.Dialog.ReadInboxMaxID,
|
||||
ReadOutboxMaxID: diff.Dialog.ReadOutboxMaxID,
|
||||
UnreadCount: diff.Dialog.UnreadCount,
|
||||
UnreadMentions: diff.Dialog.UnreadMentions,
|
||||
UnreadReactions: diff.Dialog.UnreadReactions,
|
||||
UnreadMark: diff.Dialog.UnreadMark,
|
||||
FolderID: diff.Dialog.FolderID,
|
||||
})
|
||||
if dialog != nil {
|
||||
dialog.SetPts(diff.Pts)
|
||||
}
|
||||
return &tg.UpdatesChannelDifferenceTooLong{
|
||||
Final: diff.Final,
|
||||
Timeout: diff.Timeout,
|
||||
Dialog: dialog,
|
||||
Messages: messages,
|
||||
Chats: tgChannelDifferenceChats(viewerUserID, diff),
|
||||
Users: tgUsersForViewer(viewerUserID, diff.Users),
|
||||
}
|
||||
}
|
||||
if len(diff.Events) == 0 && len(diff.NewMessages) == 0 && len(diff.OtherUpdates) == 0 {
|
||||
return &tg.UpdatesChannelDifferenceEmpty{
|
||||
Final: diff.Final,
|
||||
Pts: diff.Pts,
|
||||
Timeout: diff.Timeout,
|
||||
}
|
||||
}
|
||||
messages := make([]tg.MessageClass, 0, len(diff.NewMessages))
|
||||
for _, msg := range diff.NewMessages {
|
||||
if item := tgChannelMessage(viewerUserID, msg); item != nil {
|
||||
messages = append(messages, item)
|
||||
}
|
||||
}
|
||||
updates := make([]tg.UpdateClass, 0, len(diff.OtherUpdates))
|
||||
// 断线后经差量首次看到自己消息时,updateMessageID 让客户端把本地
|
||||
// pending 按 random_id 对账,避免短暂的重复气泡。
|
||||
for _, msg := range diff.NewMessages {
|
||||
if msg.SenderUserID == viewerUserID && viewerUserID != 0 && msg.RandomID != 0 && msg.ID > 0 {
|
||||
updates = append(updates, &tg.UpdateMessageID{ID: msg.ID, RandomID: msg.RandomID})
|
||||
}
|
||||
}
|
||||
for _, event := range diff.OtherUpdates {
|
||||
if update := tgChannelUpdate(viewerUserID, event); update != nil {
|
||||
updates = append(updates, update)
|
||||
}
|
||||
}
|
||||
chats := tgChannelDifferenceChats(viewerUserID, diff)
|
||||
users := tgUsersForViewer(viewerUserID, diff.Users)
|
||||
return &tg.UpdatesChannelDifference{
|
||||
Final: diff.Final,
|
||||
Pts: diff.Pts,
|
||||
Timeout: diff.Timeout,
|
||||
NewMessages: messages,
|
||||
OtherUpdates: updates,
|
||||
Chats: chats,
|
||||
Users: users,
|
||||
}
|
||||
}
|
||||
|
||||
func tgChannelDifferenceChats(viewerUserID int64, diff domain.ChannelDifference) []tg.ChatClass {
|
||||
return tgChannelChatsWithPrimarySelf(viewerUserID, diff.Channel, diff.Channels, diff.Self)
|
||||
}
|
||||
|
||||
func tgChannelUpdate(viewerUserID int64, event domain.ChannelUpdateEvent) tg.UpdateClass {
|
||||
switch event.Type {
|
||||
case domain.ChannelUpdateNewMessage:
|
||||
msg := tgChannelMessage(viewerUserID, event.Message)
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateNewChannelMessage{Message: msg, Pts: event.Pts, PtsCount: event.PtsCount}
|
||||
case domain.ChannelUpdateEditMessage:
|
||||
msg := tgChannelMessage(viewerUserID, event.Message)
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateEditChannelMessage{Message: msg, Pts: event.Pts, PtsCount: event.PtsCount}
|
||||
case domain.ChannelUpdateWebPage:
|
||||
// 频道链接预览就地替换:updateChannelWebPage 仅携已解析 webPage(按 id 关联消息里的
|
||||
// pending 占位),客户端就地换卡片、不触碰 edit_date。
|
||||
if event.Message.Media == nil || event.Message.Media.WebPage == nil {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateChannelWebPage{
|
||||
ChannelID: event.ChannelID,
|
||||
Webpage: tgWebPage(*event.Message.Media.WebPage),
|
||||
Pts: event.Pts,
|
||||
PtsCount: event.PtsCount,
|
||||
}
|
||||
case domain.ChannelUpdateDeleteMessages:
|
||||
if len(event.MessageIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateDeleteChannelMessages{
|
||||
ChannelID: event.ChannelID,
|
||||
Messages: append([]int(nil), event.MessageIDs...),
|
||||
Pts: event.Pts,
|
||||
PtsCount: event.PtsCount,
|
||||
}
|
||||
case domain.ChannelUpdatePinnedMessages:
|
||||
if len(event.MessageIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdatePinnedChannelMessages{
|
||||
Pinned: event.Pinned,
|
||||
ChannelID: event.ChannelID,
|
||||
Messages: append([]int(nil), event.MessageIDs...),
|
||||
Pts: event.Pts,
|
||||
PtsCount: event.PtsCount,
|
||||
}
|
||||
case domain.ChannelUpdateParticipant:
|
||||
userID := event.Participant.UserID
|
||||
if userID == 0 {
|
||||
userID = event.Previous.UserID
|
||||
}
|
||||
if userID == 0 {
|
||||
return nil
|
||||
}
|
||||
actorID := event.SenderUserID
|
||||
if actorID == 0 {
|
||||
actorID = userID
|
||||
}
|
||||
update := &tg.UpdateChannelParticipant{
|
||||
ChannelID: event.ChannelID,
|
||||
Date: event.Date,
|
||||
ActorID: actorID,
|
||||
UserID: userID,
|
||||
}
|
||||
if event.Previous.UserID != 0 {
|
||||
update.SetPrevParticipant(tgChannelParticipantForUpdate(viewerUserID, event.Previous))
|
||||
}
|
||||
if event.Participant.UserID != 0 {
|
||||
update.SetNewParticipant(tgChannelParticipantForUpdate(viewerUserID, event.Participant))
|
||||
}
|
||||
return update
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func tgOtherUpdateFromEvent(event domain.UpdateEvent) tg.UpdateClass {
|
||||
switch event.Type {
|
||||
case domain.UpdateEventChannelState:
|
||||
if event.Peer.Type != domain.PeerTypeChannel || event.Peer.ID == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateChannel{ChannelID: event.Peer.ID}
|
||||
case domain.UpdateEventStory:
|
||||
peer := tgPeer(event.Peer)
|
||||
if peer == nil {
|
||||
peer = tgPeer(event.Story.Owner)
|
||||
}
|
||||
if peer == nil || event.Story.ID == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateStory{Peer: peer, Story: tgStoryItem(event.Story)}
|
||||
case domain.UpdateEventReadStories:
|
||||
peer := tgPeer(event.Peer)
|
||||
if peer == nil || event.MaxID <= 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateReadStories{Peer: peer, MaxID: event.MaxID}
|
||||
case domain.UpdateEventSentStoryReaction:
|
||||
peer := tgPeer(event.Peer)
|
||||
if peer == nil || event.MaxID <= 0 {
|
||||
return nil
|
||||
}
|
||||
reaction := tg.ReactionClass(&tg.ReactionEmpty{})
|
||||
if event.Reaction != nil {
|
||||
reaction = tgMessageReaction(*event.Reaction)
|
||||
}
|
||||
return &tg.UpdateSentStoryReaction{Peer: peer, StoryID: event.MaxID, Reaction: reaction}
|
||||
case domain.UpdateEventNewStoryReaction:
|
||||
peer := tgPeer(event.Peer)
|
||||
if peer == nil || event.MaxID <= 0 || event.Reaction == nil {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateNewStoryReaction{Peer: peer, StoryID: event.MaxID, Reaction: tgMessageReaction(*event.Reaction)}
|
||||
case domain.UpdateEventQuickReplies:
|
||||
return &tg.UpdateQuickReplies{QuickReplies: tgQuickReplies(event.QuickReplies)}
|
||||
case domain.UpdateEventNewQuickReply:
|
||||
return &tg.UpdateNewQuickReply{QuickReply: tgQuickReply(event.QuickReply)}
|
||||
case domain.UpdateEventDeleteQuickReply:
|
||||
if event.MaxID <= 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateDeleteQuickReply{ShortcutID: event.MaxID}
|
||||
case domain.UpdateEventQuickReplyMessage:
|
||||
msg := tgQuickReplyMessage(event.QuickReplyMessage)
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateQuickReplyMessage{Message: msg}
|
||||
case domain.UpdateEventDeleteQuickReplyMessages:
|
||||
if event.MaxID <= 0 || len(event.MessageIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateDeleteQuickReplyMessages{
|
||||
ShortcutID: event.MaxID,
|
||||
Messages: append([]int(nil), event.MessageIDs...),
|
||||
}
|
||||
case domain.UpdateEventContactsReset:
|
||||
return &tg.UpdateContactsReset{}
|
||||
case domain.UpdateEventDialogPinned:
|
||||
// archive folder 行自身的置顶:peer 是 dialogPeerFolder 且绝不能带
|
||||
// folder_id flag(TDesktop Folder::applyPinnedUpdate 视其为
|
||||
// "Nested folders" 错误)。
|
||||
if event.Peer.Type == domain.PeerTypeFolder {
|
||||
if event.Peer.ID == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateDialogPinned{Pinned: event.Bool, Peer: &tg.DialogPeerFolder{FolderID: int(event.Peer.ID)}}
|
||||
}
|
||||
peer := tgDialogPeer(event.Peer)
|
||||
if peer == nil {
|
||||
return nil
|
||||
}
|
||||
// FolderID 零值不编码 flag(EncodeBare 自动 SetFlags),归档内置顶
|
||||
// 必须带 folder_id=1,否则离线重放会把它应用到主列表。
|
||||
return &tg.UpdateDialogPinned{Pinned: event.Bool, Peer: peer, FolderID: event.FolderID}
|
||||
case domain.UpdateEventPinnedDialogs:
|
||||
update := &tg.UpdatePinnedDialogs{FolderID: event.FolderID}
|
||||
if len(event.Peers) > 0 {
|
||||
update.Order = tgDialogPeers(event.Peers)
|
||||
}
|
||||
return update
|
||||
case domain.UpdateEventSavedDialogPinned:
|
||||
peer := tgDialogPeer(event.Peer)
|
||||
if peer == nil {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateSavedDialogPinned{Pinned: event.Bool, Peer: peer}
|
||||
case domain.UpdateEventPinnedSavedDialogs:
|
||||
update := &tg.UpdatePinnedSavedDialogs{}
|
||||
if len(event.Peers) > 0 {
|
||||
update.SetOrder(tgDialogPeers(event.Peers))
|
||||
}
|
||||
return update
|
||||
case domain.UpdateEventDialogUnreadMark:
|
||||
peer := tgDialogPeer(event.Peer)
|
||||
if peer == nil {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateDialogUnreadMark{Unread: event.Bool, Peer: peer}
|
||||
case domain.UpdateEventDraftMessage:
|
||||
peer := tgPeer(event.Peer)
|
||||
if peer == nil {
|
||||
return nil
|
||||
}
|
||||
// Draft 由 enrichDraftMessageEvent 按当前权威态填充;nil/空 = 草稿已删。
|
||||
var draft tg.DraftMessageClass
|
||||
if event.Draft != nil && !event.Draft.Empty() {
|
||||
draft = tgDialogDraft(*event.Draft)
|
||||
} else {
|
||||
empty := &tg.DraftMessageEmpty{}
|
||||
if event.Date > 0 {
|
||||
empty.SetDate(event.Date)
|
||||
}
|
||||
draft = empty
|
||||
}
|
||||
update := &tg.UpdateDraftMessage{Peer: peer, Draft: draft}
|
||||
if event.MaxID > 0 {
|
||||
update.SetTopMsgID(event.MaxID)
|
||||
}
|
||||
return update
|
||||
case domain.UpdateEventChannelViewForum:
|
||||
if event.Peer.Type != domain.PeerTypeChannel || event.Peer.ID == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateChannelViewForumAsMessages{ChannelID: event.Peer.ID, Enabled: event.Bool}
|
||||
case domain.UpdateEventReadChannelDiscussionInbox:
|
||||
if event.Peer.Type != domain.PeerTypeChannel || event.Peer.ID == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateReadChannelDiscussionInbox{ChannelID: event.Peer.ID, TopMsgID: event.TopMsgID, ReadMaxID: event.MaxID}
|
||||
case domain.UpdateEventReadChannelDiscussionOutbox:
|
||||
if event.Peer.Type != domain.PeerTypeChannel || event.Peer.ID == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateReadChannelDiscussionOutbox{ChannelID: event.Peer.ID, TopMsgID: event.TopMsgID, ReadMaxID: event.MaxID}
|
||||
case domain.UpdateEventPeerSettings:
|
||||
peer := tgPeer(event.Peer)
|
||||
if peer == nil {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdatePeerSettings{Peer: peer, Settings: tgPeerSettings(event.Settings)}
|
||||
case domain.UpdateEventPeerStoryBlocked:
|
||||
peer := tgPeer(event.Peer)
|
||||
if peer == nil {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdatePeerBlocked{PeerID: peer, Blocked: event.Bool, BlockedMyStoriesFrom: true}
|
||||
case domain.UpdateEventDeleteMessages:
|
||||
if len(event.MessageIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateDeleteMessages{
|
||||
Messages: append([]int(nil), event.MessageIDs...),
|
||||
Pts: event.Pts,
|
||||
PtsCount: event.PtsCount,
|
||||
}
|
||||
case domain.UpdateEventPinnedMessages:
|
||||
peer := tgPeer(event.Peer)
|
||||
if peer == nil || len(event.MessageIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdatePinnedMessages{
|
||||
Pinned: event.Bool,
|
||||
Peer: peer,
|
||||
Messages: append([]int(nil), event.MessageIDs...),
|
||||
Pts: event.Pts,
|
||||
PtsCount: event.PtsCount,
|
||||
}
|
||||
case domain.UpdateEventReadHistoryOutbox:
|
||||
return tgReadHistoryOutbox(event)
|
||||
case domain.UpdateEventReadMessageContents:
|
||||
if len(event.MessageIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
contents := &tg.UpdateReadMessagesContents{
|
||||
Messages: append([]int(nil), event.MessageIDs...),
|
||||
Pts: event.Pts,
|
||||
PtsCount: event.PtsCount,
|
||||
}
|
||||
if event.Date > 0 {
|
||||
// date 是内容被读取的时刻:客户端用它调度 TTL 媒体的
|
||||
// "自读取起算"删除与 sender 侧已听时间。
|
||||
contents.SetDate(event.Date)
|
||||
}
|
||||
return contents
|
||||
case domain.UpdateEventEditMessage:
|
||||
msg := tgMessage(event.Message)
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateEditMessage{
|
||||
Message: msg,
|
||||
Pts: event.Pts,
|
||||
PtsCount: event.PtsCount,
|
||||
}
|
||||
case domain.UpdateEventWebPage:
|
||||
// 链接预览就地替换:updateWebPage 仅携带已解析 webPage(按 webPage id 与消息里的
|
||||
// pending 占位关联),客户端就地换卡片、不触碰 edit_date。
|
||||
if event.Message.Media == nil || event.Message.Media.WebPage == nil {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateWebPage{
|
||||
Webpage: tgWebPage(*event.Message.Media.WebPage),
|
||||
Pts: event.Pts,
|
||||
PtsCount: event.PtsCount,
|
||||
}
|
||||
case domain.UpdateEventMessagePoll:
|
||||
if event.Message.ID <= 0 || event.Message.ID > domain.MaxMessageBoxID {
|
||||
return nil
|
||||
}
|
||||
pollPeer := event.Message.Peer
|
||||
if pollPeer.Type == "" || pollPeer.ID == 0 {
|
||||
pollPeer = event.Peer
|
||||
}
|
||||
media := event.Message.Media
|
||||
if media == nil || media.Kind != domain.MessageMediaKindPoll || media.Poll == nil {
|
||||
return nil
|
||||
}
|
||||
return tgUpdateMessagePoll(pollPeer, event.Message.ID, media.Poll)
|
||||
case domain.UpdateEventMessageReactions:
|
||||
if event.Message.ID <= 0 || event.Message.ID > domain.MaxMessageBoxID {
|
||||
return nil
|
||||
}
|
||||
peer := event.Message.Peer
|
||||
if peer.Type == "" || peer.ID == 0 {
|
||||
peer = event.Peer
|
||||
}
|
||||
outPeer := tgPeer(peer)
|
||||
if outPeer == nil {
|
||||
return nil
|
||||
}
|
||||
reactions := event.Message.Reactions
|
||||
if reactions == nil {
|
||||
empty := domain.ChannelMessageReactions{CanSeeList: true, Results: []domain.ChannelMessageReactionCount{}, Recent: []domain.ChannelMessagePeerReaction{}}
|
||||
reactions = &empty
|
||||
}
|
||||
converted := tgMessageReactions(event.UserID, reactions)
|
||||
if converted == nil {
|
||||
converted = &tg.MessageReactions{Results: []tg.ReactionCount{}}
|
||||
}
|
||||
return &tg.UpdateMessageReactions{
|
||||
Peer: outPeer,
|
||||
MsgID: event.Message.ID,
|
||||
Reactions: *converted,
|
||||
}
|
||||
case domain.UpdateEventDialogFilter:
|
||||
update := &tg.UpdateDialogFilter{ID: event.FilterID}
|
||||
if event.DialogFilter != nil {
|
||||
update.SetFilter(tgDialogFilter(*event.DialogFilter))
|
||||
}
|
||||
return update
|
||||
case domain.UpdateEventDialogFilterOrder:
|
||||
return &tg.UpdateDialogFilterOrder{Order: append([]int(nil), event.FilterOrder...)}
|
||||
case domain.UpdateEventDialogFilters:
|
||||
return &tg.UpdateDialogFilters{}
|
||||
case domain.UpdateEventFolderPeers:
|
||||
if len(event.FolderPeers) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateFolderPeers{
|
||||
FolderPeers: tgFolderPeers(event.FolderPeers),
|
||||
Pts: event.Pts,
|
||||
PtsCount: event.PtsCount,
|
||||
}
|
||||
case domain.UpdateEventChannelAvailable:
|
||||
if event.Peer.Type != domain.PeerTypeChannel || event.Peer.ID == 0 || event.MaxID <= 0 {
|
||||
return nil
|
||||
}
|
||||
return &tg.UpdateChannelAvailableMessages{
|
||||
ChannelID: event.Peer.ID,
|
||||
AvailableMinID: event.MaxID,
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func addChannels(out *tg.UpdatesDifference, seen map[int64]struct{}, viewerUserID int64, channels []domain.Channel) {
|
||||
for _, ch := range channels {
|
||||
if ch.ID == 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[ch.ID]; ok {
|
||||
continue
|
||||
}
|
||||
seen[ch.ID] = struct{}{}
|
||||
out.Chats = append(out.Chats, tgChannelChatMin(viewerUserID, ch))
|
||||
}
|
||||
}
|
||||
|
||||
func addChannelNudgeChat(out *tg.UpdatesDifference, seen map[int64]struct{}, chat tg.ChatClass) {
|
||||
channelID, ok := channelChatID(chat)
|
||||
if !ok || channelID == 0 {
|
||||
return
|
||||
}
|
||||
if _, exists := seen[channelID]; exists {
|
||||
upgradeMinChannelChat(out, channelID, chat)
|
||||
return
|
||||
}
|
||||
seen[channelID] = struct{}{}
|
||||
out.Chats = append(out.Chats, chat)
|
||||
}
|
||||
|
||||
func upgradeMinChannelChat(out *tg.UpdatesDifference, channelID int64, candidate tg.ChatClass) {
|
||||
next, ok := candidate.(*tg.Channel)
|
||||
if !ok || next.Min {
|
||||
return
|
||||
}
|
||||
for i, existing := range out.Chats {
|
||||
existingID, ok := channelChatID(existing)
|
||||
if !ok || existingID != channelID {
|
||||
continue
|
||||
}
|
||||
if current, ok := existing.(*tg.Channel); ok && current.Min {
|
||||
out.Chats[i] = candidate
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func channelChatID(chat tg.ChatClass) (int64, bool) {
|
||||
switch v := chat.(type) {
|
||||
case *tg.Channel:
|
||||
return v.ID, true
|
||||
case *tg.ChannelForbidden:
|
||||
return v.ID, true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
func tgChannelParticipantForUpdate(selfUserID int64, member domain.ChannelMember) tg.ChannelParticipantClass {
|
||||
if member.UserID == 0 {
|
||||
return nil
|
||||
}
|
||||
if member.Status == domain.ChannelMemberKicked || member.Status == domain.ChannelMemberBanned || member.BannedRights.ViewMessages {
|
||||
return &tg.ChannelParticipantBanned{
|
||||
Left: member.Status != domain.ChannelMemberActive,
|
||||
Peer: &tg.PeerUser{UserID: member.UserID},
|
||||
KickedBy: member.InviterUserID,
|
||||
Date: member.LeftAt,
|
||||
BannedRights: tgChatBannedRights(member.BannedRights),
|
||||
}
|
||||
}
|
||||
if member.Status == domain.ChannelMemberLeft {
|
||||
return &tg.ChannelParticipantLeft{Peer: &tg.PeerUser{UserID: member.UserID}}
|
||||
}
|
||||
return tgChannelParticipant(selfUserID, member)
|
||||
}
|
||||
|
||||
func tgLangPackDifference(pack domain.LangPack) *tg.LangPackDifference {
|
||||
return &tg.LangPackDifference{
|
||||
LangCode: pack.LangCode,
|
||||
FromVersion: pack.FromVersion,
|
||||
Version: pack.Version,
|
||||
Strings: tgLangPackStrings(pack.Strings),
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue