Shared media improvements

This commit is contained in:
Ali
2021-10-26 20:34:09 +04:00
parent 426c2f7e79
commit 7871cd8f43
15 changed files with 858 additions and 79 deletions

View File

@@ -4,10 +4,12 @@ import Postbox
public final class AdMessageAttribute: MessageAttribute {
public let opaqueId: Data
public let startParam: String?
public let messageId: MessageId?
public init(opaqueId: Data, startParam: String?) {
public init(opaqueId: Data, startParam: String?, messageId: MessageId?) {
self.opaqueId = opaqueId
self.startParam = startParam
self.messageId = messageId
}
public init(decoder: PostboxDecoder) {

View File

@@ -8,7 +8,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)))
}
func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, explicitTopMessageId: MessageId?, type: CloudChatClearHistoryType) {
func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, explicitTopMessageId: MessageId?, minTimestamp: Int32?, maxTimestamp: Int32?, type: CloudChatClearHistoryType) {
if type == .scheduledMessages {
var messageIds: [MessageId] = []
transaction.withAllMessages(peerId: peerId, namespace: Namespaces.Message.ScheduledCloud) { message -> Bool in
@@ -24,7 +24,7 @@ func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId,
topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud)
}
if let topMessageId = topMessageId {
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId, type: type))
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, type: type))
}
}
}

View File

