From b90904ebbd8bdd7537cae38e7e69088403cf0c56 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Tue, 22 Mar 2022 14:09:47 +1100 Subject: [PATCH] Updated the code to only update the last message hash once the MessageReceiveJobs have been created --- Session/Utilities/BackgroundPoller.swift | 6 +++- .../Pollers/ClosedGroupPoller.swift | 11 +++++-- .../Sending & Receiving/Pollers/Poller.swift | 6 +++- SessionSnodeKit/SnodeAPI.swift | 33 +++++++------------ 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/Session/Utilities/BackgroundPoller.swift b/Session/Utilities/BackgroundPoller.swift index 0d67c90fe..ff31d0965 100644 --- a/Session/Utilities/BackgroundPoller.swift +++ b/Session/Utilities/BackgroundPoller.swift @@ -42,7 +42,7 @@ public final class BackgroundPoller : NSObject { guard let snode = swarm.randomElement() else { throw SnodeAPI.Error.generic } return attempt(maxRetryCount: 4, recoveringOn: DispatchQueue.main) { return SnodeAPI.getRawMessages(from: snode, associatedWith: publicKey).then(on: DispatchQueue.main) { rawResponse -> Promise in - let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: publicKey) + let (messages, lastRawMessage) = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: publicKey) let promises = messages.compactMap { json -> Promise? in // Use a best attempt approach here; we don't want to fail the entire process if one of the // messages failed to parse. @@ -51,6 +51,10 @@ public final class BackgroundPoller : NSObject { let job = MessageReceiveJob(data: data, serverHash: json["hash"] as? String, isBackgroundPoll: true) return job.execute() } + + // Now that the MessageReceiveJob's have been created we can update the `lastMessageHash` value + SnodeAPI.updateLastMessageHashValueIfPossible(for: snode, associatedWith: publicKey, from: lastRawMessage) + return when(fulfilled: promises) // The promise returned by MessageReceiveJob never rejects } } diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift index eb5966cd5..1644488e6 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift @@ -100,15 +100,17 @@ public final class ClosedGroupPoller : NSObject { private func poll(_ groupPublicKey: String) -> Promise { guard isPolling(for: groupPublicKey) else { return Promise.value(()) } - let promise = SnodeAPI.getSwarm(for: groupPublicKey).then2 { [weak self] swarm -> Promise<[JSON]> in + let promise = SnodeAPI.getSwarm(for: groupPublicKey).then2 { [weak self] swarm -> Promise<(Snode, [JSON], JSON?)> in // randomElement() uses the system's default random generator, which is cryptographically secure guard let snode = swarm.randomElement() else { return Promise(error: Error.insufficientSnodes) } guard let self = self, self.isPolling(for: groupPublicKey) else { return Promise(error: Error.pollingCanceled) } return SnodeAPI.getRawMessages(from: snode, associatedWith: groupPublicKey).map2 { - SnodeAPI.parseRawMessagesResponse($0, from: snode, associatedWith: groupPublicKey) + let (rawMessages, lastRawMessage) = SnodeAPI.parseRawMessagesResponse($0, from: snode, associatedWith: groupPublicKey) + + return (snode, rawMessages, lastRawMessage) } } - promise.done2 { [weak self] rawMessages in + promise.done2 { [weak self] snode, rawMessages, lastRawMessage in guard let self = self, self.isPolling(for: groupPublicKey) else { return } if !rawMessages.isEmpty { SNLog("Received \(rawMessages.count) new message(s) in closed group with public key: \(groupPublicKey).") @@ -125,6 +127,9 @@ public final class ClosedGroupPoller : NSObject { SNLog("Failed to deserialize envelope due to error: \(error).") } } + + // Now that the MessageReceiveJob's have been created we can update the `lastMessageHash` value + SnodeAPI.updateLastMessageHashValueIfPossible(for: snode, associatedWith: groupPublicKey, from: lastRawMessage) } promise.catch2 { error in SNLog("Polling failed for closed group with public key: \(groupPublicKey) due to error: \(error).") diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift index 623acf1ff..5c9e66561 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift @@ -94,7 +94,7 @@ public final class Poller : NSObject { let userPublicKey = getUserHexEncodedPublicKey() return SnodeAPI.getRawMessages(from: snode, associatedWith: userPublicKey).then(on: Threading.pollerQueue) { [weak self] rawResponse -> Promise in guard let strongSelf = self, strongSelf.isPolling else { return Promise { $0.fulfill(()) } } - let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: userPublicKey) + let (messages, lastRawMessage) = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: userPublicKey) if !messages.isEmpty { SNLog("Received \(messages.count) new message(s).") } @@ -110,6 +110,10 @@ public final class Poller : NSObject { SNLog("Failed to deserialize envelope due to error: \(error).") } } + + // Now that the MessageReceiveJob's have been created we can update the `lastMessageHash` value + SnodeAPI.updateLastMessageHashValueIfPossible(for: snode, associatedWith: userPublicKey, from: lastRawMessage) + strongSelf.pollCount += 1 if strongSelf.pollCount == Poller.maxPollCount { throw Error.pollLimitReached diff --git a/SessionSnodeKit/SnodeAPI.swift b/SessionSnodeKit/SnodeAPI.swift index 7602242bf..ae1382e67 100644 --- a/SessionSnodeKit/SnodeAPI.swift +++ b/SessionSnodeKit/SnodeAPI.swift @@ -398,20 +398,6 @@ public final class SnodeAPI : NSObject { return promise } - public static func getMessages(for publicKey: String) -> Promise> { - let (promise, seal) = Promise>.pending() - Threading.workQueue.async { - attempt(maxRetryCount: maxRetryCount, recoveringOn: Threading.workQueue) { - getTargetSnodes(for: publicKey).mapValues2 { targetSnode in - return getMessagesInternal(from: targetSnode, associatedWith: publicKey).map2 { rawResponse in - parseRawMessagesResponse(rawResponse, from: targetSnode, associatedWith: publicKey) - } - }.map2 { Set($0) } - }.done2 { seal.fulfill($0) }.catch2 { seal.reject($0) } - } - return promise - } - private static func getMessagesInternal(from snode: Snode, associatedWith publicKey: String) -> RawResponsePromise { let storage = SNSnodeKitConfiguration.shared.storage @@ -573,20 +559,23 @@ public final class SnodeAPI : NSObject { }) } - public static func parseRawMessagesResponse(_ rawResponse: Any, from snode: Snode, associatedWith publicKey: String) -> [JSON] { - guard let json = rawResponse as? JSON, let rawMessages = json["messages"] as? [JSON] else { return [] } - updateLastMessageHashValueIfPossible(for: snode, associatedWith: publicKey, from: rawMessages) - return removeDuplicates(from: rawMessages, associatedWith: publicKey) + public static func parseRawMessagesResponse(_ rawResponse: Any, from snode: Snode, associatedWith publicKey: String) -> (messages: [JSON], lastRawMessage: JSON?) { + guard let json = rawResponse as? JSON, let rawMessages = json["messages"] as? [JSON] else { return ([], nil) } + + return ( + removeDuplicates(from: rawMessages, associatedWith: publicKey), + rawMessages.last + ) } - private static func updateLastMessageHashValueIfPossible(for snode: Snode, associatedWith publicKey: String, from rawMessages: [JSON]) { - if let lastMessage = rawMessages.last, let lastHash = lastMessage["hash"] as? String, let expirationDate = lastMessage["expiration"] as? UInt64 { + public static func updateLastMessageHashValueIfPossible(for snode: Snode, associatedWith publicKey: String, from lastRawMessage: JSON?) { + if let lastMessage = lastRawMessage, let lastHash = lastMessage["hash"] as? String, let expirationDate = lastMessage["expiration"] as? UInt64 { SNSnodeKitConfiguration.shared.storage.writeSync { transaction in SNSnodeKitConfiguration.shared.storage.setLastMessageHashInfo(for: snode, associatedWith: publicKey, to: [ "hash" : lastHash, "expirationDate" : NSNumber(value: expirationDate) ], using: transaction) } - } else if (!rawMessages.isEmpty) { - SNLog("Failed to update last message hash value from: \(rawMessages).") + } else if (lastRawMessage != nil) { + SNLog("Failed to update last message hash value from: \(String(describing: lastRawMessage)).") } }