import Foundation #if os(macOS) import PostboxMac import SwiftSignalKitMac import MtProtoKitMac import TelegramApiMac #else import Postbox import SwiftSignalKit import TelegramApi #if BUCK import MtProtoKit #else import MtProtoKitDynamic #endif #endif import SyncCore #if os(macOS) private typealias SignalKitTimer = SwiftSignalKitMac.Timer #else private typealias SignalKitTimer = SwiftSignalKit.Timer #endif private final class ManagedAutoremoveMessageOperationsHelper { var entry: (TimestampBasedMessageAttributesEntry, MetaDisposable)? func update(_ head: TimestampBasedMessageAttributesEntry?) -> (disposeOperations: [Disposable], beginOperations: [(TimestampBasedMessageAttributesEntry, MetaDisposable)]) { var disposeOperations: [Disposable] = [] var beginOperations: [(TimestampBasedMessageAttributesEntry, MetaDisposable)] = [] if self.entry?.0.index != head?.index { if let (_, disposable) = self.entry { self.entry = nil disposeOperations.append(disposable) } if let head = head { let disposable = MetaDisposable() self.entry = (head, disposable) beginOperations.append((head, disposable)) } } return (disposeOperations, beginOperations) } func reset() -> [Disposable] { if let entry = entry { return [entry.1] } else { return [] } } } func managedAutoremoveMessageOperations(postbox: Postbox) -> Signal { return Signal { _ in let helper = Atomic(value: ManagedAutoremoveMessageOperationsHelper()) let disposable = postbox.timestampBasedMessageAttributesView(tag: 0).start(next: { view in let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(TimestampBasedMessageAttributesEntry, MetaDisposable)]) in return helper.update(view.head) } for disposable in disposeOperations { disposable.dispose() } for (entry, disposable) in beginOperations { let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 let signal = Signal.complete() |> suspendAwareDelay(max(0.0, Double(entry.timestamp) - timestamp), queue: Queue.concurrentDefaultQueue()) |> then(postbox.transaction { transaction -> Void in if let message = transaction.getMessage(entry.messageId) { if message.id.peerId.namespace == Namespaces.Peer.SecretChat { deleteMessages(transaction: transaction, mediaBox: postbox.mediaBox, ids: [entry.messageId]) } else { transaction.updateMessage(message.id, update: { currentMessage in var storeForwardInfo: StoreMessageForwardInfo? if let forwardInfo = currentMessage.forwardInfo { storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) } var updatedMedia = currentMessage.media for i in 0 ..< updatedMedia.count { if let _ = updatedMedia[i] as? TelegramMediaImage { updatedMedia[i] = TelegramMediaExpiredContent(data: .image) } else if let _ = updatedMedia[i] as? TelegramMediaFile { updatedMedia[i] = TelegramMediaExpiredContent(data: .file) } } return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: updatedMedia)) }) } } transaction.removeTimestampBasedMessageAttribute(tag: 0, messageId: entry.messageId) }) disposable.set(signal.start()) } }) return ActionDisposable { disposable.dispose() let disposables = helper.with { helper -> [Disposable] in return helper.reset() } for disposable in disposables { disposable.dispose() } } } }