|  |  |  | import PromiseKit | 
					
						
							|  |  |  | import SessionSnodeKit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @objc(LKBackgroundPoller) | 
					
						
							|  |  |  | public final class BackgroundPoller : NSObject { | 
					
						
							|  |  |  |     private static var closedGroupPoller: ClosedGroupPoller! | 
					
						
							|  |  |  |     private static var promises: [Promise<Void>] = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private override init() { } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @objc(pollWithCompletionHandler:) | 
					
						
							|  |  |  |     public static func poll(completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { | 
					
						
							|  |  |  |         promises = [] | 
					
						
							|  |  |  |         promises.append(pollForMessages()) | 
					
						
							|  |  |  |         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)) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         when(resolved: promises).done { _ in | 
					
						
							|  |  |  |             completionHandler(.newData) | 
					
						
							|  |  |  |         }.catch { _ in | 
					
						
							|  |  |  |             completionHandler(.failed) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     private static func pollForMessages() -> Promise<Void> { | 
					
						
							|  |  |  |         let userPublicKey = getUserHexEncodedPublicKey() | 
					
						
							|  |  |  |         return getMessages(for: userPublicKey) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     private static func pollForClosedGroupMessages() -> [Promise<Void>] { | 
					
						
							|  |  |  |         let publicKeys = Storage.shared.getUserClosedGroupPublicKeys() | 
					
						
							|  |  |  |         return publicKeys.map { getMessages(for: $0) } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     private static func getMessages(for publicKey: String) -> Promise<Void> { | 
					
						
							|  |  |  |         return SnodeAPI.getSwarm(for: publicKey).then2 { swarm -> Promise<Void> in | 
					
						
							|  |  |  |             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 | 
					
						
							|  |  |  |                 let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: publicKey) | 
					
						
							|  |  |  |                 let promises = messages.compactMap { json -> Promise<Void>? in | 
					
						
							|  |  |  |                     // Use a best attempt approach here; we don't want to fail the entire process if one of the | 
					
						
							|  |  |  |                     // messages failed to parse. | 
					
						
							|  |  |  |                     guard let envelope = SNProtoEnvelope.from(json), | 
					
						
							|  |  |  |                         let data = try? envelope.serializedData() else { return nil } | 
					
						
							|  |  |  |                     let job = MessageReceiveJob(data: data, isBackgroundPoll: true) | 
					
						
							|  |  |  |                     return job.execute() | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return when(fulfilled: promises) // The promise returned by MessageReceiveJob never rejects | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |