State management fixes

This commit is contained in:
Ali 2020-04-22 21:37:41 +04:00
parent 4a045feb2f
commit fb07f06a26
9 changed files with 292 additions and 147 deletions

View File

@ -10,6 +10,11 @@ public final class InteractivePhoneFormatter {
public func updateText(_ text: String) -> (String?, String) { public func updateText(_ text: String) -> (String?, String) {
self.formatter.clear() self.formatter.clear()
let string = self.formatter.inputString(text) let string = self.formatter.inputString(text)
return (self.formatter.regionPrefix, string ?? "")
var regionPrefix = self.formatter.regionPrefix
if let string = string, string.hasPrefix("+383") {
regionPrefix = "+383"
}
return (regionPrefix, string ?? "")
} }
} }

View File

@ -10,20 +10,24 @@ struct PeerChatInfo {
var notificationSettings: PeerNotificationSettings var notificationSettings: PeerNotificationSettings
} }
struct AccountStateChannelState: Equatable {
var pts: Int32
}
final class AccountInitialState { final class AccountInitialState {
let state: AuthorizedAccountState.State let state: AuthorizedAccountState.State
let peerIds: Set<PeerId> let peerIds: Set<PeerId>
let chatStates: [PeerId: PeerChatState] let channelStates: [PeerId: AccountStateChannelState]
let peerChatInfos: [PeerId: PeerChatInfo] let peerChatInfos: [PeerId: PeerChatInfo]
let peerIdsRequiringLocalChatState: Set<PeerId> let peerIdsRequiringLocalChatState: Set<PeerId>
let locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]] let locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]
let cloudReadStates: [PeerId: PeerReadState] let cloudReadStates: [PeerId: PeerReadState]
let channelsToPollExplicitely: Set<PeerId> let channelsToPollExplicitely: Set<PeerId>
init(state: AuthorizedAccountState.State, peerIds: Set<PeerId>, peerIdsRequiringLocalChatState: Set<PeerId>, chatStates: [PeerId: PeerChatState], peerChatInfos: [PeerId: PeerChatInfo], locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]], cloudReadStates: [PeerId: PeerReadState], 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.state = state
self.peerIds = peerIds self.peerIds = peerIds
self.chatStates = chatStates self.channelStates = channelStates
self.peerIdsRequiringLocalChatState = peerIdsRequiringLocalChatState self.peerIdsRequiringLocalChatState = peerIdsRequiringLocalChatState
self.peerChatInfos = peerChatInfos self.peerChatInfos = peerChatInfos
self.locallyGeneratedMessageTimestamps = locallyGeneratedMessageTimestamps self.locallyGeneratedMessageTimestamps = locallyGeneratedMessageTimestamps
@ -72,7 +76,9 @@ enum AccountStateMutationOperation {
case ResetMessageTagSummary(PeerId, MessageId.Namespace, Int32, MessageHistoryTagNamespaceCountValidityRange) case ResetMessageTagSummary(PeerId, MessageId.Namespace, Int32, MessageHistoryTagNamespaceCountValidityRange)
case ReadGroupFeedInbox(PeerGroupId, MessageIndex) case ReadGroupFeedInbox(PeerGroupId, MessageIndex)
case UpdateState(AuthorizedAccountState.State) case UpdateState(AuthorizedAccountState.State)
case UpdateChannelState(PeerId, ChannelState) case UpdateChannelState(PeerId, Int32)
case UpdateChannelInvalidationPts(PeerId, Int32)
case UpdateChannelSynchronizedUntilMessage(PeerId, MessageId.Id)
case UpdateNotificationSettings(AccountStateNotificationSettingsSubject, PeerNotificationSettings) case UpdateNotificationSettings(AccountStateNotificationSettingsSubject, PeerNotificationSettings)
case UpdateGlobalNotificationSettings(AccountStateGlobalNotificationSettingsSubject, MessageNotificationSettings) case UpdateGlobalNotificationSettings(AccountStateGlobalNotificationSettingsSubject, MessageNotificationSettings)
case MergeApiChats([Api.Chat]) case MergeApiChats([Api.Chat])
@ -110,7 +116,7 @@ struct AccountMutableState {
var state: AuthorizedAccountState.State var state: AuthorizedAccountState.State
var peers: [PeerId: Peer] var peers: [PeerId: Peer]
var chatStates: [PeerId: PeerChatState] var channelStates: [PeerId: AccountStateChannelState]
var peerChatInfos: [PeerId: PeerChatInfo] var peerChatInfos: [PeerId: PeerChatInfo]
var referencedMessageIds: Set<MessageId> var referencedMessageIds: Set<MessageId>
var storedMessages: Set<MessageId> var storedMessages: Set<MessageId>
@ -139,7 +145,7 @@ struct AccountMutableState {
self.referencedMessageIds = initialReferencedMessageIds self.referencedMessageIds = initialReferencedMessageIds
self.storedMessages = initialStoredMessages self.storedMessages = initialStoredMessages
self.readInboxMaxIds = initialReadInboxMaxIds self.readInboxMaxIds = initialReadInboxMaxIds
self.chatStates = initialState.chatStates self.channelStates = initialState.channelStates
self.peerChatInfos = initialState.peerChatInfos self.peerChatInfos = initialState.peerChatInfos
self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp
self.branchOperationIndex = 0 self.branchOperationIndex = 0
@ -147,12 +153,12 @@ struct AccountMutableState {
self.updatedOutgoingUniqueMessageIds = [:] self.updatedOutgoingUniqueMessageIds = [:]
} }
init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], chatStates: [PeerId: PeerChatState], peerChatInfos: [PeerId: PeerChatInfo], referencedMessageIds: Set<MessageId>, storedMessages: Set<MessageId>, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>], namespacesWithHolesFromPreviousState: [PeerId: Set<MessageId.Namespace>], updatedOutgoingUniqueMessageIds: [Int64: Int32], displayAlerts: [(text: String, isDropAuth: Bool)], branchOperationIndex: Int) { 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: Set<MessageId.Namespace>], updatedOutgoingUniqueMessageIds: [Int64: Int32], displayAlerts: [(text: String, isDropAuth: Bool)], branchOperationIndex: Int) {
self.initialState = initialState self.initialState = initialState
self.operations = operations self.operations = operations
self.state = state self.state = state
self.peers = peers self.peers = peers
self.chatStates = chatStates self.channelStates = channelStates
self.referencedMessageIds = referencedMessageIds self.referencedMessageIds = referencedMessageIds
self.storedMessages = storedMessages self.storedMessages = storedMessages
self.peerChatInfos = peerChatInfos self.peerChatInfos = peerChatInfos
@ -165,7 +171,7 @@ struct AccountMutableState {
} }
func branch() -> AccountMutableState { func branch() -> AccountMutableState {
return AccountMutableState(initialState: self.initialState, operations: self.operations, state: self.state, peers: self.peers, chatStates: self.chatStates, 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) 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) { mutating func merge(_ other: AccountMutableState) {
@ -269,8 +275,16 @@ struct AccountMutableState {
self.addOperation(.UpdateState(state)) self.addOperation(.UpdateState(state))
} }
mutating func updateChannelState(_ peerId: PeerId, state: ChannelState) { mutating func updateChannelState(_ peerId: PeerId, pts: Int32) {
self.addOperation(.UpdateChannelState(peerId, state)) 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) { mutating func updateNotificationSettings(_ subject: AccountStateNotificationSettingsSubject, notificationSettings: PeerNotificationSettings) {
@ -464,8 +478,12 @@ struct AccountMutableState {
} }
case let .UpdateState(state): case let .UpdateState(state):
self.state = state self.state = state
case let .UpdateChannelState(peerId, channelState): case let .UpdateChannelState(peerId, pts):
self.chatStates[peerId] = channelState self.channelStates[peerId] = AccountStateChannelState(pts: pts)
case .UpdateChannelInvalidationPts:
break
case .UpdateChannelSynchronizedUntilMessage:
break
case let .UpdateNotificationSettings(subject, notificationSettings): case let .UpdateNotificationSettings(subject, notificationSettings):
if case let .peer(peerId) = subject { if case let .peer(peerId) = subject {
if var currentInfo = self.peerChatInfos[peerId] { if var currentInfo = self.peerChatInfos[peerId] {

View File

@ -356,7 +356,7 @@ private func locallyGeneratedMessageTimestampsFromDifference(_ difference: Api.u
private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set<PeerId>, activeChannelIds: Set<PeerId>, associatedMessageIds: Set<MessageId>, peerIdsRequiringLocalChatState: Set<PeerId>, locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]) -> AccountMutableState { private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set<PeerId>, activeChannelIds: Set<PeerId>, associatedMessageIds: Set<MessageId>, peerIdsRequiringLocalChatState: Set<PeerId>, locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]) -> AccountMutableState {
var peers: [PeerId: Peer] = [:] var peers: [PeerId: Peer] = [:]
var chatStates: [PeerId: PeerChatState] = [:] var channelStates: [PeerId: AccountStateChannelState] = [:]
var channelsToPollExplicitely = Set<PeerId>() var channelsToPollExplicitely = Set<PeerId>()
@ -367,11 +367,11 @@ private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set<Pe
if peerId.namespace == Namespaces.Peer.CloudChannel { if peerId.namespace == Namespaces.Peer.CloudChannel {
if let channelState = transaction.getPeerChatState(peerId) as? ChannelState { if let channelState = transaction.getPeerChatState(peerId) as? ChannelState {
chatStates[peerId] = channelState channelStates[peerId] = AccountStateChannelState(pts: channelState.pts)
} }
} else if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { } else if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup {
if let chatState = transaction.getPeerChatState(peerId) as? RegularChatState { if let _ = transaction.getPeerChatState(peerId) as? RegularChatState {
chatStates[peerId] = chatState //chatStates[peerId] = chatState
} }
} }
} }
@ -434,7 +434,7 @@ private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set<Pe
} }
} }
return AccountMutableState(initialState: AccountInitialState(state: (transaction.getState() as? AuthorizedAccountState)!.state!, peerIds: peerIds, peerIdsRequiringLocalChatState: peerIdsRequiringLocalChatState, chatStates: chatStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: locallyGeneratedMessageTimestamps, cloudReadStates: cloudReadStates, channelsToPollExplicitely: channelsToPollExplicitely), initialPeers: peers, initialReferencedMessageIds: associatedMessageIds, initialStoredMessages: storedMessages, initialReadInboxMaxIds: readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: storedMessagesByPeerIdAndTimestamp) return AccountMutableState(initialState: AccountInitialState(state: (transaction.getState() as? AuthorizedAccountState)!.state!, peerIds: peerIds, peerIdsRequiringLocalChatState: peerIdsRequiringLocalChatState, channelStates: channelStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: locallyGeneratedMessageTimestamps, cloudReadStates: cloudReadStates, channelsToPollExplicitely: channelsToPollExplicitely), initialPeers: peers, initialReferencedMessageIds: associatedMessageIds, initialStoredMessages: storedMessages, initialReadInboxMaxIds: readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: storedMessagesByPeerIdAndTimestamp)
} }
func initialStateWithUpdateGroups(postbox: Postbox, groups: [UpdateGroup]) -> Signal<AccountMutableState, NoError> { func initialStateWithUpdateGroups(postbox: Postbox, groups: [UpdateGroup]) -> Signal<AccountMutableState, NoError> {
@ -772,7 +772,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
case let .updateChannelTooLong(_, channelId, channelPts): case let .updateChannelTooLong(_, channelId, channelPts):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
if !channelsToPoll.contains(peerId) { if !channelsToPoll.contains(peerId) {
if let channelPts = channelPts, let channelState = state.chatStates[peerId] as? ChannelState, channelState.pts >= channelPts { if let channelPts = channelPts, let channelState = state.channelStates[peerId], channelState.pts >= channelPts {
Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) skip updateChannelTooLong by pts") Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) skip updateChannelTooLong by pts")
} else { } else {
channelsToPoll.insert(peerId) channelsToPoll.insert(peerId)
@ -780,12 +780,12 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
} }
case let .updateDeleteChannelMessages(channelId, messages, pts: pts, ptsCount): case let .updateDeleteChannelMessages(channelId, messages, pts: pts, ptsCount):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
if let previousState = updatedState.chatStates[peerId] as? ChannelState { if let previousState = updatedState.channelStates[peerId] {
if previousState.pts >= pts { if previousState.pts >= pts {
Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) skip old delete update") Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) skip old delete update")
} else if previousState.pts + ptsCount == pts { } else if previousState.pts + ptsCount == pts {
updatedState.deleteMessages(messages.map({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })) updatedState.deleteMessages(messages.map({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }))
updatedState.updateChannelState(peerId, state: previousState.withUpdatedPts(pts)) updatedState.updateChannelState(peerId, pts: pts)
} else { } else {
if !channelsToPoll.contains(peerId) { if !channelsToPoll.contains(peerId) {
Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) delete pts hole") Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) delete pts hole")
@ -802,7 +802,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
case let .updateEditChannelMessage(apiMessage, pts, ptsCount): case let .updateEditChannelMessage(apiMessage, pts, ptsCount):
if let message = StoreMessage(apiMessage: apiMessage), case let .Id(messageId) = message.id { if let message = StoreMessage(apiMessage: apiMessage), case let .Id(messageId) = message.id {
let peerId = messageId.peerId let peerId = messageId.peerId
if let previousState = updatedState.chatStates[peerId] as? ChannelState { if let previousState = updatedState.channelStates[peerId] {
if previousState.pts >= pts { if previousState.pts >= pts {
Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) skip old edit update") Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) skip old edit update")
} else if previousState.pts + ptsCount == pts { } else if previousState.pts + ptsCount == pts {
@ -814,7 +814,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
var attributes = message.attributes var attributes = message.attributes
attributes.append(ChannelMessageStateVersionAttribute(pts: pts)) attributes.append(ChannelMessageStateVersionAttribute(pts: pts))
updatedState.editMessage(messageId, message: message.withUpdatedAttributes(attributes)) updatedState.editMessage(messageId, message: message.withUpdatedAttributes(attributes))
updatedState.updateChannelState(peerId, state: previousState.withUpdatedPts(pts)) updatedState.updateChannelState(peerId, pts: pts)
} else { } else {
if !channelsToPoll.contains(peerId) { if !channelsToPoll.contains(peerId) {
Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) edit message pts hole") Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) edit message pts hole")
@ -833,7 +833,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
} }
case let .updateChannelWebPage(channelId, apiWebpage, pts, ptsCount): case let .updateChannelWebPage(channelId, apiWebpage, pts, ptsCount):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
if let previousState = updatedState.chatStates[peerId] as? ChannelState { if let previousState = updatedState.channelStates[peerId] {
if previousState.pts >= pts { if previousState.pts >= pts {
} else if previousState.pts + ptsCount == pts { } else if previousState.pts + ptsCount == pts {
switch apiWebpage { switch apiWebpage {
@ -845,7 +845,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
} }
} }
updatedState.updateChannelState(peerId, state: previousState.withUpdatedPts(pts)) updatedState.updateChannelState(peerId, pts: pts)
} else { } else {
if !channelsToPoll.contains(peerId) { if !channelsToPoll.contains(peerId) {
Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) updateWebPage pts hole") Logger.shared.log("State", "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) updateWebPage pts hole")
@ -880,7 +880,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
} }
case let .updateNewChannelMessage(apiMessage, pts, ptsCount): case let .updateNewChannelMessage(apiMessage, pts, ptsCount):
if let message = StoreMessage(apiMessage: apiMessage) { if let message = StoreMessage(apiMessage: apiMessage) {
if let previousState = updatedState.chatStates[message.id.peerId] as? ChannelState { if let previousState = updatedState.channelStates[message.id.peerId] {
if previousState.pts >= pts { if previousState.pts >= pts {
let messageText: String let messageText: String
if Logger.shared.redactSensitiveData { if Logger.shared.redactSensitiveData {
@ -898,7 +898,10 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
var attributes = message.attributes var attributes = message.attributes
attributes.append(ChannelMessageStateVersionAttribute(pts: pts)) attributes.append(ChannelMessageStateVersionAttribute(pts: pts))
updatedState.addMessages([message.withUpdatedAttributes(attributes)], location: .UpperHistoryBlock) updatedState.addMessages([message.withUpdatedAttributes(attributes)], location: .UpperHistoryBlock)
updatedState.updateChannelState(message.id.peerId, state: previousState.withUpdatedPts(pts)) updatedState.updateChannelState(message.id.peerId, pts: pts)
if case let .Id(id) = message.id {
updatedState.updateChannelSynchronizedUntilMessage(id.peerId, id: id.id)
}
} else { } else {
if !channelsToPoll.contains(message.id.peerId) { if !channelsToPoll.contains(message.id.peerId) {
Logger.shared.log("State", "channel \(message.id.peerId) (\((updatedState.peers[message.id.peerId] as? TelegramChannel)?.title ?? "nil")) message pts hole") Logger.shared.log("State", "channel \(message.id.peerId) (\((updatedState.peers[message.id.peerId] as? TelegramChannel)?.title ?? "nil")) message pts hole")
@ -1587,9 +1590,9 @@ private func resolveMissingPeerChatInfos(network: Network, state: AccountMutable
func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager) -> Signal<Void, NoError> { func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Signal<Void, NoError> in return postbox.transaction { transaction -> Signal<Void, NoError> in
if let accountState = (transaction.getState() as? AuthorizedAccountState)?.state, let peer = transaction.getPeer(peerId) { if let accountState = (transaction.getState() as? AuthorizedAccountState)?.state, let peer = transaction.getPeer(peerId) {
var chatStates: [PeerId: PeerChatState] = [:] var channelStates: [PeerId: AccountStateChannelState] = [:]
if let channelState = transaction.getPeerChatState(peerId) as? ChannelState { if let channelState = transaction.getPeerChatState(peerId) as? ChannelState {
chatStates[peerId] = channelState channelStates[peerId] = AccountStateChannelState(pts: channelState.pts)
} }
let initialPeers: [PeerId: Peer] = [peerId: peer] let initialPeers: [PeerId: Peer] = [peerId: peer]
var peerChatInfos: [PeerId: PeerChatInfo] = [:] var peerChatInfos: [PeerId: PeerChatInfo] = [:]
@ -1606,7 +1609,7 @@ func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stat
peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings) peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings)
} }
} }
let initialState = AccountMutableState(initialState: AccountInitialState(state: accountState, peerIds: Set(), peerIdsRequiringLocalChatState: Set(), chatStates: chatStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: [:], cloudReadStates: [:], channelsToPollExplicitely: Set()), initialPeers: initialPeers, initialReferencedMessageIds: Set(), initialStoredMessages: Set(), initialReadInboxMaxIds: [:], storedMessagesByPeerIdAndTimestamp: [:]) let initialState = AccountMutableState(initialState: AccountInitialState(state: accountState, peerIds: Set(), peerIdsRequiringLocalChatState: Set(), channelStates: channelStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: [:], cloudReadStates: [:], channelsToPollExplicitely: Set()), initialPeers: initialPeers, initialReferencedMessageIds: Set(), initialStoredMessages: Set(), initialReadInboxMaxIds: [:], storedMessagesByPeerIdAndTimestamp: [:])
return pollChannel(network: network, peer: peer, state: initialState) return pollChannel(network: network, peer: peer, state: initialState)
|> mapToSignal { (finalState, _, timeout) -> Signal<Void, NoError> in |> mapToSignal { (finalState, _, timeout) -> Signal<Void, NoError> in
return resolveAssociatedMessages(network: network, state: finalState) return resolveAssociatedMessages(network: network, state: finalState)
@ -1657,7 +1660,9 @@ private func resetChannels(network: Network, peers: [Peer], state: AccountMutabl
var storeMessages: [StoreMessage] = [] var storeMessages: [StoreMessage] = []
var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:] var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:]
var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:] var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:]
var channelStates: [PeerId: ChannelState] = [:] var channelStates: [PeerId: AccountStateChannelState] = [:]
var invalidateChannelStates: [PeerId: Int32] = [:]
var channelSynchronizedUntilMessage: [PeerId: MessageId.Id] = [:]
var notificationSettings: [PeerId: PeerNotificationSettings] = [:] var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
if let result = result { if let result = result {
@ -1714,7 +1719,8 @@ private func resetChannels(network: Network, peers: [Peer], state: AccountMutabl
} }
if let apiChannelPts = apiChannelPts { if let apiChannelPts = apiChannelPts {
channelStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: apiChannelPts, synchronizedUntilMessageId: nil) channelStates[peerId] = AccountStateChannelState(pts: apiChannelPts)
invalidateChannelStates[peerId] = apiChannelPts
} }
notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings) notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings)
@ -1744,6 +1750,7 @@ private func resetChannels(network: Network, peers: [Peer], state: AccountMutabl
for message in storeMessages { for message in storeMessages {
if case let .Id(id) = message.id, id.namespace == Namespaces.Message.Cloud { if case let .Id(id) = message.id, id.namespace == Namespaces.Message.Cloud {
updatedState.setNeedsHoleFromPreviousState(peerId: id.peerId, namespace: id.namespace) updatedState.setNeedsHoleFromPreviousState(peerId: id.peerId, namespace: id.namespace)
channelSynchronizedUntilMessage[id.peerId] = id.id
} }
} }
@ -1766,7 +1773,13 @@ private func resetChannels(network: Network, peers: [Peer], state: AccountMutabl
} }
for (peerId, channelState) in channelStates { for (peerId, channelState) in channelStates {
updatedState.updateChannelState(peerId, state: channelState) updatedState.updateChannelState(peerId, pts: channelState.pts)
}
for (peerId, pts) in invalidateChannelStates {
updatedState.updateChannelInvalidationPts(peerId, invalidationPts: pts)
}
for (peerId, id) in channelSynchronizedUntilMessage {
updatedState.updateChannelSynchronizedUntilMessage(peerId, id: id)
} }
for (peerId, settings) in notificationSettings { for (peerId, settings) in notificationSettings {
@ -1792,7 +1805,7 @@ private func pollChannel(network: Network, peer: Peer, state: AccountMutableStat
#endif #endif
let pollPts: Int32 let pollPts: Int32
if let channelState = state.chatStates[peer.id] as? ChannelState { if let channelState = state.channelStates[peer.id] {
pollPts = channelState.pts pollPts = channelState.pts
} else { } else {
pollPts = 1 pollPts = 1
@ -1814,13 +1827,13 @@ private func pollChannel(network: Network, peer: Peer, state: AccountMutableStat
switch difference { switch difference {
case let .channelDifference(_, pts, timeout, newMessages, otherUpdates, chats, users): case let .channelDifference(_, pts, timeout, newMessages, otherUpdates, chats, users):
apiTimeout = timeout apiTimeout = timeout
let channelState: ChannelState let channelPts: Int32
if let previousState = updatedState.chatStates[peer.id] as? ChannelState { if let _ = updatedState.channelStates[peer.id] {
channelState = previousState.withUpdatedPts(pts) channelPts = pts
} else { } else {
channelState = ChannelState(pts: pts, invalidatedPts: nil, synchronizedUntilMessageId: nil) channelPts = pts
} }
updatedState.updateChannelState(peer.id, state: channelState) updatedState.updateChannelState(peer.id, pts: channelPts)
updatedState.mergeChats(chats) updatedState.mergeChats(chats)
updatedState.mergeUsers(users) updatedState.mergeUsers(users)
@ -1833,6 +1846,9 @@ private func pollChannel(network: Network, peer: Peer, state: AccountMutableStat
} }
} }
updatedState.addMessages([message], location: .UpperHistoryBlock) updatedState.addMessages([message], location: .UpperHistoryBlock)
if case let .Id(id) = message.id {
updatedState.updateChannelSynchronizedUntilMessage(id.peerId, id: id.id)
}
} }
} }
for update in otherUpdates { for update in otherUpdates {
@ -1895,13 +1911,13 @@ private func pollChannel(network: Network, peer: Peer, state: AccountMutableStat
case let .channelDifferenceEmpty(_, pts, timeout): case let .channelDifferenceEmpty(_, pts, timeout):
apiTimeout = timeout apiTimeout = timeout
let channelState: ChannelState let channelPts: Int32
if let previousState = updatedState.chatStates[peer.id] as? ChannelState { if let previousState = updatedState.channelStates[peer.id] {
channelState = previousState.withUpdatedPts(pts) channelPts = pts
} else { } else {
channelState = ChannelState(pts: pts, invalidatedPts: nil, synchronizedUntilMessageId: nil) channelPts = pts
} }
updatedState.updateChannelState(peer.id, state: channelState) updatedState.updateChannelState(peer.id, pts: channelPts)
case let .channelDifferenceTooLong(_, timeout, dialog, messages, chats, users): case let .channelDifferenceTooLong(_, timeout, dialog, messages, chats, users):
apiTimeout = timeout apiTimeout = timeout
@ -1917,8 +1933,8 @@ private func pollChannel(network: Network, peer: Peer, state: AccountMutableStat
} }
if let (peer, pts, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount) = parameters { if let (peer, pts, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount) = parameters {
let channelState = ChannelState(pts: pts, invalidatedPts: pts, synchronizedUntilMessageId: nil) updatedState.updateChannelState(peer.peerId, pts: pts)
updatedState.updateChannelState(peer.peerId, state: channelState) updatedState.updateChannelInvalidationPts(peer.peerId, invalidationPts: pts)
updatedState.mergeChats(chats) updatedState.mergeChats(chats)
updatedState.mergeUsers(users) updatedState.mergeUsers(users)
@ -1936,6 +1952,7 @@ private func pollChannel(network: Network, peer: Peer, state: AccountMutableStat
let location: AddMessagesLocation let location: AddMessagesLocation
if case let .Id(id) = message.id, id.id == topMessage { if case let .Id(id) = message.id, id.id == topMessage {
location = .UpperHistoryBlock location = .UpperHistoryBlock
updatedState.updateChannelSynchronizedUntilMessage(id.peerId, id: id.id)
} else { } else {
location = .Random location = .Random
} }
@ -2007,9 +2024,9 @@ private func verifyTransaction(_ transaction: Transaction, finalState: AccountMu
for peerId in channelsWithUpdatedStates { for peerId in channelsWithUpdatedStates {
let currentState = transaction.getPeerChatState(peerId) let currentState = transaction.getPeerChatState(peerId)
var previousStateMatches = false var previousStateMatches = false
let previousState = finalState.initialState.chatStates[peerId] as? ChannelState let previousState = finalState.initialState.channelStates[peerId]
if let currentState = currentState, let previousState = previousState { if let currentState = currentState as? ChannelState, let previousState = previousState {
if currentState.equals(previousState) { if currentState.pts == previousState.pts {
previousStateMatches = true previousStateMatches = true
} }
} else if currentState == nil && previousState == nil { } else if currentState == nil && previousState == nil {
@ -2048,7 +2065,9 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
var result: [AccountStateMutationOperation] = [] var result: [AccountStateMutationOperation] = []
var updatedState: AuthorizedAccountState.State? var updatedState: AuthorizedAccountState.State?
var updatedChannelStates: [PeerId: ChannelState] = [:] var updatedChannelStates: [PeerId: AccountStateChannelState] = [:]
var invalidateChannelPts: [PeerId: Int32] = [:]
var updateChannelSynchronizedUntilMessage: [PeerId: MessageId.Id] = [:]
var currentAddMessages: OptimizeAddMessagesState? var currentAddMessages: OptimizeAddMessagesState?
var currentAddScheduledMessages: OptimizeAddMessagesState? var currentAddScheduledMessages: OptimizeAddMessagesState?
@ -2065,8 +2084,12 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
result.append(operation) result.append(operation)
case let .UpdateState(state): case let .UpdateState(state):
updatedState = state updatedState = state
case let .UpdateChannelState(peerId, state): case let .UpdateChannelState(peerId, pts):
updatedChannelStates[peerId] = state updatedChannelStates[peerId] = AccountStateChannelState(pts: pts)
case let .UpdateChannelInvalidationPts(peerId, pts):
invalidateChannelPts[peerId] = pts
case let .UpdateChannelSynchronizedUntilMessage(peerId, id):
updateChannelSynchronizedUntilMessage[peerId] = id
case let .AddMessages(messages, location): case let .AddMessages(messages, location):
if let currentAddMessages = currentAddMessages, currentAddMessages.location == location { if let currentAddMessages = currentAddMessages, currentAddMessages.location == location {
currentAddMessages.messages.append(contentsOf: messages) currentAddMessages.messages.append(contentsOf: messages)
@ -2097,7 +2120,15 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
} }
for (peerId, state) in updatedChannelStates { for (peerId, state) in updatedChannelStates {
result.append(.UpdateChannelState(peerId, state)) result.append(.UpdateChannelState(peerId, state.pts))
}
for (peerId, pts) in invalidateChannelPts {
result.append(.UpdateChannelInvalidationPts(peerId, pts))
}
for (peerId, id) in updateChannelSynchronizedUntilMessage {
result.append(.UpdateChannelSynchronizedUntilMessage(peerId, id))
} }
return result return result
@ -2144,8 +2175,18 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
for (peerId, namespaces) in finalState.state.namespacesWithHolesFromPreviousState { for (peerId, namespaces) in finalState.state.namespacesWithHolesFromPreviousState {
for namespace in namespaces { for namespace in namespaces {
if let id = transaction.getTopPeerMessageId(peerId: peerId, namespace: namespace) { var topId: Int32?
holesFromPreviousStateMessageIds.append(MessageId(peerId: id.peerId, namespace: id.namespace, id: id.id + 1)) if namespace == Namespaces.Message.Cloud, let channelState = transaction.getPeerChatState(peerId) as? ChannelState {
if let synchronizedUntilMessageId = channelState.synchronizedUntilMessageId {
topId = synchronizedUntilMessageId + 1
}
}
if topId == nil {
topId = transaction.getTopPeerMessageId(peerId: peerId, namespace: namespace)?.id
}
if let id = topId {
holesFromPreviousStateMessageIds.append(MessageId(peerId: peerId, namespace: namespace, id: id + 1))
} else { } else {
holesFromPreviousStateMessageIds.append(MessageId(peerId: peerId, namespace: namespace, id: 1)) holesFromPreviousStateMessageIds.append(MessageId(peerId: peerId, namespace: namespace, id: 1))
} }
@ -2494,9 +2535,21 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
let currentState = transaction.getState() as! AuthorizedAccountState let currentState = transaction.getState() as! AuthorizedAccountState
transaction.setState(currentState.changedState(state)) transaction.setState(currentState.changedState(state))
Logger.shared.log("State", "apply state \(state)") Logger.shared.log("State", "apply state \(state)")
case let .UpdateChannelState(peerId, channelState): case let .UpdateChannelState(peerId, pts):
transaction.setPeerChatState(peerId, state: channelState) var state = (transaction.getPeerChatState(peerId) as? ChannelState) ?? ChannelState(pts: pts, invalidatedPts: nil, synchronizedUntilMessageId: nil)
Logger.shared.log("State", "apply channel state \(peerId): \(channelState)") state = state.withUpdatedPts(pts)
transaction.setPeerChatState(peerId, state: state)
Logger.shared.log("State", "apply channel state \(peerId): \(state)")
case let .UpdateChannelInvalidationPts(peerId, pts):
var state = (transaction.getPeerChatState(peerId) as? ChannelState) ?? ChannelState(pts: 0, invalidatedPts: pts, synchronizedUntilMessageId: nil)
state = state.withUpdatedInvalidatedPts(pts)
transaction.setPeerChatState(peerId, state: state)
Logger.shared.log("State", "apply channel invalidation pts \(peerId): \(state)")
case let .UpdateChannelSynchronizedUntilMessage(peerId, id):
var state = (transaction.getPeerChatState(peerId) as? ChannelState) ?? ChannelState(pts: 0, invalidatedPts: nil, synchronizedUntilMessageId: id)
state = state.withUpdatedSynchronizedUntilMessageId(id)
transaction.setPeerChatState(peerId, state: state)
Logger.shared.log("State", "apply channel synchronized until message \(peerId): \(state)")
case let .UpdateNotificationSettings(subject, notificationSettings): case let .UpdateNotificationSettings(subject, notificationSettings):
switch subject { switch subject {
case let .peer(peerId): case let .peer(peerId):

View File

@ -564,7 +564,7 @@ private func loadAndStorePeerChatInfos(accountPeerId: PeerId, postbox: Postbox,
var peers: [Peer] = [] var peers: [Peer] = []
var peerPresences: [PeerId: PeerPresence] = [:] var peerPresences: [PeerId: PeerPresence] = [:]
var notificationSettings: [PeerId: PeerNotificationSettings] = [:] var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
var channelStates: [PeerId: ChannelState] = [:] var channelStates: [PeerId: Int32] = [:]
switch result { switch result {
case let .peerDialogs(dialogs, messages, chats, users, _): case let .peerDialogs(dialogs, messages, chats, users, _):
@ -644,9 +644,10 @@ private func loadAndStorePeerChatInfos(accountPeerId: PeerId, postbox: Postbox,
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, maxId: topMessage) transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: unreadMentionsCount, maxId: topMessage)
if let pts = pts { if let pts = pts {
let channelState = ChannelState(pts: pts, invalidatedPts: pts, synchronizedUntilMessageId: nil) if transaction.getPeerChatState(peerId) == nil {
transaction.setPeerChatState(peerId, state: channelState) transaction.setPeerChatState(peerId, state: ChannelState(pts: pts, invalidatedPts: nil, synchronizedUntilMessageId: nil))
channelStates[peer.peerId] = channelState }
channelStates[peer.peerId] = pts
} }
case .dialogFolder: case .dialogFolder:
assertionFailure() assertionFailure()
@ -659,9 +660,9 @@ private func loadAndStorePeerChatInfos(accountPeerId: PeerId, postbox: Postbox,
if let storeMessage = StoreMessage(apiMessage: message) { if let storeMessage = StoreMessage(apiMessage: message) {
var updatedStoreMessage = storeMessage var updatedStoreMessage = storeMessage
if case let .Id(id) = storeMessage.id { if case let .Id(id) = storeMessage.id {
if let channelState = channelStates[id.peerId] { if let channelPts = channelStates[id.peerId] {
var updatedAttributes = storeMessage.attributes var updatedAttributes = storeMessage.attributes
updatedAttributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts)) updatedAttributes.append(ChannelMessageStateVersionAttribute(pts: channelPts))
updatedStoreMessage = updatedStoreMessage.withUpdatedAttributes(updatedAttributes) updatedStoreMessage = updatedStoreMessage.withUpdatedAttributes(updatedAttributes)
} }
} }

View File

@ -19,7 +19,7 @@ struct ParsedDialogs {
let notificationSettings: [PeerId: PeerNotificationSettings] let notificationSettings: [PeerId: PeerNotificationSettings]
let readStates: [PeerId: [MessageId.Namespace: PeerReadState]] let readStates: [PeerId: [MessageId.Namespace: PeerReadState]]
let mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] let mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary]
let chatStates: [PeerId: PeerChatState] let channelStates: [PeerId: Int32]
let topMessageIds: [PeerId: MessageId] let topMessageIds: [PeerId: MessageId]
let storeMessages: [StoreMessage] let storeMessages: [StoreMessage]
@ -50,7 +50,7 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message],
var notificationSettings: [PeerId: PeerNotificationSettings] = [:] var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:] var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:]
var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:] var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:]
var chatStates: [PeerId: PeerChatState] = [:] var channelStates: [PeerId: Int32] = [:]
var topMessageIds: [PeerId: MessageId] = [:] var topMessageIds: [PeerId: MessageId] = [:]
var storeMessages: [StoreMessage] = [] var storeMessages: [StoreMessage] = []
@ -131,7 +131,7 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message],
} }
if let apiChannelPts = apiChannelPts { if let apiChannelPts = apiChannelPts {
chatStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: nil, synchronizedUntilMessageId: nil) channelStates[peerId] = apiChannelPts
} }
notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings) notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings)
@ -149,9 +149,9 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message],
if let storeMessage = StoreMessage(apiMessage: message) { if let storeMessage = StoreMessage(apiMessage: message) {
var updatedStoreMessage = storeMessage var updatedStoreMessage = storeMessage
if case let .Id(id) = storeMessage.id { if case let .Id(id) = storeMessage.id {
if let channelState = chatStates[id.peerId] as? ChannelState { if let channelPts = channelStates[id.peerId] {
var updatedAttributes = storeMessage.attributes var updatedAttributes = storeMessage.attributes
updatedAttributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts)) updatedAttributes.append(ChannelMessageStateVersionAttribute(pts: channelPts))
updatedStoreMessage = updatedStoreMessage.withUpdatedAttributes(updatedAttributes) updatedStoreMessage = updatedStoreMessage.withUpdatedAttributes(updatedAttributes)
} }
@ -174,7 +174,7 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message],
notificationSettings: notificationSettings, notificationSettings: notificationSettings,
readStates: readStates, readStates: readStates,
mentionTagSummaries: mentionTagSummaries, mentionTagSummaries: mentionTagSummaries,
chatStates: chatStates, channelStates: channelStates,
topMessageIds: topMessageIds, topMessageIds: topMessageIds,
storeMessages: storeMessages, storeMessages: storeMessages,
@ -190,7 +190,7 @@ struct FetchedChatList {
let notificationSettings: [PeerId: PeerNotificationSettings] let notificationSettings: [PeerId: PeerNotificationSettings]
let readStates: [PeerId: [MessageId.Namespace: PeerReadState]] let readStates: [PeerId: [MessageId.Namespace: PeerReadState]]
let mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] let mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary]
let chatStates: [PeerId: PeerChatState] let channelStates: [PeerId: Int32]
let storeMessages: [StoreMessage] let storeMessages: [StoreMessage]
let topMessageIds: [PeerId: MessageId] let topMessageIds: [PeerId: MessageId]
@ -295,7 +295,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
var notificationSettings: [PeerId: PeerNotificationSettings] = [:] var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:] var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:]
var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:] var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:]
var chatStates: [PeerId: PeerChatState] = [:] var channelStates: [PeerId: Int32] = [:]
var storeMessages: [StoreMessage] = [] var storeMessages: [StoreMessage] = []
var topMessageIds: [PeerId: MessageId] = [:] var topMessageIds: [PeerId: MessageId] = [:]
@ -304,7 +304,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
notificationSettings.merge(parsedRemoteChats.notificationSettings, uniquingKeysWith: { _, updated in updated }) notificationSettings.merge(parsedRemoteChats.notificationSettings, uniquingKeysWith: { _, updated in updated })
readStates.merge(parsedRemoteChats.readStates, uniquingKeysWith: { _, updated in updated }) readStates.merge(parsedRemoteChats.readStates, uniquingKeysWith: { _, updated in updated })
mentionTagSummaries.merge(parsedRemoteChats.mentionTagSummaries, uniquingKeysWith: { _, updated in updated }) mentionTagSummaries.merge(parsedRemoteChats.mentionTagSummaries, uniquingKeysWith: { _, updated in updated })
chatStates.merge(parsedRemoteChats.chatStates, uniquingKeysWith: { _, updated in updated }) channelStates.merge(parsedRemoteChats.channelStates, uniquingKeysWith: { _, updated in updated })
storeMessages.append(contentsOf: parsedRemoteChats.storeMessages) storeMessages.append(contentsOf: parsedRemoteChats.storeMessages)
topMessageIds.merge(parsedRemoteChats.topMessageIds, uniquingKeysWith: { _, updated in updated }) topMessageIds.merge(parsedRemoteChats.topMessageIds, uniquingKeysWith: { _, updated in updated })
@ -314,7 +314,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
notificationSettings.merge(parsedPinnedChats.notificationSettings, uniquingKeysWith: { _, updated in updated }) notificationSettings.merge(parsedPinnedChats.notificationSettings, uniquingKeysWith: { _, updated in updated })
readStates.merge(parsedPinnedChats.readStates, uniquingKeysWith: { _, updated in updated }) readStates.merge(parsedPinnedChats.readStates, uniquingKeysWith: { _, updated in updated })
mentionTagSummaries.merge(parsedPinnedChats.mentionTagSummaries, uniquingKeysWith: { _, updated in updated }) mentionTagSummaries.merge(parsedPinnedChats.mentionTagSummaries, uniquingKeysWith: { _, updated in updated })
chatStates.merge(parsedPinnedChats.chatStates, uniquingKeysWith: { _, updated in updated }) channelStates.merge(parsedPinnedChats.channelStates, uniquingKeysWith: { _, updated in updated })
storeMessages.append(contentsOf: parsedPinnedChats.storeMessages) storeMessages.append(contentsOf: parsedPinnedChats.storeMessages)
topMessageIds.merge(parsedPinnedChats.topMessageIds, uniquingKeysWith: { _, updated in updated }) topMessageIds.merge(parsedPinnedChats.topMessageIds, uniquingKeysWith: { _, updated in updated })
} }
@ -336,7 +336,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
notificationSettings.merge(folderChats.notificationSettings, uniquingKeysWith: { _, updated in updated }) notificationSettings.merge(folderChats.notificationSettings, uniquingKeysWith: { _, updated in updated })
readStates.merge(folderChats.readStates, uniquingKeysWith: { _, updated in updated }) readStates.merge(folderChats.readStates, uniquingKeysWith: { _, updated in updated })
mentionTagSummaries.merge(folderChats.mentionTagSummaries, uniquingKeysWith: { _, updated in updated }) mentionTagSummaries.merge(folderChats.mentionTagSummaries, uniquingKeysWith: { _, updated in updated })
chatStates.merge(folderChats.chatStates, uniquingKeysWith: { _, updated in updated }) channelStates.merge(folderChats.channelStates, uniquingKeysWith: { _, updated in updated })
storeMessages.append(contentsOf: folderChats.storeMessages) storeMessages.append(contentsOf: folderChats.storeMessages)
} }
@ -369,7 +369,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
notificationSettings: notificationSettings, notificationSettings: notificationSettings,
readStates: readStates, readStates: readStates,
mentionTagSummaries: mentionTagSummaries, mentionTagSummaries: mentionTagSummaries,
chatStates: chatStates, channelStates: channelStates,
storeMessages: storeMessages, storeMessages: storeMessages,
topMessageIds: topMessageIds, topMessageIds: topMessageIds,

View File

@ -479,15 +479,11 @@ func fetchChatListHole(postbox: Postbox, network: Network, accountPeerId: PeerId
} }
} }
for (peerId, chatState) in fetchedChats.chatStates { for (peerId, pts) in fetchedChats.channelStates {
if let chatState = chatState as? ChannelState {
if let current = transaction.getPeerChatState(peerId) as? ChannelState { if let current = transaction.getPeerChatState(peerId) as? ChannelState {
transaction.setPeerChatState(peerId, state: current.withUpdatedPts(chatState.pts)) transaction.setPeerChatState(peerId, state: current.withUpdatedPts(pts))
} else { } else {
transaction.setPeerChatState(peerId, state: chatState) transaction.setPeerChatState(peerId, state: ChannelState(pts: pts, invalidatedPts: nil, synchronizedUntilMessageId: nil))
}
} else {
transaction.setPeerChatState(peerId, state: chatState)
} }
} }

View File

@ -2,70 +2,134 @@ import Foundation
import Postbox import Postbox
import SwiftSignalKit import SwiftSignalKit
private final class ManagedSynchronizePeerReadStatesState { private final class SynchronizePeerReadStatesContextImpl {
private var synchronizeDisposables: [PeerId: (PeerReadStateSynchronizationOperation, Disposable)] = [:] private final class Operation {
let operation: PeerReadStateSynchronizationOperation
let disposable: Disposable
func clearDisposables() -> [Disposable] { init(
let disposables = Array(self.synchronizeDisposables.values.map({ $0.1 })) operation: PeerReadStateSynchronizationOperation,
self.synchronizeDisposables.removeAll() disposable: Disposable
return disposables ) {
self.operation = operation
self.disposable = disposable
} }
func update(operations: [PeerId: PeerReadStateSynchronizationOperation]) -> (removed: [Disposable], added: [(PeerId, PeerReadStateSynchronizationOperation, MetaDisposable)]) { deinit {
var removed: [Disposable] = [] self.disposable.dispose()
var added: [(PeerId, PeerReadStateSynchronizationOperation, MetaDisposable)] = []
for (peerId, (operation, disposable)) in self.synchronizeDisposables {
if operations[peerId] != operation {
removed.append(disposable)
self.synchronizeDisposables.removeValue(forKey: peerId)
} }
} }
for (peerId, operation) in operations { private let queue: Queue
if self.synchronizeDisposables[peerId] == nil { private let network: Network
let disposable = MetaDisposable() private let postbox: Postbox
self.synchronizeDisposables[peerId] = (operation, disposable) private let stateManager: AccountStateManager
added.append((peerId, operation, disposable))
private var disposable: Disposable?
private var currentState: [PeerId : PeerReadStateSynchronizationOperation] = [:]
private var activeOperations: [PeerId: Operation] = [:]
private var pendingOperations: [PeerId: PeerReadStateSynchronizationOperation] = [:]
init(queue: Queue, network: Network, postbox: Postbox, stateManager: AccountStateManager) {
self.queue = queue
self.network = network
self.postbox = postbox
self.stateManager = stateManager
self.disposable = (postbox.synchronizePeerReadStatesView()
|> deliverOn(self.queue)).start(next: { [weak self] view in
guard let strongSelf = self else {
return
}
strongSelf.currentState = view.operations
strongSelf.update()
})
}
deinit {
self.disposable?.dispose()
}
func dispose() {
}
private func update() {
let peerIds = Set(self.currentState.keys).union(Set(self.pendingOperations.keys))
for peerId in peerIds {
var maybeOperation: PeerReadStateSynchronizationOperation?
if let operation = self.currentState[peerId] {
maybeOperation = operation
} else if let operation = self.pendingOperations[peerId] {
maybeOperation = operation
self.pendingOperations.removeValue(forKey: peerId)
}
if let operation = maybeOperation {
if let current = self.activeOperations[peerId] {
if current.operation != operation {
self.pendingOperations[peerId] = operation
}
} else {
let operationDisposable = MetaDisposable()
let activeOperation = Operation(
operation: operation,
disposable: operationDisposable
)
self.activeOperations[peerId] = activeOperation
let signal: Signal<Never, NoError>
switch operation {
case .Validate:
signal = synchronizePeerReadState(network: self.network, postbox: self.postbox, stateManager: self.stateManager, peerId: peerId, push: false, validate: true)
|> ignoreValues
case let .Push(_, thenSync):
signal = synchronizePeerReadState(network: self.network, postbox: self.postbox, stateManager: stateManager, peerId: peerId, push: true, validate: thenSync)
|> ignoreValues
}
operationDisposable.set((signal
|> deliverOn(self.queue)).start(completed: { [weak self, weak activeOperation] in
guard let strongSelf = self else {
return
}
if let activeOperation = activeOperation {
if let current = strongSelf.activeOperations[peerId], current === activeOperation {
strongSelf.activeOperations.removeValue(forKey: peerId)
strongSelf.update()
}
}
}))
}
}
}
} }
} }
return (removed, added) private final class SynchronizePeerReadStatesStatesContext {
private let queue: Queue
private let impl: QueueLocalObject<SynchronizePeerReadStatesContextImpl>
init(network: Network, postbox: Postbox, stateManager: AccountStateManager) {
self.queue = Queue()
let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: {
return SynchronizePeerReadStatesContextImpl(queue: queue, network: network, postbox: postbox, stateManager: stateManager)
})
}
func dispose() {
self.impl.with { impl in
impl.dispose()
}
} }
} }
func managedSynchronizePeerReadStates(network: Network, postbox: Postbox, stateManager: AccountStateManager) -> Signal<Void, NoError> { func managedSynchronizePeerReadStates(network: Network, postbox: Postbox, stateManager: AccountStateManager) -> Signal<Void, NoError> {
return Signal { _ in return Signal { _ in
let state = Atomic(value: ManagedSynchronizePeerReadStatesState()) let context = SynchronizePeerReadStatesStatesContext(network: network, postbox: postbox, stateManager: stateManager)
let disposable = postbox.synchronizePeerReadStatesView().start(next: { view in
let (removed, added) = state.with { state -> (removed: [Disposable], added: [(PeerId, PeerReadStateSynchronizationOperation, MetaDisposable)]) in
return state.update(operations: view.operations)
}
for disposable in removed {
disposable.dispose()
}
for (peerId, operation, disposable) in added {
let synchronizeOperation: Signal<Void, NoError>
switch operation {
case .Validate:
synchronizeOperation = synchronizePeerReadState(network: network, postbox: postbox, stateManager: stateManager, peerId: peerId, push: false, validate: true)
case let .Push(_, thenSync):
synchronizeOperation = synchronizePeerReadState(network: network, postbox: postbox, stateManager: stateManager, peerId: peerId, push: true, validate: thenSync)
}
disposable.set(synchronizeOperation.start())
}
})
return ActionDisposable { return ActionDisposable {
disposable.dispose() context.dispose()
for disposable in state.with({ state -> [Disposable] in
state.clearDisposables()
}) {
disposable.dispose()
}
} }
} }
} }

View File

@ -135,7 +135,7 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox,
|> mapToSignal { dialogs -> Signal<Void, NoError> in |> mapToSignal { dialogs -> Signal<Void, NoError> in
var storeMessages: [StoreMessage] = [] var storeMessages: [StoreMessage] = []
var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:] var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:]
var chatStates: [PeerId: PeerChatState] = [:] var channelStates: [PeerId: Int32] = [:]
var notificationSettings: [PeerId: PeerNotificationSettings] = [:] var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
var remoteItemIds: [PinnedItemId] = [] var remoteItemIds: [PinnedItemId] = []
@ -200,7 +200,7 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox,
readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount, markedUnread: apiMarkedUnread) readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount, markedUnread: apiMarkedUnread)
if let apiChannelPts = apiChannelPts { if let apiChannelPts = apiChannelPts {
chatStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: nil, synchronizedUntilMessageId: nil) channelStates[peerId] = apiChannelPts
} }
notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings) notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings)
@ -245,15 +245,11 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox,
transaction.resetIncomingReadStates(readStates) transaction.resetIncomingReadStates(readStates)
for (peerId, chatState) in chatStates { for (peerId, pts) in channelStates {
if let chatState = chatState as? ChannelState {
if let _ = transaction.getPeerChatState(peerId) as? ChannelState { if let _ = transaction.getPeerChatState(peerId) as? ChannelState {
// skip changing state // skip changing state
} else { } else {
transaction.setPeerChatState(peerId, state: chatState) transaction.setPeerChatState(peerId, state: ChannelState(pts: pts, invalidatedPts: nil, synchronizedUntilMessageId: nil))
}
} else {
transaction.setPeerChatState(peerId, state: chatState)
} }
} }

View File

@ -49,8 +49,20 @@ private func canEditMessage(accountPeerId: PeerId, limitsConfiguration: LimitsCo
} }
} else if message.id.peerId.namespace == Namespaces.Peer.SecretChat || message.id.namespace != Namespaces.Message.Cloud { } else if message.id.peerId.namespace == Namespaces.Peer.SecretChat || message.id.namespace != Namespaces.Message.Cloud {
hasEditRights = false hasEditRights = false
} else if let author = message.author, author.id == accountPeerId { } else if let author = message.author, author.id == accountPeerId, let peer = message.peers[message.id.peerId] {
hasEditRights = true hasEditRights = true
if let peer = peer as? TelegramChannel {
switch peer.info {
case .broadcast:
if peer.hasPermission(.editAllMessages) || !message.flags.contains(.Incoming) {
unlimitedInterval = true
}
case .group:
if peer.hasPermission(.pinMessages) {
unlimitedInterval = true
}
}
}
} else if message.author?.id == message.id.peerId, let peer = message.peers[message.id.peerId] { } else if message.author?.id == message.id.peerId, let peer = message.peers[message.id.peerId] {
if let peer = peer as? TelegramChannel { if let peer = peer as? TelegramChannel {
switch peer.info { switch peer.info {