Fix clear history

This commit is contained in:
Peter 2019-03-20 21:15:16 +04:00
parent 6696d6045c
commit 2a05628f97
8 changed files with 59 additions and 25 deletions

View File

@ -90,6 +90,7 @@ enum AccountStateMutationOperation {
case UpdateCall(Api.PhoneCall) case UpdateCall(Api.PhoneCall)
case UpdateLangPack(String, Api.LangPackDifference?) case UpdateLangPack(String, Api.LangPackDifference?)
case UpdateMinAvailableMessage(MessageId) case UpdateMinAvailableMessage(MessageId)
case UpdatePeerInclusionMinTimestamp(PeerId, Int32)
} }
struct AccountMutableState { struct AccountMutableState {
@ -277,6 +278,10 @@ struct AccountMutableState {
self.addOperation(.UpdateMinAvailableMessage(id)) self.addOperation(.UpdateMinAvailableMessage(id))
} }
mutating func updatePeerInclusionMinTimestamp(peerId: PeerId, timestamp: Int32) {
self.addOperation(.UpdatePeerInclusionMinTimestamp(peerId, timestamp))
}
mutating func mergeUsers(_ users: [Api.User]) { mutating func mergeUsers(_ users: [Api.User]) {
self.addOperation(.MergeApiUsers(users)) self.addOperation(.MergeApiUsers(users))
@ -347,7 +352,7 @@ struct AccountMutableState {
mutating func addOperation(_ operation: AccountStateMutationOperation) { mutating func addOperation(_ operation: AccountStateMutationOperation) {
switch operation { switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact: case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerInclusionMinTimestamp, .UpdatePeerChatUnreadMark, .UpdateIsContact:
break break
case let .AddMessages(messages, location): case let .AddMessages(messages, location):
for message in messages { for message in messages {

View File

@ -829,6 +829,13 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
} }
} }
updatedState.editMessage(messageId, message: message) updatedState.editMessage(messageId, message: message)
for media in message.media {
if let media = media as? TelegramMediaAction {
if case .historyCleared = media.action {
updatedState.readInbox(messageId)
}
}
}
} }
case let .updateNewChannelMessage(apiMessage, pts, ptsCount): case let .updateNewChannelMessage(apiMessage, pts, ptsCount):
if let message = StoreMessage(apiMessage: apiMessage) { if let message = StoreMessage(apiMessage: apiMessage) {
@ -1885,7 +1892,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
var currentAddMessages: OptimizeAddMessagesState? var currentAddMessages: OptimizeAddMessagesState?
for operation in operations { for operation in operations {
switch operation { switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact: case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerInclusionMinTimestamp, .UpdateIsContact:
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
} }
@ -2104,6 +2111,14 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
deleteMessages(transaction: transaction, mediaBox: mediaBox, ids: ids) deleteMessages(transaction: transaction, mediaBox: mediaBox, ids: ids)
case let .UpdateMinAvailableMessage(id): case let .UpdateMinAvailableMessage(id):
transaction.deleteMessagesInRange(peerId: id.peerId, namespace: id.namespace, minId: 1, maxId: id.id) transaction.deleteMessagesInRange(peerId: id.peerId, namespace: id.namespace, minId: 1, maxId: id.id)
case let .UpdatePeerInclusionMinTimestamp(peerId, timestamp):
let inclusion = transaction.getPeerChatListInclusion(peerId)
switch inclusion {
case .ifHasMessages, .ifHasMessagesOrOneOf:
transaction.updatePeerChatListInclusion(peerId, inclusion: inclusion.withSetIfHasMessagesOrMaxMinTimestamp(timestamp))
default:
break
}
case let .EditMessage(id, message): case let .EditMessage(id, message):
transaction.updateMessage(id, update: { previousMessage in transaction.updateMessage(id, update: { previousMessage in
var updatedFlags = message.flags var updatedFlags = message.flags

View File

@ -86,15 +86,18 @@ final class CloudChatRemoveChatOperation: PostboxCoding {
final class CloudChatClearHistoryOperation: PostboxCoding { final class CloudChatClearHistoryOperation: PostboxCoding {
let peerId: PeerId let peerId: PeerId
let topMessageId: MessageId let topMessageId: MessageId
let type: InteractiveMessagesDeletionType
init(peerId: PeerId, topMessageId: MessageId) { init(peerId: PeerId, topMessageId: MessageId, type: InteractiveMessagesDeletionType) {
self.peerId = peerId self.peerId = peerId
self.topMessageId = topMessageId self.topMessageId = topMessageId
self.type = type
} }
init(decoder: PostboxDecoder) { init(decoder: PostboxDecoder) {
self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0))
self.topMessageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0)) self.topMessageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0))
self.type = InteractiveMessagesDeletionType(rawValue: decoder.decodeInt32ForKey("type", orElse: 0)) ?? .forLocalPeer
} }
func encode(_ encoder: PostboxEncoder) { func encode(_ encoder: PostboxEncoder) {
@ -102,6 +105,7 @@ final class CloudChatClearHistoryOperation: PostboxCoding {
encoder.encodeInt64(self.topMessageId.peerId.toInt64(), forKey: "m.p") encoder.encodeInt64(self.topMessageId.peerId.toInt64(), forKey: "m.p")
encoder.encodeInt32(self.topMessageId.namespace, forKey: "m.n") encoder.encodeInt32(self.topMessageId.namespace, forKey: "m.n")
encoder.encodeInt32(self.topMessageId.id, forKey: "m.i") encoder.encodeInt32(self.topMessageId.id, forKey: "m.i")
encoder.encodeInt32(self.type.rawValue, forKey: "type")
} }
} }
@ -113,7 +117,7 @@ func cloudChatAddRemoveChatOperation(transaction: Transaction, peerId: PeerId, r
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatRemoveChatOperation(peerId: peerId, reportChatSpam: reportChatSpam, deleteGloballyIfPossible: deleteGloballyIfPossible, topMessageId: transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud))) transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatRemoveChatOperation(peerId: peerId, reportChatSpam: reportChatSpam, deleteGloballyIfPossible: deleteGloballyIfPossible, topMessageId: transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud)))
} }
func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, explicitTopMessageId: MessageId?) { func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, explicitTopMessageId: MessageId?, type: InteractiveMessagesDeletionType) {
let topMessageId: MessageId? let topMessageId: MessageId?
if let explicitTopMessageId = explicitTopMessageId { if let explicitTopMessageId = explicitTopMessageId {
topMessageId = explicitTopMessageId topMessageId = explicitTopMessageId
@ -121,6 +125,6 @@ func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId,
topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud) topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud)
} }
if let topMessageId = topMessageId { if let topMessageId = topMessageId {
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId)) transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId, type: type))
} }
} }