@@ -302,7 +302,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
}
let deleteMessages: Signal<Void, NoError>
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, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
deleteMessages = requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: topMessageId.id, justClear: false, minTimestamp: nil, maxTimestamp: nil, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
} else {
deleteMessages = .complete()
}
@@ -326,7 +326,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
} else {
reportSignal = .complete()
}
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId?.id ?? Int32.max - 1, justClear: false, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId?.id ?? Int32.max - 1, justClear: false, minTimestamp: nil, maxTimestamp: nil, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
|> then(reportSignal)
|> then(postbox.transaction { transaction -> Void in
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peer.id, namespaces: .not(Namespaces.Message.allScheduled))
@@ -339,7 +339,7 @@ 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, type: CloudChatClearHistoryType) -> Signal<Void, NoError> {
private func requestClearHistory(postbox: Postbox, network: Network, stateManager: AccountStateManager, inputPeer: Api.InputPeer, maxId: Int32, justClear: Bool, minTimestamp: Int32?, maxTimestamp: Int32?, type: CloudChatClearHistoryType) -> Signal<Void, NoError> {
var flags: Int32 = 0
if justClear {
flags |= 1 << 0
@@ -347,7 +347,16 @@ private func requestClearHistory(postbox: Postbox, network: Network, stateManage
if case .forEveryone = type {
flags |= 1 << 1
}
let signal = network.request(Api.functions.messages.deleteHistory(flags: flags, peer: inputPeer, maxId: maxId, minDate: nil, maxDate: nil))
var updatedMaxId = maxId
if minTimestamp != nil {
flags |= 1 << 2
updatedMaxId = 0
}
if maxTimestamp != nil {
flags |= 1 << 3
updatedMaxId = 0
}
let signal = network.request(Api.functions.messages.deleteHistory(flags: flags, peer: inputPeer, maxId: updatedMaxId, minDate: minTimestamp, maxDate: maxTimestamp))
|> map { result -> Api.messages.AffectedHistory? in
return result
}
@@ -378,17 +387,21 @@ private func requestClearHistory(postbox: Postbox, network: Network, stateManage
private func _internal_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 let inputPeer = apiInputPeer(peer) {
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId.id, justClear: true, type: operation.type)
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId.id, justClear: true, minTimestamp: operation.minTimestamp, maxTimestamp: operation.maxTimestamp, type: operation.type)
} else {
return .complete()
}
} else if peer.id.namespace == Namespaces.Peer.CloudChannel, let inputChannel = apiInputChannel(peer) {
return network.request(Api.functions.channels.deleteHistory(channel: inputChannel, maxId: operation.topMessageId.id))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> mapToSignal { _ -> Signal<Void, NoError> in
if operation.minTimestamp != nil {
return .complete()
} else {
return network.request(Api.functions.channels.deleteHistory(channel: inputChannel, maxId: operation.topMessageId.id))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> mapToSignal { _ -> Signal<Void, NoError> in
return .complete()
}
}
} else {
assertionFailure()

View File

@@ -112,17 +112,23 @@ public extension CloudChatClearHistoryType {
public final class CloudChatClearHistoryOperation: PostboxCoding {
public let peerId: PeerId
public let topMessageId: MessageId
public let minTimestamp: Int32?
public let maxTimestamp: Int32?
public let type: CloudChatClearHistoryType
public init(peerId: PeerId, topMessageId: MessageId, type: CloudChatClearHistoryType) {
public init(peerId: PeerId, topMessageId: MessageId, minTimestamp: Int32?, maxTimestamp: Int32?, type: CloudChatClearHistoryType) {
self.peerId = peerId
self.topMessageId = topMessageId
self.minTimestamp = minTimestamp
self.maxTimestamp = maxTimestamp
self.type = type
}
public init(decoder: PostboxDecoder) {
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.minTimestamp = decoder.decodeOptionalInt32ForKey("minTimestamp")
self.maxTimestamp = decoder.decodeOptionalInt32ForKey("maxTimestamp")
self.type = CloudChatClearHistoryType(rawValue: decoder.decodeInt32ForKey("type", orElse: 0)) ?? .forLocalPeer
}
@@ -131,6 +137,16 @@ public final class CloudChatClearHistoryOperation: PostboxCoding {
encoder.encodeInt64(self.topMessageId.peerId.toInt64(), forKey: "m.p")
encoder.encodeInt32(self.topMessageId.namespace, forKey: "m.n")
encoder.encodeInt32(self.topMessageId.id, forKey: "m.i")
if let minTimestamp = self.minTimestamp {
encoder.encodeInt32(minTimestamp, forKey: "minTimestamp")
} else {
encoder.encodeNil(forKey: "minTimestamp")
}
if let maxTimestamp = self.maxTimestamp {
encoder.encodeInt32(maxTimestamp, forKey: "maxTimestamp")
} else {
encoder.encodeNil(forKey: "maxTimestamp")
}
encoder.encodeInt32(self.type.rawValue, forKey: "type")
}
}

View File

@@ -111,7 +111,7 @@ private class AdMessagesHistoryContextImpl {
func toMessage(peerId: PeerId, transaction: Transaction) -> Message {
var attributes: [MessageAttribute] = []
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId, startParam: self.startParam))
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId, startParam: self.startParam, messageId: self.messageId))
if !self.textEntities.isEmpty {
let attribute = TextEntitiesMessageAttribute(entities: self.textEntities)
attributes.append(attribute)

View File

@@ -87,7 +87,24 @@ func _internal_clearHistory(transaction: Transaction, mediaBox: MediaBox, peerId
let _ = mediaBox.removeCachedResources(Set(resourceIds), force: true).start()
}
}
transaction.clearHistory(peerId, namespaces: namespaces, forEachMedia: { _ in
transaction.clearHistory(peerId, minTimestamp: nil, maxTimestamp: nil, namespaces: namespaces, forEachMedia: { _ in
})
}
func _internal_clearHistoryInRange(transaction: Transaction, mediaBox: MediaBox, peerId: PeerId, minTimestamp: Int32, maxTimestamp: Int32, namespaces: MessageIdNamespaces) {
if peerId.namespace == Namespaces.Peer.SecretChat {
var resourceIds: [MediaResourceId] = []
transaction.withAllMessages(peerId: peerId, { message in
if message.timestamp >= minTimestamp && message.timestamp <= maxTimestamp {
addMessageMediaResourceIdsToRemove(message: message, resourceIds: &resourceIds)
}
return true
})
if !resourceIds.isEmpty {
let _ = mediaBox.removeCachedResources(Set(resourceIds), force: true).start()
}
}
transaction.clearHistory(peerId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: namespaces, forEachMedia: { _ in
})
}

View File

@@ -96,10 +96,43 @@ func deleteMessagesInteractively(transaction: Transaction, stateManager: Account
}
}
func _internal_clearHistoryInRangeInteractively(postbox: Postbox, peerId: PeerId, minTimestamp: Int32, maxTimestamp: Int32, type: InteractiveHistoryClearingType) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel {
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, type: CloudChatClearHistoryType(type))
if type == .scheduledMessages {
} else {
_internal_clearHistoryInRange(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: .not(Namespaces.Message.allScheduled))
}
} else if peerId.namespace == Namespaces.Peer.SecretChat {
/*_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId, namespaces: .all)
if let state = transaction.getPeerChatState(peerId) as? SecretChatState {
var layer: SecretChatLayer?
switch state.embeddedState {
case .terminated, .handshake:
break
case .basicLayer:
layer = .layer8
case let .sequenceBasedLayer(sequenceState):
layer = sequenceState.layerNegotiationState.activeLayer.secretChatLayer
}
if let layer = layer {
let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: SecretChatOutgoingOperationContents.clearHistory(layer: layer, actionGloballyUniqueId: Int64.random(in: Int64.min ... Int64.max)), state: state)
if updatedState != state {
transaction.setPeerChatState(peerId, state: updatedState)
}
}
}*/
}
}
}
func _internal_clearHistoryInteractively(postbox: Postbox, peerId: PeerId, type: InteractiveHistoryClearingType) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel {
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil, type: CloudChatClearHistoryType(type))
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil, minTimestamp: nil, maxTimestamp: nil, type: CloudChatClearHistoryType(type))
if type == .scheduledMessages {
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId, namespaces: .just(Namespaces.Message.allScheduled))
} else {
@@ -110,7 +143,7 @@ func _internal_clearHistoryInteractively(postbox: Postbox, peerId: PeerId, type:
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId, namespaces: .not(Namespaces.Message.allScheduled))
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), type: CloudChatClearHistoryType(type))
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: migrationReference.maxMessageId.peerId, explicitTopMessageId: MessageId(peerId: migrationReference.maxMessageId.peerId, namespace: migrationReference.maxMessageId.namespace, id: migrationReference.maxMessageId.id + 1), minTimestamp: nil, maxTimestamp: nil, type: CloudChatClearHistoryType(type))
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: migrationReference.maxMessageId.peerId, namespaces: .all)
}
if let topIndex = topIndex {

View File

@@ -581,6 +581,24 @@ public final class SparseMessageCalendar {
self.loadMore()
}
func removeMessagesInRange(minTimestamp: Int32, maxTimestamp: Int32, type: InteractiveHistoryClearingType, completion: @escaping () -> Void) -> Disposable {
var removeKeys: [Int32] = []
for (id, message) in self.state.messagesByDay {
if message.timestamp >= minTimestamp && message.timestamp <= maxTimestamp {
removeKeys.append(id)
}
}
for id in removeKeys {
self.state.messagesByDay.removeValue(forKey: id)
}
self.statePromise.set(.single(self.state))
return _internal_clearHistoryInRangeInteractively(postbox: self.account.postbox, peerId: self.peerId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, type: type).start(completed: {
completion()
})
}
private func loadMore() {
guard let nextRequestOffset = self.state.nextRequestOffset else {
return
@@ -754,4 +772,14 @@ public final class SparseMessageCalendar {
impl.maybeLoadMore()
}
}
public func removeMessagesInRange(minTimestamp: Int32, maxTimestamp: Int32, type: InteractiveHistoryClearingType, completion: @escaping () -> Void) -> Disposable {
let disposable = MetaDisposable()
self.impl.with { impl in
disposable.set(impl.removeMessagesInRange(minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, type: type, completion: completion))
}
return disposable
}
}