mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
6.0 KiB
Swift
176 lines
6.0 KiB
Swift
8 years ago
|
//
|
||
6 years ago
|
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||
8 years ago
|
//
|
||
8 years ago
|
|
||
|
import Foundation
|
||
|
import PromiseKit
|
||
5 years ago
|
import SignalUtilitiesKit
|
||
8 years ago
|
|
||
|
@objc(OWSMessageFetcherJob)
|
||
7 years ago
|
public class MessageFetcherJob: NSObject {
|
||
8 years ago
|
|
||
7 years ago
|
private var timer: Timer?
|
||
|
|
||
7 years ago
|
@objc
|
||
7 years ago
|
public override init() {
|
||
7 years ago
|
super.init()
|
||
7 years ago
|
|
||
7 years ago
|
SwiftSingletons.register(self)
|
||
8 years ago
|
}
|
||
|
|
||
7 years ago
|
// MARK: Singletons
|
||
|
|
||
|
private var networkManager: TSNetworkManager {
|
||
|
return SSKEnvironment.shared.networkManager
|
||
|
}
|
||
|
|
||
|
private var messageReceiver: OWSMessageReceiver {
|
||
|
return SSKEnvironment.shared.messageReceiver
|
||
|
}
|
||
|
|
||
6 years ago
|
private var signalService: OWSSignalService {
|
||
7 years ago
|
return OWSSignalService.sharedInstance()
|
||
|
}
|
||
|
|
||
7 years ago
|
// MARK:
|
||
|
|
||
7 years ago
|
@discardableResult
|
||
|
public func run() -> Promise<Void> {
|
||
6 years ago
|
let promise = fetchUndeliveredMessages().then { promises -> Promise<Void> in
|
||
|
let promises = promises.map { promise -> Promise<Void> in
|
||
|
return promise.then { envelopes -> Promise<Void> in
|
||
|
for envelope in envelopes {
|
||
|
Logger.info("Envelope received.")
|
||
|
do {
|
||
|
let envelopeData = try envelope.serializedData()
|
||
|
self.messageReceiver.handleReceivedEnvelopeData(envelopeData)
|
||
|
} catch {
|
||
|
owsFailDebug("Failed to serialize envelope.")
|
||
|
}
|
||
|
self.acknowledgeDelivery(envelope: envelope)
|
||
|
}
|
||
|
return Promise.value(())
|
||
|
}
|
||
|
}
|
||
|
return when(resolved: promises).asVoid()
|
||
|
}
|
||
|
promise.retainUntilComplete()
|
||
|
return promise
|
||
8 years ago
|
}
|
||
|
|
||
7 years ago
|
@objc
|
||
|
@discardableResult
|
||
|
public func run() -> AnyPromise {
|
||
7 years ago
|
return AnyPromise(run() as Promise)
|
||
8 years ago
|
}
|
||
|
|
||
|
// use in DEBUG or wherever you can't receive push notifications to poll for messages.
|
||
|
// Do not use in production.
|
||
8 years ago
|
public func startRunLoop(timeInterval: Double) {
|
||
7 years ago
|
Logger.error("Starting message fetch polling. This should not be used in production.")
|
||
8 years ago
|
timer = WeakTimer.scheduledTimer(timeInterval: timeInterval, target: self, userInfo: nil, repeats: true) {[weak self] _ in
|
||
8 years ago
|
let _: Promise<Void>? = self?.run()
|
||
|
return
|
||
8 years ago
|
}
|
||
8 years ago
|
}
|
||
|
|
||
8 years ago
|
public func stopRunLoop() {
|
||
8 years ago
|
timer?.invalidate()
|
||
|
timer = nil
|
||
|
}
|
||
|
|
||
7 years ago
|
private func parseMessagesResponse(responseObject: Any?) -> (envelopes: [SSKProtoEnvelope], more: Bool)? {
|
||
8 years ago
|
guard let responseObject = responseObject else {
|
||
7 years ago
|
Logger.error("response object was surpringly nil")
|
||
8 years ago
|
return nil
|
||
|
}
|
||
|
|
||
|
guard let responseDict = responseObject as? [String: Any] else {
|
||
7 years ago
|
Logger.error("response object was not a dictionary")
|
||
8 years ago
|
return nil
|
||
|
}
|
||
|
|
||
|
guard let messageDicts = responseDict["messages"] as? [[String: Any]] else {
|
||
7 years ago
|
Logger.error("messages object was not a list of dictionaries")
|
||
8 years ago
|
return nil
|
||
|
}
|
||
|
|
||
8 years ago
|
let moreMessages = { () -> Bool in
|
||
8 years ago
|
if let responseMore = responseDict["more"] as? Bool {
|
||
|
return responseMore
|
||
|
} else {
|
||
7 years ago
|
Logger.warn("more object was not a bool. Assuming no more")
|
||
8 years ago
|
return false
|
||
|
}
|
||
|
}()
|
||
|
|
||
7 years ago
|
let envelopes: [SSKProtoEnvelope] = messageDicts.compactMap { buildEnvelope(messageDict: $0) }
|
||
8 years ago
|
|
||
|
return (
|
||
|
envelopes: envelopes,
|
||
|
more: moreMessages
|
||
|
)
|
||
|
}
|
||
|
|
||
7 years ago
|
private func buildEnvelope(messageDict: [String: Any]) -> SSKProtoEnvelope? {
|
||
7 years ago
|
do {
|
||
|
let params = ParamParser(dictionary: messageDict)
|
||
8 years ago
|
|
||
7 years ago
|
let typeInt: Int32 = try params.required(key: "type")
|
||
7 years ago
|
guard let type: SSKProtoEnvelope.SSKProtoEnvelopeType = SSKProtoEnvelope.SSKProtoEnvelopeType(rawValue: typeInt) else {
|
||
7 years ago
|
Logger.error("`type` was invalid: \(typeInt)")
|
||
7 years ago
|
throw ParamParser.ParseError.invalidFormat("type")
|
||
|
}
|
||
8 years ago
|
|
||
7 years ago
|
guard let timestamp: UInt64 = try params.required(key: "timestamp") else {
|
||
7 years ago
|
Logger.error("`timestamp` was invalid: \(typeInt)")
|
||
7 years ago
|
throw ParamParser.ParseError.invalidFormat("timestamp")
|
||
7 years ago
|
}
|
||
7 years ago
|
|
||
7 years ago
|
let builder = SSKProtoEnvelope.builder(type: type, timestamp: timestamp)
|
||
|
|
||
|
if let source: String = try params.optional(key: "source") {
|
||
|
builder.setSource(source)
|
||
7 years ago
|
}
|
||
7 years ago
|
|
||
7 years ago
|
if let sourceDevice: UInt32 = try params.optional(key: "sourceDevice") {
|
||
|
builder.setSourceDevice(sourceDevice)
|
||
|
}
|
||
7 years ago
|
|
||
7 years ago
|
if let legacyMessage = try params.optionalBase64EncodedData(key: "message") {
|
||
|
builder.setLegacyMessage(legacyMessage)
|
||
|
}
|
||
|
if let content = try params.optionalBase64EncodedData(key: "content") {
|
||
|
builder.setContent(content)
|
||
|
}
|
||
7 years ago
|
if let serverTimestamp: UInt64 = try params.optional(key: "serverTimestamp") {
|
||
|
builder.setServerTimestamp(serverTimestamp)
|
||
|
}
|
||
|
if let serverGuid: String = try params.optional(key: "guid") {
|
||
|
builder.setServerGuid(serverGuid)
|
||
|
}
|
||
8 years ago
|
|
||
7 years ago
|
return try builder.build()
|
||
7 years ago
|
} catch {
|
||
7 years ago
|
owsFailDebug("error building envelope: \(error)")
|
||
8 years ago
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
6 years ago
|
private func fetchUndeliveredMessages() -> Promise<Set<Promise<[SSKProtoEnvelope]>>> {
|
||
5 years ago
|
let userPublickKey = getUserHexEncodedPublicKey() // Can be missing in rare cases
|
||
|
guard !userPublickKey.isEmpty else { return Promise.value(Set()) }
|
||
5 years ago
|
return SnodeAPI.getMessages(for: userPublickKey).map2 { promises -> Set<Promise<[SSKProtoEnvelope]>> in
|
||
|
return Set(promises.map { promise -> Promise<[SSKProtoEnvelope]> in
|
||
|
return promise.map2 { rawMessages -> [SSKProtoEnvelope] in
|
||
|
return rawMessages.compactMap { SSKProtoEnvelope.from($0) }
|
||
|
}
|
||
|
})
|
||
|
}
|
||
8 years ago
|
}
|
||
|
|
||
7 years ago
|
private func acknowledgeDelivery(envelope: SSKProtoEnvelope) {
|
||
5 years ago
|
// Do nothing
|
||
8 years ago
|
}
|
||
|
}
|