mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
720 lines
37 KiB
Swift
720 lines
37 KiB
Swift
import Foundation
|
|
import Postbox
|
|
import SwiftSignalKit
|
|
import TelegramApi
|
|
import MtProtoKit
|
|
|
|
|
|
struct PeerChatInfo {
|
|
var notificationSettings: PeerNotificationSettings
|
|
}
|
|
|
|
struct AccountStateChannelState: Equatable {
|
|
var pts: Int32
|
|
}
|
|
|
|
final class AccountInitialState {
|
|
let state: AuthorizedAccountState.State
|
|
let peerIds: Set<PeerId>
|
|
let channelStates: [PeerId: AccountStateChannelState]
|
|
let peerChatInfos: [PeerId: PeerChatInfo]
|
|
let peerIdsRequiringLocalChatState: Set<PeerId>
|
|
let locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]
|
|
let cloudReadStates: [PeerId: PeerReadState]
|
|
let channelsToPollExplicitely: Set<PeerId>
|
|
|
|
init(state: AuthorizedAccountState.State, peerIds: Set<PeerId>, peerIdsRequiringLocalChatState: Set<PeerId>, channelStates: [PeerId: AccountStateChannelState], peerChatInfos: [PeerId: PeerChatInfo], locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]], cloudReadStates: [PeerId: PeerReadState], channelsToPollExplicitely: Set<PeerId>) {
|
|
self.state = state
|
|
self.peerIds = peerIds
|
|
self.channelStates = channelStates
|
|
self.peerIdsRequiringLocalChatState = peerIdsRequiringLocalChatState
|
|
self.peerChatInfos = peerChatInfos
|
|
self.locallyGeneratedMessageTimestamps = locallyGeneratedMessageTimestamps
|
|
self.cloudReadStates = cloudReadStates
|
|
self.channelsToPollExplicitely = channelsToPollExplicitely
|
|
}
|
|
}
|
|
|
|
enum AccountStateUpdatePinnedItemIdsOperation {
|
|
case pin(PinnedItemId)
|
|
case unpin(PinnedItemId)
|
|
case reorder([PinnedItemId])
|
|
case sync
|
|
}
|
|
|
|
enum AccountStateUpdateStickerPacksOperation {
|
|
case add(Api.messages.StickerSet)
|
|
case reorder(SynchronizeInstalledStickerPacksOperationNamespace, [Int64])
|
|
case sync
|
|
}
|
|
|
|
enum AccountStateNotificationSettingsSubject {
|
|
case peer(PeerId)
|
|
}
|
|
|
|
enum AccountStateGlobalNotificationSettingsSubject {
|
|
case privateChats
|
|
case groups
|
|
case channels
|
|
}
|
|
|
|
enum AccountStateMutationOperation {
|
|
case AddMessages([StoreMessage], AddMessagesLocation)
|
|
case AddScheduledMessages([StoreMessage])
|
|
case DeleteMessagesWithGlobalIds([Int32])
|
|
case DeleteMessages([MessageId])
|
|
case EditMessage(MessageId, StoreMessage)
|
|
case UpdateMessagePoll(MediaId, Api.Poll?, Api.PollResults)
|
|
case UpdateMessageReactions(MessageId, Api.MessageReactions)
|
|
case UpdateMedia(MediaId, Media?)
|
|
case ReadInbox(MessageId)
|
|
case ReadOutbox(MessageId, Int32?)
|
|
case ResetReadState(peerId: PeerId, namespace: MessageId.Namespace, maxIncomingReadId: MessageId.Id, maxOutgoingReadId: MessageId.Id, maxKnownId: MessageId.Id, count: Int32, markedUnread: Bool?)
|
|
case ResetIncomingReadState(groupId: PeerGroupId, peerId: PeerId, namespace: MessageId.Namespace, maxIncomingReadId: MessageId.Id, count: Int32, pts: Int32)
|
|
case UpdatePeerChatUnreadMark(PeerId, MessageId.Namespace, Bool)
|
|
case ResetMessageTagSummary(PeerId, MessageId.Namespace, Int32, MessageHistoryTagNamespaceCountValidityRange)
|
|
case ReadGroupFeedInbox(PeerGroupId, MessageIndex)
|
|
case UpdateState(AuthorizedAccountState.State)
|
|
case UpdateChannelState(PeerId, Int32)
|
|
case UpdateChannelInvalidationPts(PeerId, Int32)
|
|
case UpdateChannelSynchronizedUntilMessage(PeerId, MessageId.Id)
|
|
case UpdateNotificationSettings(AccountStateNotificationSettingsSubject, PeerNotificationSettings)
|
|
case UpdateGlobalNotificationSettings(AccountStateGlobalNotificationSettingsSubject, MessageNotificationSettings)
|
|
case MergeApiChats([Api.Chat])
|
|
case UpdatePeer(PeerId, (Peer?) -> Peer?)
|
|
case UpdateIsContact(PeerId, Bool)
|
|
case UpdateCachedPeerData(PeerId, (CachedPeerData?) -> CachedPeerData?)
|
|
case UpdateMessagesPinned([MessageId], Bool)
|
|
case MergeApiUsers([Api.User])
|
|
case MergePeerPresences([PeerId: Api.UserStatus], Bool)
|
|
case UpdateSecretChat(chat: Api.EncryptedChat, timestamp: Int32)
|
|
case AddSecretMessages([Api.EncryptedMessage])
|
|
case ReadSecretOutbox(peerId: PeerId, maxTimestamp: Int32, actionTimestamp: Int32)
|
|
case AddPeerInputActivity(chatPeerId: PeerActivitySpace, peerId: PeerId?, activity: PeerInputActivity?)
|
|
case UpdatePinnedItemIds(PeerGroupId, AccountStateUpdatePinnedItemIdsOperation)
|
|
case ReadMessageContents((PeerId?, [Int32]))
|
|
case UpdateMessageImpressionCount(MessageId, Int32)
|
|
case UpdateMessageForwardsCount(MessageId, Int32)
|
|
case UpdateInstalledStickerPacks(AccountStateUpdateStickerPacksOperation)
|
|
case UpdateRecentGifs
|
|
case UpdateChatInputState(PeerId, SynchronizeableChatInputState?)
|
|
case UpdateCall(Api.PhoneCall)
|
|
case AddCallSignalingData(Int64, Data)
|
|
case UpdateLangPack(String, Api.LangPackDifference?)
|
|
case UpdateMinAvailableMessage(MessageId)
|
|
case UpdatePeerChatInclusion(peerId: PeerId, groupId: PeerGroupId, changedGroup: Bool)
|
|
case UpdatePeersNearby([PeerNearby])
|
|
case UpdateTheme(TelegramTheme)
|
|
case SyncChatListFilters
|
|
case UpdateChatListFilterOrder(order: [Int32])
|
|
case UpdateChatListFilter(id: Int32, filter: Api.DialogFilter?)
|
|
case UpdateReadThread(threadMessageId: MessageId, readMaxId: Int32, isIncoming: Bool, mainChannelMessage: MessageId?)
|
|
case UpdateGroupCallParticipants(id: Int64, accessHash: Int64, participants: [Api.GroupCallParticipant], version: Int32)
|
|
case UpdateGroupCall(peerId: PeerId, call: Api.GroupCall)
|
|
case UpdateAutoremoveTimeout(peer: Api.Peer, value: CachedPeerAutoremoveTimeout.Value?)
|
|
}
|
|
|
|
struct HoleFromPreviousState {
|
|
var validateChannelPts: Int32?
|
|
|
|
func mergedWith(_ other: HoleFromPreviousState) -> HoleFromPreviousState {
|
|
var result = self
|
|
if let pts = self.validateChannelPts, let otherPts = other.validateChannelPts {
|
|
result.validateChannelPts = max(pts, otherPts)
|
|
} else if let pts = self.validateChannelPts {
|
|
result.validateChannelPts = pts
|
|
} else if let otherPts = other.validateChannelPts {
|
|
result.validateChannelPts = otherPts
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
struct AccountMutableState {
|
|
let initialState: AccountInitialState
|
|
let branchOperationIndex: Int
|
|
|
|
var operations: [AccountStateMutationOperation] = []
|
|
|
|
var state: AuthorizedAccountState.State
|
|
var peers: [PeerId: Peer]
|
|
var channelStates: [PeerId: AccountStateChannelState]
|
|
var peerChatInfos: [PeerId: PeerChatInfo]
|
|
var referencedMessageIds: Set<MessageId>
|
|
var storedMessages: Set<MessageId>
|
|
var readInboxMaxIds: [PeerId: MessageId]
|
|
var namespacesWithHolesFromPreviousState: [PeerId: [MessageId.Namespace: HoleFromPreviousState]]
|
|
var updatedOutgoingUniqueMessageIds: [Int64: Int32]
|
|
|
|
var storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>]
|
|
var displayAlerts: [(text: String, isDropAuth: Bool)] = []
|
|
|
|
var insertedPeers: [PeerId: Peer] = [:]
|
|
|
|
var preCachedResources: [(MediaResource, Data)] = []
|
|
|
|
var updatedMaxMessageId: Int32?
|
|
var updatedQts: Int32?
|
|
|
|
var externallyUpdatedPeerId = Set<PeerId>()
|
|
|
|
var authorizationListUpdated: Bool = false
|
|
|
|
init(initialState: AccountInitialState, initialPeers: [PeerId: Peer], initialReferencedMessageIds: Set<MessageId>, initialStoredMessages: Set<MessageId>, initialReadInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>]) {
|
|
self.initialState = initialState
|
|
self.state = initialState.state
|
|
self.peers = initialPeers
|
|
self.referencedMessageIds = initialReferencedMessageIds
|
|
self.storedMessages = initialStoredMessages
|
|
self.readInboxMaxIds = initialReadInboxMaxIds
|
|
self.channelStates = initialState.channelStates
|
|
self.peerChatInfos = initialState.peerChatInfos
|
|
self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp
|
|
self.branchOperationIndex = 0
|
|
self.namespacesWithHolesFromPreviousState = [:]
|
|
self.updatedOutgoingUniqueMessageIds = [:]
|
|
}
|
|
|
|
init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], channelStates: [PeerId: AccountStateChannelState], peerChatInfos: [PeerId: PeerChatInfo], referencedMessageIds: Set<MessageId>, storedMessages: Set<MessageId>, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>], namespacesWithHolesFromPreviousState: [PeerId: [MessageId.Namespace: HoleFromPreviousState]], updatedOutgoingUniqueMessageIds: [Int64: Int32], displayAlerts: [(text: String, isDropAuth: Bool)], branchOperationIndex: Int) {
|
|
self.initialState = initialState
|
|
self.operations = operations
|
|
self.state = state
|
|
self.peers = peers
|
|
self.channelStates = channelStates
|
|
self.referencedMessageIds = referencedMessageIds
|
|
self.storedMessages = storedMessages
|
|
self.peerChatInfos = peerChatInfos
|
|
self.readInboxMaxIds = readInboxMaxIds
|
|
self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp
|
|
self.namespacesWithHolesFromPreviousState = namespacesWithHolesFromPreviousState
|
|
self.updatedOutgoingUniqueMessageIds = updatedOutgoingUniqueMessageIds
|
|
self.displayAlerts = displayAlerts
|
|
self.branchOperationIndex = branchOperationIndex
|
|
}
|
|
|
|
func branch() -> AccountMutableState {
|
|
return AccountMutableState(initialState: self.initialState, operations: self.operations, state: self.state, peers: self.peers, channelStates: self.channelStates, peerChatInfos: self.peerChatInfos, referencedMessageIds: self.referencedMessageIds, storedMessages: self.storedMessages, readInboxMaxIds: self.readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: self.storedMessagesByPeerIdAndTimestamp, namespacesWithHolesFromPreviousState: self.namespacesWithHolesFromPreviousState, updatedOutgoingUniqueMessageIds: self.updatedOutgoingUniqueMessageIds, displayAlerts: self.displayAlerts, branchOperationIndex: self.operations.count)
|
|
}
|
|
|
|
mutating func merge(_ other: AccountMutableState) {
|
|
self.referencedMessageIds.formUnion(other.referencedMessageIds)
|
|
for i in other.branchOperationIndex ..< other.operations.count {
|
|
self.addOperation(other.operations[i])
|
|
}
|
|
for (_, peer) in other.insertedPeers {
|
|
self.peers[peer.id] = peer
|
|
}
|
|
self.preCachedResources.append(contentsOf: other.preCachedResources)
|
|
self.externallyUpdatedPeerId.formUnion(other.externallyUpdatedPeerId)
|
|
for (peerId, namespaces) in other.namespacesWithHolesFromPreviousState {
|
|
if self.namespacesWithHolesFromPreviousState[peerId] == nil {
|
|
self.namespacesWithHolesFromPreviousState[peerId] = [:]
|
|
}
|
|
for (namespace, namespaceState) in namespaces {
|
|
if self.namespacesWithHolesFromPreviousState[peerId]![namespace] == nil {
|
|
self.namespacesWithHolesFromPreviousState[peerId]![namespace] = namespaceState
|
|
} else {
|
|
self.namespacesWithHolesFromPreviousState[peerId]![namespace] = self.namespacesWithHolesFromPreviousState[peerId]![namespace]!.mergedWith(namespaceState)
|
|
}
|
|
}
|
|
}
|
|
self.updatedOutgoingUniqueMessageIds.merge(other.updatedOutgoingUniqueMessageIds, uniquingKeysWith: { lhs, _ in lhs })
|
|
self.displayAlerts.append(contentsOf: other.displayAlerts)
|
|
}
|
|
|
|
mutating func addPreCachedResource(_ resource: MediaResource, data: Data) {
|
|
self.preCachedResources.append((resource, data))
|
|
}
|
|
|
|
mutating func addExternallyUpdatedPeerId(_ peerId: PeerId) {
|
|
self.externallyUpdatedPeerId.insert(peerId)
|
|
}
|
|
|
|
mutating func addMessages(_ messages: [StoreMessage], location: AddMessagesLocation) {
|
|
self.addOperation(.AddMessages(messages, location))
|
|
}
|
|
|
|
mutating func addScheduledMessages(_ messages: [StoreMessage]) {
|
|
self.addOperation(.AddScheduledMessages(messages))
|
|
}
|
|
|
|
mutating func addDisplayAlert(_ text: String, isDropAuth: Bool) {
|
|
self.displayAlerts.append((text: text, isDropAuth: isDropAuth))
|
|
}
|
|
|
|
mutating func deleteMessagesWithGlobalIds(_ globalIds: [Int32]) {
|
|
self.addOperation(.DeleteMessagesWithGlobalIds(globalIds))
|
|
}
|
|
|
|
mutating func deleteMessages(_ messageIds: [MessageId]) {
|
|
self.addOperation(.DeleteMessages(messageIds))
|
|
}
|
|
|
|
mutating func editMessage(_ id: MessageId, message: StoreMessage) {
|
|
self.addOperation(.EditMessage(id, message))
|
|
}
|
|
|
|
mutating func updateMessagePoll(_ id: MediaId, poll: Api.Poll?, results: Api.PollResults) {
|
|
self.addOperation(.UpdateMessagePoll(id, poll, results))
|
|
}
|
|
|
|
mutating func updateMessageReactions(_ messageId: MessageId, reactions: Api.MessageReactions) {
|
|
self.addOperation(.UpdateMessageReactions(messageId, reactions))
|
|
}
|
|
|
|
mutating func updateMedia(_ id: MediaId, media: Media?) {
|
|
self.addOperation(.UpdateMedia(id, media))
|
|
}
|
|
|
|
mutating func readInbox(_ messageId: MessageId) {
|
|
self.addOperation(.ReadInbox(messageId))
|
|
}
|
|
|
|
mutating func readOutbox(_ messageId: MessageId, timestamp: Int32?) {
|
|
self.addOperation(.ReadOutbox(messageId, timestamp))
|
|
}
|
|
|
|
mutating func readThread(threadMessageId: MessageId, readMaxId: Int32, isIncoming: Bool, mainChannelMessage: MessageId?) {
|
|
self.addOperation(.UpdateReadThread(threadMessageId: threadMessageId, readMaxId: readMaxId, isIncoming: isIncoming, mainChannelMessage: mainChannelMessage))
|
|
}
|
|
|
|
mutating func updateGroupCallParticipants(id: Int64, accessHash: Int64, participants: [Api.GroupCallParticipant], version: Int32) {
|
|
self.addOperation(.UpdateGroupCallParticipants(id: id, accessHash: accessHash, participants: participants, version: version))
|
|
}
|
|
|
|
mutating func updateGroupCall(peerId: PeerId, call: Api.GroupCall) {
|
|
self.addOperation(.UpdateGroupCall(peerId: peerId, call: call))
|
|
}
|
|
|
|
mutating func updateAutoremoveTimeout(peer: Api.Peer, value: CachedPeerAutoremoveTimeout.Value?) {
|
|
self.addOperation(.UpdateAutoremoveTimeout(peer: peer, value: value))
|
|
}
|
|
|
|
mutating func readGroupFeedInbox(groupId: PeerGroupId, index: MessageIndex) {
|
|
self.addOperation(.ReadGroupFeedInbox(groupId, index))
|
|
}
|
|
|
|
mutating func resetReadState(_ peerId: PeerId, namespace: MessageId.Namespace, maxIncomingReadId: MessageId.Id, maxOutgoingReadId: MessageId.Id, maxKnownId: MessageId.Id, count: Int32, markedUnread: Bool?) {
|
|
self.addOperation(.ResetReadState(peerId: peerId, namespace: namespace, maxIncomingReadId: maxIncomingReadId, maxOutgoingReadId: maxOutgoingReadId, maxKnownId: maxKnownId, count: count, markedUnread: markedUnread))
|
|
}
|
|
|
|
mutating func resetIncomingReadState(groupId: PeerGroupId, peerId: PeerId, namespace: MessageId.Namespace, maxIncomingReadId: MessageId.Id, count: Int32, pts: Int32) {
|
|
self.addOperation(.ResetIncomingReadState(groupId: groupId, peerId: peerId, namespace: namespace, maxIncomingReadId: maxIncomingReadId, count: count, pts: pts))
|
|
}
|
|
|
|
mutating func updatePeerChatUnreadMark(_ peerId: PeerId, namespace: MessageId.Namespace, value: Bool) {
|
|
self.addOperation(.UpdatePeerChatUnreadMark(peerId, namespace, value))
|
|
}
|
|
|
|
mutating func resetMessageTagSummary(_ peerId: PeerId, namespace: MessageId.Namespace, count: Int32, range: MessageHistoryTagNamespaceCountValidityRange) {
|
|
self.addOperation(.ResetMessageTagSummary(peerId, namespace, count, range))
|
|
}
|
|
|
|
mutating func updateState(_ state: AuthorizedAccountState.State) {
|
|
if self.initialState.state.seq != state.qts {
|
|
self.updatedQts = state.qts
|
|
}
|
|
self.addOperation(.UpdateState(state))
|
|
}
|
|
|
|
mutating func updateChannelState(_ peerId: PeerId, pts: Int32) {
|
|
self.addOperation(.UpdateChannelState(peerId, pts))
|
|
}
|
|
|
|
mutating func updateChannelInvalidationPts(_ peerId: PeerId, invalidationPts: Int32) {
|
|
self.addOperation(.UpdateChannelInvalidationPts(peerId, invalidationPts))
|
|
}
|
|
|
|
mutating func updateChannelSynchronizedUntilMessage(_ peerId: PeerId, id: MessageId.Id) {
|
|
self.addOperation(.UpdateChannelSynchronizedUntilMessage(peerId, id))
|
|
}
|
|
|
|
mutating func updateNotificationSettings(_ subject: AccountStateNotificationSettingsSubject, notificationSettings: PeerNotificationSettings) {
|
|
self.addOperation(.UpdateNotificationSettings(subject, notificationSettings))
|
|
}
|
|
|
|
mutating func updateGlobalNotificationSettings(_ subject: AccountStateGlobalNotificationSettingsSubject, notificationSettings: MessageNotificationSettings) {
|
|
self.addOperation(.UpdateGlobalNotificationSettings(subject, notificationSettings))
|
|
}
|
|
|
|
mutating func setNeedsHoleFromPreviousState(peerId: PeerId, namespace: MessageId.Namespace, validateChannelPts: Int32?) {
|
|
if self.namespacesWithHolesFromPreviousState[peerId] == nil {
|
|
self.namespacesWithHolesFromPreviousState[peerId] = [:]
|
|
}
|
|
let namespaceState = HoleFromPreviousState(validateChannelPts: validateChannelPts)
|
|
if self.namespacesWithHolesFromPreviousState[peerId]![namespace] == nil {
|
|
self.namespacesWithHolesFromPreviousState[peerId]![namespace] = namespaceState
|
|
} else {
|
|
self.namespacesWithHolesFromPreviousState[peerId]![namespace] = self.namespacesWithHolesFromPreviousState[peerId]![namespace]!.mergedWith(namespaceState)
|
|
}
|
|
}
|
|
|
|
mutating func mergeChats(_ chats: [Api.Chat]) {
|
|
self.addOperation(.MergeApiChats(chats))
|
|
|
|
for chat in chats {
|
|
switch chat {
|
|
case let .channel(_, _, _, _, _, _, _, _, _, _, _, participantsCount):
|
|
if let participantsCount = participantsCount {
|
|
self.addOperation(.UpdateCachedPeerData(chat.peerId, { current in
|
|
var previous: CachedChannelData
|
|
if let current = current as? CachedChannelData {
|
|
previous = current
|
|
} else {
|
|
previous = CachedChannelData()
|
|
}
|
|
return previous.withUpdatedParticipantsSummary(previous.participantsSummary.withUpdatedMemberCount(participantsCount))
|
|
}))
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
mutating func updatePeer(_ id: PeerId, _ f: @escaping (Peer?) -> Peer?) {
|
|
self.addOperation(.UpdatePeer(id, f))
|
|
}
|
|
|
|
mutating func updatePeerIsContact(_ id: PeerId, isContact: Bool) {
|
|
self.addOperation(.UpdateIsContact(id, isContact))
|
|
}
|
|
|
|
mutating func updateCachedPeerData(_ id: PeerId, _ f: @escaping (CachedPeerData?) -> CachedPeerData?) {
|
|
self.addOperation(.UpdateCachedPeerData(id, f))
|
|
}
|
|
|
|
mutating func updateMessagesPinned(ids: [MessageId], pinned: Bool) {
|
|
self.addOperation(.UpdateMessagesPinned(ids, pinned))
|
|
}
|
|
|
|
mutating func updateLangPack(langCode: String, difference: Api.LangPackDifference?) {
|
|
self.addOperation(.UpdateLangPack(langCode, difference))
|
|
}
|
|
|
|
mutating func updateMinAvailableMessage(_ id: MessageId) {
|
|
self.addOperation(.UpdateMinAvailableMessage(id))
|
|
}
|
|
|
|
mutating func updatePeerChatInclusion(peerId: PeerId, groupId: PeerGroupId, changedGroup: Bool) {
|
|
self.addOperation(.UpdatePeerChatInclusion(peerId: peerId, groupId: groupId, changedGroup: changedGroup))
|
|
}
|
|
|
|
mutating func updatePeersNearby(_ peersNearby: [PeerNearby]) {
|
|
self.addOperation(.UpdatePeersNearby(peersNearby))
|
|
}
|
|
|
|
mutating func updateTheme(_ theme: TelegramTheme) {
|
|
self.addOperation(.UpdateTheme(theme))
|
|
}
|
|
|
|
mutating func mergeUsers(_ users: [Api.User]) {
|
|
self.addOperation(.MergeApiUsers(users))
|
|
|
|
var presences: [PeerId: Api.UserStatus] = [:]
|
|
for user in users {
|
|
switch user {
|
|
case let .user(_, id, _, _, _, _, _, _, status, _, _, _, _):
|
|
if let status = status {
|
|
presences[PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id))] = status
|
|
}
|
|
break
|
|
case .userEmpty:
|
|
break
|
|
}
|
|
}
|
|
if !presences.isEmpty {
|
|
self.addOperation(.MergePeerPresences(presences, false))
|
|
}
|
|
}
|
|
|
|
mutating func mergePeerPresences(_ presences: [PeerId: Api.UserStatus], explicit: Bool) {
|
|
self.addOperation(.MergePeerPresences(presences, explicit))
|
|
}
|
|
|
|
mutating func updateSecretChat(chat: Api.EncryptedChat, timestamp: Int32) {
|
|
self.addOperation(.UpdateSecretChat(chat: chat, timestamp: timestamp))
|
|
}
|
|
|
|
mutating func addSecretMessages(_ messages: [Api.EncryptedMessage]) {
|
|
self.addOperation(.AddSecretMessages(messages))
|
|
}
|
|
|
|
mutating func readSecretOutbox(peerId: PeerId, timestamp: Int32, actionTimestamp: Int32) {
|
|
self.addOperation(.ReadSecretOutbox(peerId: peerId, maxTimestamp: timestamp, actionTimestamp: actionTimestamp))
|
|
}
|
|
|
|
mutating func addPeerInputActivity(chatPeerId: PeerActivitySpace, peerId: PeerId?, activity: PeerInputActivity?) {
|
|
self.addOperation(.AddPeerInputActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity))
|
|
}
|
|
|
|
mutating func addUpdatePinnedItemIds(groupId: PeerGroupId, operation: AccountStateUpdatePinnedItemIdsOperation) {
|
|
self.addOperation(.UpdatePinnedItemIds(groupId, operation))
|
|
}
|
|
|
|
mutating func addReadMessagesContents(_ peerIdsAndMessageIds: (PeerId?, [Int32])) {
|
|
self.addOperation(.ReadMessageContents(peerIdsAndMessageIds))
|
|
}
|
|
|
|
mutating func addUpdateMessageImpressionCount(id: MessageId, count: Int32) {
|
|
self.addOperation(.UpdateMessageImpressionCount(id, count))
|
|
}
|
|
|
|
mutating func addUpdateMessageForwardsCount(id: MessageId, count: Int32) {
|
|
self.addOperation(.UpdateMessageForwardsCount(id, count))
|
|
}
|
|
|
|
mutating func addUpdateInstalledStickerPacks(_ operation: AccountStateUpdateStickerPacksOperation) {
|
|
self.addOperation(.UpdateInstalledStickerPacks(operation))
|
|
}
|
|
|
|
mutating func addUpdateRecentGifs() {
|
|
self.addOperation(.UpdateRecentGifs)
|
|
}
|
|
|
|
mutating func addUpdateChatInputState(peerId: PeerId, state: SynchronizeableChatInputState?) {
|
|
self.addOperation(.UpdateChatInputState(peerId, state))
|
|
}
|
|
|
|
mutating func addUpdateCall(_ call: Api.PhoneCall) {
|
|
self.addOperation(.UpdateCall(call))
|
|
}
|
|
|
|
mutating func addCallSignalingData(callId: Int64, data: Data) {
|
|
self.addOperation(.AddCallSignalingData(callId, data))
|
|
}
|
|
|
|
mutating func addSyncChatListFilters() {
|
|
self.addOperation(.SyncChatListFilters)
|
|
}
|
|
|
|
mutating func addUpdateChatListFilterOrder(order: [Int32]) {
|
|
self.addOperation(.UpdateChatListFilterOrder(order: order))
|
|
}
|
|
|
|
mutating func addUpdateChatListFilter(id: Int32, filter: Api.DialogFilter?) {
|
|
self.addOperation(.UpdateChatListFilter(id: id, filter: filter))
|
|
}
|
|
|
|
mutating func addOperation(_ operation: AccountStateMutationOperation) {
|
|
switch operation {
|
|
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout:
|
|
break
|
|
case let .AddMessages(messages, location):
|
|
for message in messages {
|
|
if case let .Id(id) = message.id {
|
|
self.storedMessages.insert(id)
|
|
if case .UpperHistoryBlock = location {
|
|
if (id.peerId.namespace == Namespaces.Peer.CloudUser || id.peerId.namespace == Namespaces.Peer.CloudGroup) && id.namespace == Namespaces.Message.Cloud {
|
|
if let updatedMaxMessageId = self.updatedMaxMessageId {
|
|
if updatedMaxMessageId < id.id {
|
|
self.updatedMaxMessageId = id.id
|
|
}
|
|
} else {
|
|
self.updatedMaxMessageId = id.id
|
|
}
|
|
}
|
|
}
|
|
}
|
|
inner: for attribute in message.attributes {
|
|
if let attribute = attribute as? ReplyMessageAttribute {
|
|
self.referencedMessageIds.insert(attribute.messageId)
|
|
break inner
|
|
}
|
|
}
|
|
}
|
|
case let .AddScheduledMessages(messages):
|
|
for message in messages {
|
|
if case let .Id(id) = message.id {
|
|
self.storedMessages.insert(id)
|
|
}
|
|
inner: for attribute in message.attributes {
|
|
if let attribute = attribute as? ReplyMessageAttribute {
|
|
self.referencedMessageIds.insert(attribute.messageId)
|
|
break inner
|
|
}
|
|
}
|
|
}
|
|
case let .UpdateState(state):
|
|
self.state = state
|
|
case let .UpdateChannelState(peerId, pts):
|
|
self.channelStates[peerId] = AccountStateChannelState(pts: pts)
|
|
case .UpdateChannelInvalidationPts:
|
|
break
|
|
case .UpdateChannelSynchronizedUntilMessage:
|
|
break
|
|
case let .UpdateNotificationSettings(subject, notificationSettings):
|
|
if case let .peer(peerId) = subject {
|
|
if var currentInfo = self.peerChatInfos[peerId] {
|
|
currentInfo.notificationSettings = notificationSettings
|
|
self.peerChatInfos[peerId] = currentInfo
|
|
}
|
|
}
|
|
case .UpdateGlobalNotificationSettings:
|
|
break
|
|
case let .MergeApiChats(chats):
|
|
for chat in chats {
|
|
if let groupOrChannel = mergeGroupOrChannel(lhs: peers[chat.peerId], rhs: chat) {
|
|
peers[groupOrChannel.id] = groupOrChannel
|
|
insertedPeers[groupOrChannel.id] = groupOrChannel
|
|
}
|
|
}
|
|
case let .MergeApiUsers(users):
|
|
for apiUser in users {
|
|
if let user = TelegramUser.merge(peers[apiUser.peerId] as? TelegramUser, rhs: apiUser) {
|
|
peers[user.id] = user
|
|
insertedPeers[user.id] = user
|
|
}
|
|
}
|
|
case let .UpdatePeer(id, f):
|
|
let peer = self.peers[id]
|
|
if let updatedPeer = f(peer) {
|
|
peers[id] = updatedPeer
|
|
insertedPeers[id] = updatedPeer
|
|
}
|
|
case let .ReadInbox(messageId):
|
|
let current = self.readInboxMaxIds[messageId.peerId]
|
|
if current == nil || current! < messageId {
|
|
self.readInboxMaxIds[messageId.peerId] = messageId
|
|
}
|
|
case let .ResetReadState(peerId, namespace, maxIncomingReadId, _, _, _, _):
|
|
let current = self.readInboxMaxIds[peerId]
|
|
if namespace == Namespaces.Message.Cloud {
|
|
if current == nil || current!.id < maxIncomingReadId {
|
|
self.readInboxMaxIds[peerId] = MessageId(peerId: peerId, namespace: namespace, id: maxIncomingReadId)
|
|
}
|
|
}
|
|
case let .ResetIncomingReadState(_, peerId, namespace, maxIncomingReadId, _, _):
|
|
let current = self.readInboxMaxIds[peerId]
|
|
if namespace == Namespaces.Message.Cloud {
|
|
if current == nil || current!.id < maxIncomingReadId {
|
|
self.readInboxMaxIds[peerId] = MessageId(peerId: peerId, namespace: namespace, id: maxIncomingReadId)
|
|
}
|
|
}
|
|
case .ResetMessageTagSummary:
|
|
break
|
|
}
|
|
|
|
self.operations.append(operation)
|
|
}
|
|
}
|
|
|
|
struct AccountFinalState {
|
|
var state: AccountMutableState
|
|
var shouldPoll: Bool
|
|
var incomplete: Bool
|
|
var missingUpdatesFromChannels: Set<PeerId>
|
|
var discard: Bool
|
|
}
|
|
|
|
struct AccountReplayedFinalState {
|
|
let state: AccountFinalState
|
|
let addedIncomingMessageIds: [MessageId]
|
|
let wasScheduledMessageIds: [MessageId]
|
|
let addedSecretMessageIds: [MessageId]
|
|
let deletedMessageIds: [DeletedMessageId]
|
|
let updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]]
|
|
let updatedWebpages: [MediaId: TelegramMediaWebpage]
|
|
let updatedCalls: [Api.PhoneCall]
|
|
let addedCallSignalingData: [(Int64, Data)]
|
|
let updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)]
|
|
let updatedPeersNearby: [PeerNearby]?
|
|
let isContactUpdates: [(PeerId, Bool)]
|
|
let delayNotificatonsUntil: Int32?
|
|
let updatedIncomingThreadReadStates: [MessageId: MessageId.Id]
|
|
let updatedOutgoingThreadReadStates: [MessageId: MessageId.Id]
|
|
}
|
|
|
|
struct AccountFinalStateEvents {
|
|
let addedIncomingMessageIds: [MessageId]
|
|
let wasScheduledMessageIds:[MessageId]
|
|
let deletedMessageIds: [DeletedMessageId]
|
|
let updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]]
|
|
let updatedWebpages: [MediaId: TelegramMediaWebpage]
|
|
let updatedCalls: [Api.PhoneCall]
|
|
let addedCallSignalingData: [(Int64, Data)]
|
|
let updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)]
|
|
let updatedPeersNearby: [PeerNearby]?
|
|
let isContactUpdates: [(PeerId, Bool)]
|
|
let displayAlerts: [(text: String, isDropAuth: Bool)]
|
|
let delayNotificatonsUntil: Int32?
|
|
let updatedMaxMessageId: Int32?
|
|
let updatedQts: Int32?
|
|
let externallyUpdatedPeerId: Set<PeerId>
|
|
let authorizationListUpdated: Bool
|
|
let updatedIncomingThreadReadStates: [MessageId: MessageId.Id]
|
|
let updatedOutgoingThreadReadStates: [MessageId: MessageId.Id]
|
|
|
|
var isEmpty: Bool {
|
|
return self.addedIncomingMessageIds.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty
|
|
}
|
|
|
|
init(addedIncomingMessageIds: [MessageId] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:]) {
|
|
self.addedIncomingMessageIds = addedIncomingMessageIds
|
|
self.wasScheduledMessageIds = wasScheduledMessageIds
|
|
self.deletedMessageIds = deletedMessageIds
|
|
self.updatedTypingActivities = updatedTypingActivities
|
|
self.updatedWebpages = updatedWebpages
|
|
self.updatedCalls = updatedCalls
|
|
self.addedCallSignalingData = addedCallSignalingData
|
|
self.updatedGroupCallParticipants = updatedGroupCallParticipants
|
|
self.updatedPeersNearby = updatedPeersNearby
|
|
self.isContactUpdates = isContactUpdates
|
|
self.displayAlerts = displayAlerts
|
|
self.delayNotificatonsUntil = delayNotificatonsUntil
|
|
self.updatedMaxMessageId = updatedMaxMessageId
|
|
self.updatedQts = updatedQts
|
|
self.externallyUpdatedPeerId = externallyUpdatedPeerId
|
|
self.authorizationListUpdated = authorizationListUpdated
|
|
self.updatedIncomingThreadReadStates = updatedIncomingThreadReadStates
|
|
self.updatedOutgoingThreadReadStates = updatedOutgoingThreadReadStates
|
|
}
|
|
|
|
init(state: AccountReplayedFinalState) {
|
|
self.addedIncomingMessageIds = state.addedIncomingMessageIds
|
|
self.wasScheduledMessageIds = state.wasScheduledMessageIds
|
|
self.deletedMessageIds = state.deletedMessageIds
|
|
self.updatedTypingActivities = state.updatedTypingActivities
|
|
self.updatedWebpages = state.updatedWebpages
|
|
self.updatedCalls = state.updatedCalls
|
|
self.addedCallSignalingData = state.addedCallSignalingData
|
|
self.updatedGroupCallParticipants = state.updatedGroupCallParticipants
|
|
self.updatedPeersNearby = state.updatedPeersNearby
|
|
self.isContactUpdates = state.isContactUpdates
|
|
self.displayAlerts = state.state.state.displayAlerts
|
|
self.delayNotificatonsUntil = state.delayNotificatonsUntil
|
|
self.updatedMaxMessageId = state.state.state.updatedMaxMessageId
|
|
self.updatedQts = state.state.state.updatedQts
|
|
self.externallyUpdatedPeerId = state.state.state.externallyUpdatedPeerId
|
|
self.authorizationListUpdated = state.state.state.authorizationListUpdated
|
|
self.updatedIncomingThreadReadStates = state.updatedIncomingThreadReadStates
|
|
self.updatedOutgoingThreadReadStates = state.updatedOutgoingThreadReadStates
|
|
}
|
|
|
|
func union(with other: AccountFinalStateEvents) -> AccountFinalStateEvents {
|
|
var delayNotificatonsUntil = self.delayNotificatonsUntil
|
|
if let other = self.delayNotificatonsUntil {
|
|
if delayNotificatonsUntil == nil || other > delayNotificatonsUntil! {
|
|
delayNotificatonsUntil = other
|
|
}
|
|
}
|
|
var updatedMaxMessageId: Int32?
|
|
var updatedQts: Int32?
|
|
if let lhsMaxMessageId = self.updatedMaxMessageId, let rhsMaxMessageId = other.updatedMaxMessageId {
|
|
updatedMaxMessageId = max(lhsMaxMessageId, rhsMaxMessageId)
|
|
} else {
|
|
updatedMaxMessageId = self.updatedMaxMessageId ?? other.updatedMaxMessageId
|
|
}
|
|
if let lhsQts = self.updatedQts, let rhsQts = other.updatedQts {
|
|
updatedQts = max(lhsQts, rhsQts)
|
|
} else {
|
|
updatedQts = self.updatedQts ?? other.updatedQts
|
|
}
|
|
|
|
let externallyUpdatedPeerId = self.externallyUpdatedPeerId.union(other.externallyUpdatedPeerId)
|
|
let authorizationListUpdated = self.authorizationListUpdated || other.authorizationListUpdated
|
|
|
|
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }))
|
|
}
|
|
}
|