View File

@ -9,9 +9,9 @@ import Foundation
import MtProtoKitDynamic import MtProtoKitDynamic
#endif #endif
public enum InteractiveMessagesDeletionType { public enum InteractiveMessagesDeletionType: Int32 {
case forLocalPeer case forLocalPeer = 0
case forEveryone case forEveryone = 1
} }
public func deleteMessagesInteractively(postbox: Postbox, messageIds: [MessageId], type: InteractiveMessagesDeletionType) -> Signal<Void, NoError> { public func deleteMessagesInteractively(postbox: Postbox, messageIds: [MessageId], type: InteractiveMessagesDeletionType) -> Signal<Void, NoError> {
@ -57,21 +57,25 @@ public func deleteMessagesInteractively(postbox: Postbox, messageIds: [MessageId
} }
} }
public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId) -> Signal<Void, NoError> { public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId, type: InteractiveMessagesDeletionType) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in return postbox.transaction { transaction -> Void in
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel { if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel {
var topTimestamp: Int32? cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil, type: type)
if let topIndex = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) { var topIndex: MessageIndex?
topTimestamp = topIndex.timestamp if let topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud), let topMessage = transaction.getMessage(topMessageId) {
topIndex = MessageIndex(topMessage)
} }
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil)
clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId) clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId)
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference { if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference {
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: migrationReference.maxMessageId.peerId, explicitTopMessageId: MessageId(peerId: migrationReference.maxMessageId.peerId, namespace: migrationReference.maxMessageId.namespace, id: migrationReference.maxMessageId.id + 1)) cloudChatAddClearHistoryOperation(transaction: transaction, peerId: migrationReference.maxMessageId.peerId, explicitTopMessageId: MessageId(peerId: migrationReference.maxMessageId.peerId, namespace: migrationReference.maxMessageId.namespace, id: migrationReference.maxMessageId.id + 1), type: type)
clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: migrationReference.maxMessageId.peerId) clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: migrationReference.maxMessageId.peerId)
} }
if let topTimestamp = topTimestamp { if let topIndex = topIndex {
updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: topTimestamp) if peerId.namespace == Namespaces.Peer.CloudUser {
let _ = transaction.addMessages([StoreMessage(id: topIndex.id, globallyUniqueId: nil, groupingKey: nil, timestamp: topIndex.timestamp, flags: StoreMessageFlags(), tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: nil, text: "", attributes: [], media: [TelegramMediaAction(action: .historyCleared)])], location: .Random)
} else {
updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: topIndex.timestamp)
}
} }
} else if peerId.namespace == Namespaces.Peer.SecretChat { } else if peerId.namespace == Namespaces.Peer.SecretChat {
clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId) clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId)

View File

