diff --git a/SignalServiceKit/src/Loki/API/LokiAPI+P2P.swift b/SignalServiceKit/src/Loki/API/LokiAPI+P2P.swift index 3c91520c1..00e3453a0 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI+P2P.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI+P2P.swift @@ -1,10 +1,72 @@ extension LokiAPI { + private static let messageSender: MessageSender = SSKEnvironment.shared.messageSender + + /// A p2p state struct + internal struct P2PDetails { + var address: String + var port: UInt32 + var isOnline: Bool + var timerDuration: Double + var pingTimer: WeakTimer? = nil + + var target: Target { + return Target(address: address, port: port) + } + } + internal static var ourP2PAddress: Target? = nil /// This is where we store the p2p details of our contacts - internal static var contactP2PDetails = [String: Target]() + internal static var contactP2PDetails = [String: P2PDetails]() + + /// Handle P2P logic when we receive a `LokiAddressMessage` + /// + /// - Parameters: + /// - pubKey: The other users pubKey + /// - address: The pther users p2p address + /// - port: The other users p2p port + /// - receivedThroughP2P: Wether we received the message through p2p + @objc public static func didReceiveLokiAddressMessage(forContact pubKey: String, address: String, port: UInt32, receivedThroughP2P: Bool) { + // Stagger the ping timers so that contacts don't ping each other at the same time + let timerDuration = pubKey < ourHexEncodedPubKey ? 1 * kMinuteInterval : 2 * kMinuteInterval + + // Get out current contact details + let oldContactDetails = contactP2PDetails[pubKey] + + // Set the new contact details + // A contact is always assumed to be offline unless the specific conditions below are met + let details = P2PDetails(address: address, port: port, isOnline: false, timerDuration: timerDuration, pingTimer: nil) + + // Set up our checks + let oldContactExists = oldContactDetails != nil + let wasOnline = oldContactDetails?.isOnline ?? false + let p2pDetailsMatch = oldContactDetails?.address == address && oldContactDetails?.port == port + + /* + We need to check if we should ping the user. + We don't ping the user IF: + - We had old contact details + - We got a P2P message + - The old contact was set as `Online` + - The new p2p details match the old one + */ + if oldContactExists && receivedThroughP2P && wasOnline && p2pDetailsMatch { + // TODO: Set contact to online and start the ping timers + return; + } + + /* + Ping the contact. + This happens in the following scenarios: + 1. We didn't have the contact, we need to ping them to let them know our details. + 2. wasP2PMessage = false, so we assume the contact doesn't have our details. + 3. We had the contact marked as offline, we need to make sure that we can reach their server. + 4. The other contact details have changed, we need to make sure that we can reach their new server. + */ + // TODO: Ping the contact + } /// Set the Contact p2p details /// @@ -13,8 +75,8 @@ extension LokiAPI { /// - address: The contacts p2p address /// - port: The contacts p2p port @objc public static func setContactP2PDetails(forContact pubKey: String, address: String, port: UInt32) { - let target = Target(address: address, port: port) - contactP2PDetails[pubKey] = target + let details = P2PDetails(address: address, port: port, isOnline: false, timerDuration: 10, pingTimer: nil) + contactP2PDetails[pubKey] = details } /// Set our local P2P address diff --git a/SignalServiceKit/src/Loki/API/LokiAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI.swift index b925740d9..e41bb628d 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI.swift @@ -87,7 +87,7 @@ import PromiseKit // TODO: probably only send to p2p if user is online or we are pinging them // p2pDetails && (isPing || peerIsOnline) if let p2pDetails = contactP2PDetails[destination] { - let targets = Promise.wrap([p2pDetails]) + let targets = Promise.wrap([p2pDetails.target]) return sendMessage(message, targets: targets).recover { _ in return sendThroughStorageServer() } } diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 9d9391160..e79b66e4b 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -435,7 +435,9 @@ NS_ASSUME_NONNULL_BEGIN // Loki: Check if we got p2p address if (contentProto.lokiAddressMessage) { - [LokiAPI setContactP2PDetailsForContact:envelope.source address:contentProto.lokiAddressMessage.ptpAddress port:contentProto.lokiAddressMessage.ptpPort]; + NSString *address = contentProto.lokiAddressMessage.ptpAddress; + uint32_t port = contentProto.lokiAddressMessage.ptpPort; + [LokiAPI didReceiveLokiAddressMessageForContact:envelope.source address:address port:port receivedThroughP2P:envelope.isPtpMessage] } if (contentProto.syncMessage) {