owpengram-server/internal/compat/tdesktop/dialogs.go

196 lines
5.2 KiB
Go

package tdesktop
import "telesrv/internal/domain"
// ShouldMergePinnedIntoInitialDialogs reports whether a TDesktop main-list
// messages.getDialogs request should carry pinned/archive rows inline.
//
// TDesktop starts the main list with getDialogs(exclude_pinned=true) and loads
// pinned rows through getPinnedDialogs in parallel. If the exclude_pinned result
// is rendered first, the first visible list temporarily lacks pinned/archive
// rows. Keep the workaround scoped to the first main-folder page with no hash so
// pagination and cache probes retain normal Telegram semantics.
func ShouldMergePinnedIntoInitialDialogs(filter domain.DialogFilter) bool {
if !filter.ExcludePinned || filter.Hash != 0 {
return false
}
if filter.HasFolderID && filter.FolderID != domain.DialogMainFolderID {
return false
}
if filter.OffsetID != 0 || filter.OffsetDate != 0 || filter.HasOffsetPeer {
return false
}
return true
}
// MergeInitialDialogsWithPinned prepends the pinned getPinnedDialogs view to an
// initial getDialogs(exclude_pinned=true) main-list response. The returned list
// remains a normal messages.dialogs/messages.dialogsSlice projection; only the
// first response carries extra pinned/archive rows for TDesktop startup.
func MergeInitialDialogsWithPinned(main, pinned domain.DialogList) domain.DialogList {
if pinned.ArchiveSummary == nil && len(pinned.Dialogs) == 0 {
return main
}
out := main
out.ArchiveSummary = pinned.ArchiveSummary
out.Dialogs = mergeDialogsByPeer(pinned.Dialogs, main.Dialogs)
out.Messages = mergePrivateMessages(pinned.Messages, main.Messages)
out.ChannelMessages = mergeChannelMessages(pinned.ChannelMessages, main.ChannelMessages)
out.Users = mergeUsersByID(pinned.Users, main.Users)
out.Channels = mergeChannelsByID(pinned.Channels, main.Channels)
pinnedEntries := len(pinned.Dialogs)
if pinned.ArchiveSummary != nil {
pinnedEntries++
}
mainCount := main.Count
if mainCount == 0 {
mainCount = len(main.Dialogs)
}
out.Count = mainCount + pinnedEntries
out.Hash = 0
return out
}
func mergeDialogsByPeer(first, second []domain.Dialog) []domain.Dialog {
out := make([]domain.Dialog, 0, len(first)+len(second))
seen := make(map[domain.Peer]struct{}, len(first)+len(second))
for _, d := range first {
if d.Peer.ID == 0 {
continue
}
if _, ok := seen[d.Peer]; ok {
continue
}
seen[d.Peer] = struct{}{}
out = append(out, d)
}
for _, d := range second {
if d.Peer.ID == 0 {
continue
}
if _, ok := seen[d.Peer]; ok {
continue
}
seen[d.Peer] = struct{}{}
out = append(out, d)
}
return out
}
type privateMessageKey struct {
peer domain.Peer
id int
}
func mergePrivateMessages(first, second []domain.Message) []domain.Message {
out := make([]domain.Message, 0, len(first)+len(second))
seen := make(map[privateMessageKey]struct{}, len(first)+len(second))
for _, msg := range first {
key := privateMessageKey{peer: msg.Peer, id: msg.ID}
if key.peer.ID == 0 || key.id == 0 {
continue
}
if _, ok := seen[key]; ok {
continue
}
seen[key] = struct{}{}
out = append(out, msg)
}
for _, msg := range second {
key := privateMessageKey{peer: msg.Peer, id: msg.ID}
if key.peer.ID == 0 || key.id == 0 {
continue
}
if _, ok := seen[key]; ok {
continue
}
seen[key] = struct{}{}
out = append(out, msg)
}
return out
}
type channelMessageKey struct {
channelID int64
id int
}
func mergeChannelMessages(first, second []domain.ChannelMessage) []domain.ChannelMessage {
out := make([]domain.ChannelMessage, 0, len(first)+len(second))
seen := make(map[channelMessageKey]struct{}, len(first)+len(second))
for _, msg := range first {
key := channelMessageKey{channelID: msg.ChannelID, id: msg.ID}
if key.channelID == 0 || key.id == 0 {
continue
}
if _, ok := seen[key]; ok {
continue
}
seen[key] = struct{}{}
out = append(out, msg)
}
for _, msg := range second {
key := channelMessageKey{channelID: msg.ChannelID, id: msg.ID}
if key.channelID == 0 || key.id == 0 {
continue
}
if _, ok := seen[key]; ok {
continue
}
seen[key] = struct{}{}
out = append(out, msg)
}
return out
}
func mergeUsersByID(first, second []domain.User) []domain.User {
out := make([]domain.User, 0, len(first)+len(second))
seen := make(map[int64]struct{}, len(first)+len(second))
for _, user := range first {
if user.ID == 0 {
continue
}
if _, ok := seen[user.ID]; ok {
continue
}
seen[user.ID] = struct{}{}
out = append(out, user)
}
for _, user := range second {
if user.ID == 0 {
continue
}
if _, ok := seen[user.ID]; ok {
continue
}
seen[user.ID] = struct{}{}
out = append(out, user)
}
return out
}
func mergeChannelsByID(first, second []domain.Channel) []domain.Channel {
out := make([]domain.Channel, 0, len(first)+len(second))
seen := make(map[int64]struct{}, len(first)+len(second))
for _, channel := range first {
if channel.ID == 0 {
continue
}
if _, ok := seen[channel.ID]; ok {
continue
}
seen[channel.ID] = struct{}{}
out = append(out, channel)
}
for _, channel := range second {
if channel.ID == 0 {
continue
}
if _, ok := seen[channel.ID]; ok {
continue
}
seen[channel.ID] = struct{}{}
out = append(out, channel)
}
return out
}