From 455c8c520bfbd9f04ba88d67393572d577dc356c Mon Sep 17 00:00:00 2001 From: Mikunj Date: Fri, 24 May 2019 16:07:00 +1000 Subject: [PATCH] More pinging logic --- .../src/Loki/API/LokiAPI+Message.swift | 17 ++++++++--- .../src/Loki/API/LokiAPI+P2P.swift | 25 ++++++++++++++-- SignalServiceKit/src/Loki/API/LokiAPI.swift | 29 +++++++++---------- .../src/Loki/Messages/LKAddressMessage.h | 6 ++-- .../src/Loki/Messages/LKAddressMessage.m | 3 ++ .../src/Messages/OWSMessageManager.m | 2 +- .../src/Messages/OWSMessageSender.m | 10 +++++-- .../src/Messages/OWSMessageServiceParams.h | 6 +++- .../src/Messages/OWSMessageServiceParams.m | 2 ++ 9 files changed, 72 insertions(+), 28 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/LokiAPI+Message.swift b/SignalServiceKit/src/Loki/API/LokiAPI+Message.swift index 78b57f1cf..2a9daf067 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI+Message.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI+Message.swift @@ -9,6 +9,9 @@ public extension LokiAPI { let data: LosslessStringConvertible /// The time to live for the message in milliseconds. let ttl: UInt64 + /// Wether this message is a ping. + /// This should always be false unless it is from p2p pinging logic. + let isPing: Bool /// When the proof of work was calculated, if applicable. /// /// - Note: Expressed as milliseconds since 00:00:00 UTC on 1 January 1970. @@ -25,9 +28,13 @@ public extension LokiAPI { let wrappedMessage = try LokiMessageWrapper.wrap(message: signalMessage, timestamp: timestamp) let data = wrappedMessage.base64EncodedString() let destination = signalMessage["destination"] as! String + var ttl = LokiAPI.defaultMessageTTL if let messageTTL = signalMessage["ttl"] as? UInt, messageTTL > 0 { ttl = UInt64(messageTTL) } - return Message(destination: destination, data: data, ttl: ttl, timestamp: nil, nonce: nil) + + let isPing = signalMessage["isPing"] as! Bool + + return Message(destination: destination, data: data, ttl: ttl, isPing: isPing) } catch let error { Logger.debug("[Loki] Failed to convert Signal message to Loki message: \(signalMessage)") return nil @@ -40,17 +47,19 @@ public extension LokiAPI { /// - destination: The destination /// - data: The data /// - ttl: The time to live - public init(destination: String, data: LosslessStringConvertible, ttl: UInt64) { + public init(destination: String, data: LosslessStringConvertible, ttl: UInt64, isPing: Bool = false) { self.destination = destination self.data = data self.ttl = ttl + self.isPing = isPing } /// Private init for setting proof of work. Use `calculatePoW` to get a message with these fields - private init(destination: String, data: LosslessStringConvertible, ttl: UInt64, timestamp: UInt64?, nonce: String?) { + private init(destination: String, data: LosslessStringConvertible, ttl: UInt64, isPing: Bool, timestamp: UInt64?, nonce: String?) { self.destination = destination self.data = data self.ttl = ttl + self.isPing = isPing self.timestamp = timestamp self.nonce = nonce } @@ -64,7 +73,7 @@ public extension LokiAPI { DispatchQueue.global(qos: .default).async { let now = NSDate.ows_millisecondTimeStamp() if let nonce = ProofOfWork.calculate(data: self.data as! String, pubKey: self.destination, timestamp: now, ttl: self.ttl) { - let result = Message(destination: self.destination, data: self.data, ttl: self.ttl, timestamp: now, nonce: nonce) + let result = Message(destination: self.destination, data: self.data, ttl: self.ttl, isPing: self.isPing, timestamp: now, nonce: nonce) seal.fulfill(result) } else { seal.reject(Error.proofOfWorkCalculationFailed) diff --git a/SignalServiceKit/src/Loki/API/LokiAPI+P2P.swift b/SignalServiceKit/src/Loki/API/LokiAPI+P2P.swift index 00e3453a0..d6b9ed770 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI+P2P.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI+P2P.swift @@ -1,15 +1,17 @@ extension LokiAPI { - private static let messageSender: MessageSender = SSKEnvironment.shared.messageSender + /// The amount of time before pinging when a user is set to offline + private static let offlinePingTime = 2 * kMinuteInterval + /// A p2p state struct internal struct P2PDetails { var address: String var port: UInt32 var isOnline: Bool var timerDuration: Double - var pingTimer: WeakTimer? = nil + var pingTimer: Timer? = nil var target: Target { return Target(address: address, port: port) @@ -68,6 +70,23 @@ extension LokiAPI { // TODO: Ping the contact } + @objc public static func setOnline(_ isOnline: Bool, forContact pubKey: String) { + guard var details = contactP2PDetails[pubKey] else { return } + + let interval = isOnline ? details.timerDuration : offlinePingTime + + // Setup a new timer + details.pingTimer?.invalidate() + details.pingTimer = WeakTimer.scheduledTimer(timeInterval: interval, target: self, userInfo: nil, repeats: true) { _ in ping(contact: pubKey) } + details.isOnline = isOnline + + contactP2PDetails[pubKey] = details + } + + @objc public static func ping(contact pubKey: String) { + + } + /// Set the Contact p2p details /// /// - Parameters: @@ -109,7 +128,7 @@ extension LokiAPI { return nil } - return LokiAddressMessage(in: thread, address: ourAddress.address, port: ourAddress.port) + return LokiAddressMessage(in: thread, address: ourAddress.address, port: ourAddress.port, isPing: false) } /// Send a `Loki Address` message to the given thread diff --git a/SignalServiceKit/src/Loki/API/LokiAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI.swift index e41bb628d..8096a4ddb 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI.swift @@ -51,16 +51,6 @@ import PromiseKit }.map { Set($0) } } - public static func ping(_ hexEncodedPublicKey: String) -> Promise>> { - let isP2PMessagingPossible = false - if isP2PMessagingPossible { - // TODO: Send using P2P protocol - } else { - let parameters: [String:Any] = [ "pubKey" : hexEncodedPublicKey ] // TODO: Figure out correct parameters - return getTargetSnodes(for: hexEncodedPublicKey).mapValues { invoke(.sendMessage, on: $0, associatedWith: hexEncodedPublicKey, parameters: parameters) }.map { Set($0) } - } - } - // MARK: Public API (Obj-C) @objc public static func objc_sendSignalMessage(_ signalMessage: SignalMessage, to destination: String, with timestamp: UInt64) -> AnyPromise { let promise = sendSignalMessage(signalMessage, to: destination, timestamp: timestamp).mapValues { AnyPromise.from($0) }.map { Set($0) } @@ -82,13 +72,22 @@ import PromiseKit } } - // If we have the p2p details then send message to that + // If we have the p2p details and we have marked the user as online OR we are pinging the user, then use peer to peer // If that failes then fallback to storage server - // TODO: probably only send to p2p if user is online or we are pinging them - // p2pDetails && (isPing || peerIsOnline) - if let p2pDetails = contactP2PDetails[destination] { + if let p2pDetails = contactP2PDetails[destination], message.isPing || p2pDetails.isOnline { let targets = Promise.wrap([p2pDetails.target]) - return sendMessage(message, targets: targets).recover { _ in return sendThroughStorageServer() } + return sendMessage(message, targets: targets).recover { error -> Promise>> in + // The user is not online + LokiAPI.setOnline(false, forContact: destination) + + // If it was a ping then don't send to the storage server + if (message.isPing) { + Logger.warn("[Loki] Failed to ping \(destination) - Marking contact as offline.") + throw error + } + + return sendThroughStorageServer() + } } return sendThroughStorageServer() diff --git a/SignalServiceKit/src/Loki/Messages/LKAddressMessage.h b/SignalServiceKit/src/Loki/Messages/LKAddressMessage.h index 9d928ce1c..ab0ffb604 100644 --- a/SignalServiceKit/src/Loki/Messages/LKAddressMessage.h +++ b/SignalServiceKit/src/Loki/Messages/LKAddressMessage.h @@ -7,11 +7,13 @@ NS_SWIFT_NAME(LokiAddressMessage) @interface LKAddressMessage : LKEphemeralMessage - (instancetype)initInThread:(nullable TSThread *)thread - address:(NSString *)address - port:(uint)port; + address:(NSString *)address + port:(uint)port + isPing:(BOOL)isPing; @property (nonatomic, readonly) NSString *address; @property (nonatomic, readonly) uint port; +@property (nonatomic, readonly) BOOL isPing; @end diff --git a/SignalServiceKit/src/Loki/Messages/LKAddressMessage.m b/SignalServiceKit/src/Loki/Messages/LKAddressMessage.m index 4a9d85d75..e67dae035 100644 --- a/SignalServiceKit/src/Loki/Messages/LKAddressMessage.m +++ b/SignalServiceKit/src/Loki/Messages/LKAddressMessage.m @@ -7,6 +7,7 @@ @property (nonatomic) NSString *address; @property (nonatomic) uint port; +@property (nonatomic) BOOL isPing; @end @@ -15,6 +16,7 @@ - (instancetype)initInThread:(nullable TSThread *)thread address:(NSString *)address port:(uint)port + isPing:(bool)isPing { self = [super initInThread:thread]; if (!self) { @@ -23,6 +25,7 @@ _address = address; _port = port; + _isPing = isPing; return self; } diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index e79b66e4b..88c338db1 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -437,7 +437,7 @@ NS_ASSUME_NONNULL_BEGIN if (contentProto.lokiAddressMessage) { NSString *address = contentProto.lokiAddressMessage.ptpAddress; uint32_t port = contentProto.lokiAddressMessage.ptpPort; - [LokiAPI didReceiveLokiAddressMessageForContact:envelope.source address:address port:port receivedThroughP2P:envelope.isPtpMessage] + [LokiAPI didReceiveLokiAddressMessageForContact:envelope.source address:address port:port receivedThroughP2P:envelope.isPtpMessage]; } if (contentProto.syncMessage) { diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index c6c66f788..1b00df5de 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -44,6 +44,7 @@ #import "TSSocketManager.h" #import "TSThread.h" #import "LKFriendRequestMessage.h" +#import "LKAddressMessage.h" #import #import #import @@ -1792,7 +1793,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; isSilent:false isOnline:false registrationId:0 - ttl:message.ttl]; + ttl:message.ttl + isPing:false]; NSError *error; NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error]; @@ -1879,6 +1881,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; BOOL isSilent = message.isSilent; BOOL isOnline = message.isOnline; + + LKAddressMessage *_Nullable addressMessage = [message as:[LKAddressMessage class]]; + BOOL isPing = addressMessage != nil && addressMessage.isPing; OWSMessageServiceParams *messageParams = [[OWSMessageServiceParams alloc] initWithType:messageType recipientId:recipientId @@ -1887,7 +1892,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; isSilent:isSilent isOnline:isOnline registrationId:[cipher throws_remoteRegistrationId:transaction] - ttl:message.ttl]; + ttl:message.ttl + isPing:isPing]; NSError *error; NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error]; diff --git a/SignalServiceKit/src/Messages/OWSMessageServiceParams.h b/SignalServiceKit/src/Messages/OWSMessageServiceParams.h index 3a8dc25c9..83f00ce3f 100644 --- a/SignalServiceKit/src/Messages/OWSMessageServiceParams.h +++ b/SignalServiceKit/src/Messages/OWSMessageServiceParams.h @@ -27,6 +27,9 @@ NS_ASSUME_NONNULL_BEGIN // Loki: Message ttl @property (nonatomic, readonly) uint ttl; +// Loki: Wether this message is a p2p ping +@property (nonatomic, readonly) BOOL isPing; + - (instancetype)initWithType:(TSWhisperMessageType)type recipientId:(NSString *)destination device:(int)deviceId @@ -34,7 +37,8 @@ NS_ASSUME_NONNULL_BEGIN isSilent:(BOOL)isSilent isOnline:(BOOL)isOnline registrationId:(int)registrationId - ttl:(uint)ttl; + ttl:(uint)ttl + isPing:(BOOL)isPing; @end diff --git a/SignalServiceKit/src/Messages/OWSMessageServiceParams.m b/SignalServiceKit/src/Messages/OWSMessageServiceParams.m index cfd88bd3e..d7a0cbf12 100644 --- a/SignalServiceKit/src/Messages/OWSMessageServiceParams.m +++ b/SignalServiceKit/src/Messages/OWSMessageServiceParams.m @@ -23,6 +23,7 @@ NS_ASSUME_NONNULL_BEGIN isOnline:(BOOL)isOnline registrationId:(int)registrationId ttl:(uint)ttl + isPing:(BOOL)isPing { self = [super init]; @@ -38,6 +39,7 @@ NS_ASSUME_NONNULL_BEGIN _silent = isSilent; _online = isOnline; _ttl = ttl; + _isPing = isPing; return self; }