Merge branch 'dev' of https://github.com/oxen-io/session-ios into home-refresh-crash

pull/412/head
ryanzhao 4 years ago
commit f05664b86c

@ -13,12 +13,6 @@ public final class BackgroundPoller : NSObject {
promises = [] promises = []
promises.append(pollForMessages()) promises.append(pollForMessages())
promises.append(contentsOf: pollForClosedGroupMessages()) promises.append(contentsOf: pollForClosedGroupMessages())
let openGroups: [String:OpenGroup] = Storage.shared.getAllUserOpenGroups()
openGroups.values.forEach { openGroup in
let poller = OpenGroupPoller(for: openGroup)
poller.stop()
promises.append(poller.pollForNewMessages(isBackgroundPoll: true))
}
let v2OpenGroupServers = Set(Storage.shared.getAllV2OpenGroups().values.map { $0.server }) let v2OpenGroupServers = Set(Storage.shared.getAllV2OpenGroups().values.map { $0.server })
v2OpenGroupServers.forEach { server in v2OpenGroupServers.forEach { server in
let poller = OpenGroupPollerV2(for: server) let poller = OpenGroupPollerV2(for: server)
@ -27,7 +21,8 @@ public final class BackgroundPoller : NSObject {
} }
when(resolved: promises).done { _ in when(resolved: promises).done { _ in
completionHandler(.newData) completionHandler(.newData)
}.catch { _ in }.catch { error in
SNLog("Background poll failed due to error: \(error)")
completionHandler(.failed) completionHandler(.failed)
} }
} }
@ -43,19 +38,21 @@ public final class BackgroundPoller : NSObject {
} }
private static func getMessages(for publicKey: String) -> Promise<Void> { private static func getMessages(for publicKey: String) -> Promise<Void> {
return SnodeAPI.getSwarm(for: publicKey).then2 { swarm -> Promise<Void> in return SnodeAPI.getSwarm(for: publicKey).then(on: DispatchQueue.main) { swarm -> Promise<Void> in
guard let snode = swarm.randomElement() else { throw SnodeAPI.Error.generic } guard let snode = swarm.randomElement() else { throw SnodeAPI.Error.generic }
return SnodeAPI.getRawMessages(from: snode, associatedWith: publicKey).then(on: DispatchQueue.main) { rawResponse -> Promise<Void> in return attempt(maxRetryCount: 4, recoveringOn: DispatchQueue.main) {
let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: publicKey) return SnodeAPI.getRawMessages(from: snode, associatedWith: publicKey).then(on: DispatchQueue.main) { rawResponse -> Promise<Void> in
let promises = messages.compactMap { json -> Promise<Void>? in let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: publicKey)
// Use a best attempt approach here; we don't want to fail the entire process if one of the let promises = messages.compactMap { json -> Promise<Void>? in
// messages failed to parse. // Use a best attempt approach here; we don't want to fail the entire process if one of the
guard let envelope = SNProtoEnvelope.from(json), // messages failed to parse.
let data = try? envelope.serializedData() else { return nil } guard let envelope = SNProtoEnvelope.from(json),
let job = MessageReceiveJob(data: data, isBackgroundPoll: true) let data = try? envelope.serializedData() else { return nil }
return job.execute() let job = MessageReceiveJob(data: data, isBackgroundPoll: true)
return job.execute()
}
return when(fulfilled: promises) // The promise returned by MessageReceiveJob never rejects
} }
return when(fulfilled: promises) // The promise returned by MessageReceiveJob never rejects
} }
} }
} }

@ -54,11 +54,6 @@ public enum MessageReceiver {
// Parse the envelope // Parse the envelope
let envelope = try SNProtoEnvelope.parseData(data) let envelope = try SNProtoEnvelope.parseData(data)
let storage = SNMessagingKitConfiguration.shared.storage let storage = SNMessagingKitConfiguration.shared.storage
// If the message failed to process the first time around we retry it later (if the error is retryable). In this case the timestamp
// will already be in the database but we don't want to treat the message as a duplicate. The isRetry flag is a simple workaround
// for this issue.
guard !Set(storage.getReceivedMessageTimestamps(using: transaction)).contains(envelope.timestamp) || isRetry else { throw Error.duplicateMessage }
storage.addReceivedMessageTimestamp(envelope.timestamp, using: transaction)
// Decrypt the contents // Decrypt the contents
guard let ciphertext = envelope.content else { throw Error.noData } guard let ciphertext = envelope.content else { throw Error.noData }
var plaintext: Data! var plaintext: Data!
@ -159,6 +154,19 @@ public enum MessageReceiver {
guard isValid else { guard isValid else {
throw Error.invalidMessage throw Error.invalidMessage
} }
// If the message failed to process the first time around we retry it later (if the error is retryable). In this case the timestamp
// will already be in the database but we don't want to treat the message as a duplicate. The isRetry flag is a simple workaround
// for this issue.
if let message = message as? ClosedGroupControlMessage, case .new = message.kind {
// Allow duplicates in this case to avoid the following situation:
// The app performed a background poll or received a push notification
// This method was invoked and the received message timestamps table was updated
// Processing wasn't finished
// The user doesn't see the new closed group
} else {
guard !Set(storage.getReceivedMessageTimestamps(using: transaction)).contains(envelope.timestamp) || isRetry else { throw Error.duplicateMessage }
storage.addReceivedMessageTimestamp(envelope.timestamp, using: transaction)
}
// Return // Return
return (message, proto) return (message, proto)
} else { } else {

Loading…
Cancel
Save