@ -6,6 +6,8 @@ import Foundation
#endif #endif
public struct LimitsConfiguration: Equatable, PreferencesEntry { public struct LimitsConfiguration: Equatable, PreferencesEntry {
public static let timeIntervalForever: Int32 = 0x7fffffff
public var maxGroupMemberCount: Int32 public var maxGroupMemberCount: Int32
public var maxSupergroupMemberCount: Int32 public var maxSupergroupMemberCount: Int32
public var maxMessageForwardBatchSize: Int32 public var maxMessageForwardBatchSize: Int32

View File

@ -261,7 +261,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
} }
let deleteMessages: Signal<Void, NoError> let deleteMessages: Signal<Void, NoError>
if let inputPeer = apiInputPeer(peer), let topMessageId = operation.topMessageId ?? transaction.getTopPeerMessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud) { if let inputPeer = apiInputPeer(peer), let topMessageId = operation.topMessageId ?? transaction.getTopPeerMessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud) {
deleteMessages = requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: topMessageId.id, justClear: false) deleteMessages = requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: topMessageId.id, justClear: false, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
} else { } else {
deleteMessages = .complete() deleteMessages = .complete()
} }
@ -285,7 +285,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
} else { } else {
reportSignal = .complete() reportSignal = .complete()
} }
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId?.id ?? Int32.max - 1, justClear: false) return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId?.id ?? Int32.max - 1, justClear: false, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
|> then(reportSignal) |> then(reportSignal)
|> then(postbox.transaction { transaction -> Void in |> then(postbox.transaction { transaction -> Void in
clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peer.id) clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peer.id)
@ -298,8 +298,15 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
} }
} }
private func requestClearHistory(postbox: Postbox, network: Network, stateManager: AccountStateManager, inputPeer: Api.InputPeer, maxId: Int32, justClear: Bool) -> Signal<Void, NoError> { private func requestClearHistory(postbox: Postbox, network: Network, stateManager: AccountStateManager, inputPeer: Api.InputPeer, maxId: Int32, justClear: Bool, type: InteractiveMessagesDeletionType) -> Signal<Void, NoError> {
let signal = network.request(Api.functions.messages.deleteHistory(flags: justClear ? 1 : 0, peer: inputPeer, maxId: maxId)) var flags: Int32 = 0
if justClear {
flags |= 1 << 0
}
if case .forEveryone = type {
flags |= 1 << 1
}
let signal = network.request(Api.functions.messages.deleteHistory(flags: flags, peer: inputPeer, maxId: maxId))
|> map { result -> Api.messages.AffectedHistory? in |> map { result -> Api.messages.AffectedHistory? in
return result return result
} }
@ -330,7 +337,7 @@ private func requestClearHistory(postbox: Postbox, network: Network, stateManage
private func clearHistory(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, peer: Peer, operation: CloudChatClearHistoryOperation) -> Signal<Void, NoError> { private func clearHistory(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, peer: Peer, operation: CloudChatClearHistoryOperation) -> Signal<Void, NoError> {
if peer.id.namespace == Namespaces.Peer.CloudGroup || peer.id.namespace == Namespaces.Peer.CloudUser { if peer.id.namespace == Namespaces.Peer.CloudGroup || peer.id.namespace == Namespaces.Peer.CloudUser {
if let inputPeer = apiInputPeer(peer) { if let inputPeer = apiInputPeer(peer) {
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId.id, justClear: true) return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId.id, justClear: true, type: operation.type)
} else { } else {
return .complete() return .complete()
} }

View File

@ -559,9 +559,6 @@ extension StoreMessage {
case .messageEmpty: case .messageEmpty:
return nil return nil
case let .messageService(flags, id, fromId, toId, replyToMsgId, date, action): case let .messageService(flags, id, fromId, toId, replyToMsgId, date, action):
if case .messageActionHistoryClear = action {
return nil
}
let peerId: PeerId let peerId: PeerId
var authorId: PeerId? var authorId: PeerId?
switch toId { switch toId {

View File

@ -240,7 +240,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
return TelegramMediaAction(action: .channelMigratedFromGroup(title: title, groupId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId))) return TelegramMediaAction(action: .channelMigratedFromGroup(title: title, groupId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)))
case let .messageActionChatAddUser(users): case let .messageActionChatAddUser(users):
return TelegramMediaAction(action: .addedMembers(peerIds: users.map({ PeerId(namespace: Namespaces.Peer.CloudUser, id: $0) }))) return TelegramMediaAction(action: .addedMembers(peerIds: users.map({ PeerId(namespace: Namespaces.Peer.CloudUser, id: $0) })))
case let .messageActionChatCreate(title, userIds): case let .messageActionChatCreate(title, _):
return TelegramMediaAction(action: .groupCreated(title: title)) return TelegramMediaAction(action: .groupCreated(title: title))
case .messageActionChatDeletePhoto: case .messageActionChatDeletePhoto:
return TelegramMediaAction(action: .photoUpdated(image: nil)) return TelegramMediaAction(action: .photoUpdated(image: nil))