From 4c9728b4fe5834826efe5431178a2c635da7d196 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 24 Mar 2021 12:37:33 +1100 Subject: [PATCH] Update other APIs for V2 open groups --- Session.xcodeproj/project.pbxproj | 16 ++- .../Database/Storage+OpenGroups.swift | 72 +++++++++--- .../Open Groups/{ => V1}/OpenGroup.swift | 0 .../{ => V1}/OpenGroupManager.swift | 0 .../Open Groups/V2/OpenGroupAPIV2.swift | 3 +- .../Open Groups/V2/OpenGroupManagerV2.swift | 74 ++++++++++++ .../Open Groups/V2/OpenGroupV2.swift | 32 ++++++ .../Pollers/OpenGroupPollerV2.swift | 105 ++++++++++++++++++ SessionMessagingKit/Storage.swift | 7 +- 9 files changed, 290 insertions(+), 19 deletions(-) rename SessionMessagingKit/Open Groups/{ => V1}/OpenGroup.swift (100%) rename SessionMessagingKit/Open Groups/{ => V1}/OpenGroupManager.swift (100%) create mode 100644 SessionMessagingKit/Open Groups/V2/OpenGroupManagerV2.swift create mode 100644 SessionMessagingKit/Open Groups/V2/OpenGroupV2.swift create mode 100644 SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 71e60e900..e9b5ae82d 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -780,6 +780,9 @@ C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */; }; C3DA9C0725AE7396008F7C7E /* ConfigurationMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DA9C0625AE7396008F7C7E /* ConfigurationMessage.swift */; }; C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; }; + C3DB6695260AC923001EFC55 /* OpenGroupV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB6694260AC923001EFC55 /* OpenGroupV2.swift */; }; + C3DB66AC260ACA42001EFC55 /* OpenGroupManagerV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66AB260ACA42001EFC55 /* OpenGroupManagerV2.swift */; }; + C3DB66C3260ACCE6001EFC55 /* OpenGroupPollerV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66C2260ACCE6001EFC55 /* OpenGroupPollerV2.swift */; }; C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; }; C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECBF7A257056B700EA7FCE /* Threading.swift */; }; @@ -1777,6 +1780,9 @@ C3D9E43025676D3D0040E4F3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; C3DA9C0625AE7396008F7C7E /* ConfigurationMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationMessage.swift; sourceTree = ""; }; C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = ""; }; + C3DB6694260AC923001EFC55 /* OpenGroupV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupV2.swift; sourceTree = ""; }; + C3DB66AB260ACA42001EFC55 /* OpenGroupManagerV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupManagerV2.swift; sourceTree = ""; }; + C3DB66C2260ACCE6001EFC55 /* OpenGroupPollerV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupPollerV2.swift; sourceTree = ""; }; C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = ""; }; C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = ""; }; C3E7134E251C867C009649BB /* Sodium+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Conversion.swift"; sourceTree = ""; }; @@ -2502,7 +2508,9 @@ C3227FF4260AAD58006EA627 /* V2 */ = { isa = PBXGroup; children = ( + C3DB6694260AC923001EFC55 /* OpenGroupV2.swift */, B88FA7B726045D100049422F /* OpenGroupAPIV2.swift */, + C3DB66AB260ACA42001EFC55 /* OpenGroupManagerV2.swift */, C3227FF5260AAD66006EA627 /* OpenGroupMessageV2.swift */, ); path = V2; @@ -2511,8 +2519,10 @@ C3228005260AAD7E006EA627 /* V1 */ = { isa = PBXGroup; children = ( + C3A721372558BDFA0043A11F /* OpenGroup.swift */, C3A721352558BDF90043A11F /* OpenGroupAPI.swift */, C3A721362558BDFA0043A11F /* OpenGroupInfo.swift */, + C3AAFFCB25AE92150089E6DD /* OpenGroupManager.swift */, C3A721342558BDF90043A11F /* OpenGroupMessage.swift */, C3A7229B2558E4310043A11F /* OpenGroupMessage+Conversion.swift */, ); @@ -2567,6 +2577,7 @@ children = ( C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */, C33FDA8C255A57FD00E217F9 /* OpenGroupPoller.swift */, + C3DB66C2260ACCE6001EFC55 /* OpenGroupPollerV2.swift */, C33FDB3A255A580B00E217F9 /* Poller.swift */, ); path = Pollers; @@ -3184,8 +3195,6 @@ children = ( C3228005260AAD7E006EA627 /* V1 */, C3227FF4260AAD58006EA627 /* V2 */, - C3A721372558BDFA0043A11F /* OpenGroup.swift */, - C3AAFFCB25AE92150089E6DD /* OpenGroupManager.swift */, ); path = "Open Groups"; sourceTree = ""; @@ -4772,6 +4781,7 @@ C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */, C32C5E75256DE020003C73A2 /* YapDatabaseTransaction+OWS.m in Sources */, C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */, + C3DB66AC260ACA42001EFC55 /* OpenGroupManagerV2.swift in Sources */, B8F5F61B25EDE4BF003BF8D4 /* DataExtractionNotificationInfoMessage.swift in Sources */, C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */, B8856D34256F1192001CE70E /* Environment.m in Sources */, @@ -4836,6 +4846,7 @@ C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */, C38D5E8D2575011E00B6A65C /* MessageSender+ClosedGroups.swift in Sources */, C32C5B1C256DC19D003C73A2 /* TSQuotedMessage.m in Sources */, + C3DB6695260AC923001EFC55 /* OpenGroupV2.swift in Sources */, C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */, C352A30925574D8500338F3E /* Message+Destination.swift in Sources */, C300A5E72554B07300555489 /* ExpirationTimerUpdate.swift in Sources */, @@ -4844,6 +4855,7 @@ C32C598A256D0664003C73A2 /* SNProtoEnvelope+Conversion.swift in Sources */, C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */, B8856D11256F112A001CE70E /* OWSAudioSession.swift in Sources */, + C3DB66C3260ACCE6001EFC55 /* OpenGroupPollerV2.swift in Sources */, C3C2A75F2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift in Sources */, C32C5FBB256E0206003C73A2 /* OWSBackgroundTask.m in Sources */, B8856CA8256F0F42001CE70E /* OWSBackupFragment.m in Sources */, diff --git a/SessionMessagingKit/Database/Storage+OpenGroups.swift b/SessionMessagingKit/Database/Storage+OpenGroups.swift index c8f351210..f75a090a4 100644 --- a/SessionMessagingKit/Database/Storage+OpenGroups.swift +++ b/SessionMessagingKit/Database/Storage+OpenGroups.swift @@ -3,33 +3,33 @@ extension Storage { // MARK: - Open Groups - private static let openGroupCollection = "LokiPublicChatCollection" + private static let openGroupCollection = "SNOpenGroupCollection" - @objc public func getAllUserOpenGroups() -> [String:OpenGroup] { - var result = [String:OpenGroup]() + @objc public func getAllV2OpenGroups() -> [String:OpenGroupV2] { + var result = [String:OpenGroupV2]() Storage.read { transaction in transaction.enumerateKeysAndObjects(inCollection: Storage.openGroupCollection) { threadID, object, _ in - guard let openGroup = object as? OpenGroup else { return } + guard let openGroup = object as? OpenGroupV2 else { return } result[threadID] = openGroup } } return result } - @objc(getOpenGroupForThreadID:) - public func getOpenGroup(for threadID: String) -> OpenGroup? { - var result: OpenGroup? + @objc(getV2OpenGroupForThreadID:) + public func getV2OpenGroup(for threadID: String) -> OpenGroupV2? { + var result: OpenGroupV2? Storage.read { transaction in - result = transaction.object(forKey: threadID, inCollection: Storage.openGroupCollection) as? OpenGroup + result = transaction.object(forKey: threadID, inCollection: Storage.openGroupCollection) as? OpenGroupV2 } return result } - public func getThreadID(for openGroupID: String) -> String? { + public func v2GetThreadID(for v2OpenGroupID: String) -> String? { var result: String? Storage.read { transaction in transaction.enumerateKeysAndObjects(inCollection: Storage.openGroupCollection, using: { threadID, object, stop in - guard let openGroup = object as? OpenGroup, "\(openGroup.server).\(openGroup.channel)" == openGroupID else { return } + guard let openGroup = object as? OpenGroupV2, openGroup.id == v2OpenGroupID else { return } result = threadID stop.pointee = true }) @@ -37,13 +37,13 @@ extension Storage { return result } - @objc(setOpenGroup:forThreadWithID:using:) - public func setOpenGroup(_ openGroup: OpenGroup, for threadID: String, using transaction: Any) { + @objc(setV2OpenGroup:forThreadWithID:using:) + public func setV2OpenGroup(_ openGroup: OpenGroupV2, for threadID: String, using transaction: Any) { (transaction as! YapDatabaseReadWriteTransaction).setObject(openGroup, forKey: threadID, inCollection: Storage.openGroupCollection) } - @objc(removeOpenGroupForThreadID:using:) - public func removeOpenGroup(for threadID: String, using transaction: Any) { + @objc(removeV2OpenGroupForThreadID:using:) + public func removeV2OpenGroup(for threadID: String, using transaction: Any) { (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: threadID, inCollection: Storage.openGroupCollection) } @@ -230,6 +230,50 @@ extension Storage { // MARK: - Deprecated + private static let oldOpenGroupCollection = "LokiPublicChatCollection" + + @objc public func getAllUserOpenGroups() -> [String:OpenGroup] { + var result = [String:OpenGroup]() + Storage.read { transaction in + transaction.enumerateKeysAndObjects(inCollection: Storage.oldOpenGroupCollection) { threadID, object, _ in + guard let openGroup = object as? OpenGroup else { return } + result[threadID] = openGroup + } + } + return result + } + + @objc(getOpenGroupForThreadID:) + public func getOpenGroup(for threadID: String) -> OpenGroup? { + var result: OpenGroup? + Storage.read { transaction in + result = transaction.object(forKey: threadID, inCollection: Storage.oldOpenGroupCollection) as? OpenGroup + } + return result + } + + public func getThreadID(for openGroupID: String) -> String? { + var result: String? + Storage.read { transaction in + transaction.enumerateKeysAndObjects(inCollection: Storage.oldOpenGroupCollection, using: { threadID, object, stop in + guard let openGroup = object as? OpenGroup, "\(openGroup.server).\(openGroup.channel)" == openGroupID else { return } + result = threadID + stop.pointee = true + }) + } + return result + } + + @objc(setOpenGroup:forThreadWithID:using:) + public func setOpenGroup(_ openGroup: OpenGroup, for threadID: String, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).setObject(openGroup, forKey: threadID, inCollection: Storage.oldOpenGroupCollection) + } + + @objc(removeOpenGroupForThreadID:using:) + public func removeOpenGroup(for threadID: String, using transaction: Any) { + (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: threadID, inCollection: Storage.oldOpenGroupCollection) + } + private static func getAuthTokenCollection(for server: String) -> String { return (server == FileServerAPI.server) ? "LokiStorageAuthTokenCollection" : "LokiGroupChatAuthTokenCollection" } diff --git a/SessionMessagingKit/Open Groups/OpenGroup.swift b/SessionMessagingKit/Open Groups/V1/OpenGroup.swift similarity index 100% rename from SessionMessagingKit/Open Groups/OpenGroup.swift rename to SessionMessagingKit/Open Groups/V1/OpenGroup.swift diff --git a/SessionMessagingKit/Open Groups/OpenGroupManager.swift b/SessionMessagingKit/Open Groups/V1/OpenGroupManager.swift similarity index 100% rename from SessionMessagingKit/Open Groups/OpenGroupManager.swift rename to SessionMessagingKit/Open Groups/V1/OpenGroupManager.swift diff --git a/SessionMessagingKit/Open Groups/V2/OpenGroupAPIV2.swift b/SessionMessagingKit/Open Groups/V2/OpenGroupAPIV2.swift index a0b7a0fe3..551d52a3c 100644 --- a/SessionMessagingKit/Open Groups/V2/OpenGroupAPIV2.swift +++ b/SessionMessagingKit/Open Groups/V2/OpenGroupAPIV2.swift @@ -2,6 +2,7 @@ import PromiseKit import SessionSnodeKit // TODO: Message signature validation +// TODO: Keeping track of moderators public enum OpenGroupAPIV2 { @@ -186,7 +187,7 @@ public enum OpenGroupAPIV2 { } return message } - let serverID = messages.map { $0.serverID! }.max() ?? 0 // Safe because messages with a nil serverID are filtered out above + let serverID = messages.map { $0.serverID! }.max() ?? 0 // Safe because messages with a nil serverID are filtered out let lastMessageServerID = storage.getLastMessageServerID(for: room, on: server) ?? 0 if serverID > lastMessageServerID { let (promise, seal) = Promise<[OpenGroupMessageV2]>.pending() diff --git a/SessionMessagingKit/Open Groups/V2/OpenGroupManagerV2.swift b/SessionMessagingKit/Open Groups/V2/OpenGroupManagerV2.swift new file mode 100644 index 000000000..576cfcbd0 --- /dev/null +++ b/SessionMessagingKit/Open Groups/V2/OpenGroupManagerV2.swift @@ -0,0 +1,74 @@ +import PromiseKit + +@objc(SNOpenGroupManagerV2) +public final class OpenGroupManagerV2 : NSObject { + private var pollers: [String:OpenGroupPollerV2] = [:] + private var isPolling = false + + // MARK: Initialization + @objc public static let shared = OpenGroupManagerV2() + + private override init() { } + + // MARK: Polling + @objc public func startPolling() { + guard !isPolling else { return } + isPolling = true + let openGroups = Storage.shared.getAllV2OpenGroups() + for (_, openGroup) in openGroups { + if let poller = pollers[openGroup.id] { poller.stop() } // Should never occur + let poller = OpenGroupPollerV2(for: openGroup) + poller.startIfNeeded() + pollers[openGroup.id] = poller + } + } + + @objc public func stopPolling() { + pollers.forEach { (_, openGroupPoller) in openGroupPoller.stop() } + pollers.removeAll() + } + + // MARK: Adding & Removing + public func add(room: String, server: String, name: String, using transaction: Any) -> Promise { + let storage = Storage.shared + storage.removeLastMessageServerID(for: room, on: server, using: transaction) + storage.removeLastDeletionServerID(for: room, on: server, using: transaction) + let openGroup = OpenGroupV2(server: server, room: room, name: name) + let groupID = LKGroupUtilities.getEncodedOpenGroupIDAsData(openGroup.id) + let model = TSGroupModel(title: openGroup.name, memberIds: [ getUserHexEncodedPublicKey() ], image: nil, groupId: groupID, groupType: .openGroup, adminIds: []) + storage.write(with: { transaction in + let thread = TSGroupThread.getOrCreateThread(with: model, transaction: transaction as! YapDatabaseReadWriteTransaction) + storage.setV2OpenGroup(openGroup, for: thread.uniqueId!, using: transaction) + }, completion: { + if let poller = OpenGroupManagerV2.shared.pollers[openGroup.id] { + poller.stop() + OpenGroupManagerV2.shared.pollers[openGroup.id] = nil + } + let poller = OpenGroupPollerV2(for: openGroup) + poller.startIfNeeded() + OpenGroupManager.shared.pollers[openGroup.id] = poller + }) + } + + public func delete(_ openGroup: OpenGroupV2, associatedWith thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { + if let poller = pollers[openGroup.id] { + poller.stop() + pollers[openGroup.id] = nil + } + var messageIDs: Set = [] + var messageTimestamps: Set = [] + thread.enumerateInteractions(with: transaction) { interaction, _ in + messageIDs.insert(interaction.uniqueId!) + messageTimestamps.insert(interaction.timestamp) + } + SNMessagingKitConfiguration.shared.storage.updateMessageIDCollectionByPruningMessagesWithIDs(messageIDs, using: transaction) + Storage.shared.removeReceivedMessageTimestamps(messageTimestamps, using: transaction) + Storage.shared.removeLastMessageServerID(for: openGroup.room, on: openGroup.server, using: transaction) + Storage.shared.removeLastDeletionServerID(for: openGroup.room, on: openGroup.server, using: transaction) + let _ = OpenGroupAPIV2.deleteAuthToken(for: openGroup.room, on: openGroup.server) + Storage.shared.removeOpenGroupPublicKey(for: openGroup.server, using: transaction) + thread.removeAllThreadInteractions(with: transaction) + thread.remove(with: transaction) + Storage.shared.removeV2OpenGroup(for: thread.uniqueId!, using: transaction) + } +} diff --git a/SessionMessagingKit/Open Groups/V2/OpenGroupV2.swift b/SessionMessagingKit/Open Groups/V2/OpenGroupV2.swift new file mode 100644 index 000000000..b9ef33b66 --- /dev/null +++ b/SessionMessagingKit/Open Groups/V2/OpenGroupV2.swift @@ -0,0 +1,32 @@ + +@objc(SNOpenGroupV2) +public final class OpenGroupV2 : NSObject, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility + public let server: String + public let room: String + public let id: String + public let name: String + + public init(server: String, room: String, name: String) { + self.server = server.lowercased() + self.room = room + self.id = "\(server).\(room)" + self.name = name + } + + // MARK: Coding + public init?(coder: NSCoder) { + server = coder.decodeObject(forKey: "server") as! String + room = coder.decodeObject(forKey: "room") as! String + self.id = "\(server).\(room)" + name = coder.decodeObject(forKey: "name") as! String + super.init() + } + + public func encode(with coder: NSCoder) { + coder.encode(server, forKey: "server") + coder.encode(room, forKey: "room") + coder.encode(name, forKey: "name") + } + + override public var description: String { "\(name) (\(server) → \(room)" } +} diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift new file mode 100644 index 000000000..cc9e03355 --- /dev/null +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift @@ -0,0 +1,105 @@ +import PromiseKit + +@objc(SNOpenGroupPollerV2) +public final class OpenGroupPollerV2 : NSObject { + private let openGroup: OpenGroupV2 + private var pollForNewMessagesTimer: Timer? = nil + private var pollForDeletedMessagesTimer: Timer? = nil + private var pollForModeratorsTimer: Timer? = nil + private var hasStarted = false + private var isPolling = false + + private var isMainAppAndActive: Bool { + var isMainAppAndActive = false + if let sharedUserDefaults = UserDefaults(suiteName: "group.com.loki-project.loki-messenger") { + isMainAppAndActive = sharedUserDefaults.bool(forKey: "isMainAppActive") + } + return isMainAppAndActive + } + + // MARK: Settings + private let pollForNewMessagesInterval: TimeInterval = 4 + private let pollForDeletedMessagesInterval: TimeInterval = 30 + private let pollForModeratorsInterval: TimeInterval = 10 * 60 + + // MARK: Lifecycle + public init(for openGroup: OpenGroupV2) { + self.openGroup = openGroup + super.init() + } + + @objc public func startIfNeeded() { + guard !hasStarted else { return } + guard isMainAppAndActive else { stop(); return } + DispatchQueue.main.async { [weak self] in // Timers don't do well on background queues + guard let strongSelf = self else { return } + strongSelf.hasStarted = true + // Create timers + strongSelf.pollForNewMessagesTimer = Timer.scheduledTimer(withTimeInterval: strongSelf.pollForNewMessagesInterval, repeats: true) { _ in self?.pollForNewMessages() } + strongSelf.pollForDeletedMessagesTimer = Timer.scheduledTimer(withTimeInterval: strongSelf.pollForDeletedMessagesInterval, repeats: true) { _ in self?.pollForDeletedMessages() } + strongSelf.pollForModeratorsTimer = Timer.scheduledTimer(withTimeInterval: strongSelf.pollForModeratorsInterval, repeats: true) { _ in self?.pollForModerators() } + // Perform initial updates + strongSelf.pollForNewMessages() + strongSelf.pollForDeletedMessages() + strongSelf.pollForModerators() + } + } + + @objc public func stop() { + pollForNewMessagesTimer?.invalidate() + pollForDeletedMessagesTimer?.invalidate() + pollForModeratorsTimer?.invalidate() + hasStarted = false + } + + // MARK: Polling + @discardableResult + public func pollForNewMessages() -> Promise { + guard isMainAppAndActive else { stop(); return Promise.value(()) } + return pollForNewMessages(isBackgroundPoll: false) + } + + @discardableResult + public func pollForNewMessages(isBackgroundPoll: Bool) -> Promise { + guard !self.isPolling else { return Promise.value(()) } + self.isPolling = true + let openGroup = self.openGroup + let (promise, seal) = Promise.pending() + promise.retainUntilComplete() + OpenGroupAPIV2.getMessages(for: openGroup.room, on: openGroup.server).done(on: DispatchQueue.global(qos: .default)) { [weak self] messages in + guard let self = self else { return } + self.isPolling = false + // Sorting the messages by server ID before importing them fixes an issue where messages that quote older messages can't find those older messages + let messages = messages.sorted { $0.serverID! < $1.serverID! } // Safe because messages with a nil serverID are filtered out + messages.forEach { message in + guard let data = Data(base64Encoded: message.base64EncodedData) else { + return SNLog("Ignoring open group message with invalid encoding.") + } + let job = MessageReceiveJob(data: data, openGroupMessageServerID: UInt64(message.serverID!), openGroupID: self.openGroup.id, isBackgroundPoll: isBackgroundPoll) + SNMessagingKitConfiguration.shared.storage.write { transaction in + SessionMessagingKit.JobQueue.shared.add(job, using: transaction) + } + } + }.catch(on: DispatchQueue.global(qos: .userInitiated)) { _ in + seal.fulfill(()) // The promise is just used to keep track of when we're done + }.retainUntilComplete() + return promise + } + + private func pollForDeletedMessages() { + let openGroup = self.openGroup + OpenGroupAPIV2.getDeletedMessages(for: openGroup.room, on: openGroup.server).done(on: DispatchQueue.global(qos: .default)) { serverIDs in + let messageIDs = serverIDs.compactMap { Storage.shared.getIDForMessage(withServerID: UInt64($0)) } + SNMessagingKitConfiguration.shared.storage.write { transaction in + let transaction = transaction as! YapDatabaseReadWriteTransaction + messageIDs.forEach { messageID in + TSMessage.fetch(uniqueId: messageID, transaction: transaction)?.remove(with: transaction) + } + } + }.retainUntilComplete() + } + + private func pollForModerators() { + OpenGroupAPIV2.getModerators(for: openGroup.room, on: openGroup.server).retainUntilComplete() + } +} diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index a3dda1822..537fa3a59 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -43,8 +43,8 @@ public protocol SessionMessagingKitStorageProtocol { // MARK: - Open Groups - func getAllUserOpenGroups() -> [String:OpenGroup] - func getOpenGroup(for threadID: String) -> OpenGroup? + func getAllV2OpenGroups() -> [String:OpenGroupV2] + func getV2OpenGroup(for threadID: String) -> OpenGroupV2? func getThreadID(for openGroupID: String) -> String? func updateMessageIDCollectionByPruningMessagesWithIDs(_ messageIDs: Set, using transaction: Any) @@ -101,4 +101,7 @@ public protocol SessionMessagingKitStorageProtocol { func getLastDeletionServerID(for group: UInt64, on server: String) -> UInt64? func setLastDeletionServerID(for group: UInt64, on server: String, to newValue: UInt64, using transaction: Any) func removeLastDeletionServerID(for group: UInt64, on server: String, using transaction: Any) + + func getAllUserOpenGroups() -> [String:OpenGroup] + func getOpenGroup(for threadID: String) -> OpenGroup? }