More pinging logic

pull/20/head
Mikunj 6 years ago
parent 7f679ba5ed
commit 455c8c520b

@ -9,6 +9,9 @@ public extension LokiAPI {
let data: LosslessStringConvertible let data: LosslessStringConvertible
/// The time to live for the message in milliseconds. /// The time to live for the message in milliseconds.
let ttl: UInt64 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. /// When the proof of work was calculated, if applicable.
/// ///
/// - Note: Expressed as milliseconds since 00:00:00 UTC on 1 January 1970. /// - 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 wrappedMessage = try LokiMessageWrapper.wrap(message: signalMessage, timestamp: timestamp)
let data = wrappedMessage.base64EncodedString() let data = wrappedMessage.base64EncodedString()
let destination = signalMessage["destination"] as! String let destination = signalMessage["destination"] as! String
var ttl = LokiAPI.defaultMessageTTL var ttl = LokiAPI.defaultMessageTTL
if let messageTTL = signalMessage["ttl"] as? UInt, messageTTL > 0 { ttl = UInt64(messageTTL) } 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 { } catch let error {
Logger.debug("[Loki] Failed to convert Signal message to Loki message: \(signalMessage)") Logger.debug("[Loki] Failed to convert Signal message to Loki message: \(signalMessage)")
return nil return nil
@ -40,17 +47,19 @@ public extension LokiAPI {
/// - destination: The destination /// - destination: The destination
/// - data: The data /// - data: The data
/// - ttl: The time to live /// - 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.destination = destination
self.data = data self.data = data
self.ttl = ttl self.ttl = ttl
self.isPing = isPing
} }
/// Private init for setting proof of work. Use `calculatePoW` to get a message with these fields /// 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.destination = destination
self.data = data self.data = data
self.ttl = ttl self.ttl = ttl
self.isPing = isPing
self.timestamp = timestamp self.timestamp = timestamp
self.nonce = nonce self.nonce = nonce
} }
@ -64,7 +73,7 @@ public extension LokiAPI {
DispatchQueue.global(qos: .default).async { DispatchQueue.global(qos: .default).async {
let now = NSDate.ows_millisecondTimeStamp() let now = NSDate.ows_millisecondTimeStamp()
if let nonce = ProofOfWork.calculate(data: self.data as! String, pubKey: self.destination, timestamp: now, ttl: self.ttl) { 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) seal.fulfill(result)
} else { } else {
seal.reject(Error.proofOfWorkCalculationFailed) seal.reject(Error.proofOfWorkCalculationFailed)

@ -1,15 +1,17 @@
extension LokiAPI { extension LokiAPI {
private static let messageSender: MessageSender = SSKEnvironment.shared.messageSender 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 /// A p2p state struct
internal struct P2PDetails { internal struct P2PDetails {
var address: String var address: String
var port: UInt32 var port: UInt32
var isOnline: Bool var isOnline: Bool
var timerDuration: Double var timerDuration: Double
var pingTimer: WeakTimer? = nil var pingTimer: Timer? = nil
var target: Target { var target: Target {
return Target(address: address, port: port) return Target(address: address, port: port)
@ -68,6 +70,23 @@ extension LokiAPI {
// TODO: Ping the contact // 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 /// Set the Contact p2p details
/// ///
/// - Parameters: /// - Parameters:
@ -109,7 +128,7 @@ extension LokiAPI {
return nil 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 /// Send a `Loki Address` message to the given thread

@ -51,16 +51,6 @@ import PromiseKit
}.map { Set($0) } }.map { Set($0) }
} }
public static func ping(_ hexEncodedPublicKey: String) -> Promise<Set<Promise<RawResponse>>> {
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) // MARK: Public API (Obj-C)
@objc public static func objc_sendSignalMessage(_ signalMessage: SignalMessage, to destination: String, with timestamp: UInt64) -> AnyPromise { @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) } 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 // If that failes then fallback to storage server
// TODO: probably only send to p2p if user is online or we are pinging them if let p2pDetails = contactP2PDetails[destination], message.isPing || p2pDetails.isOnline {
// p2pDetails && (isPing || peerIsOnline)
if let p2pDetails = contactP2PDetails[destination] {
let targets = Promise.wrap([p2pDetails.target]) let targets = Promise.wrap([p2pDetails.target])
return sendMessage(message, targets: targets).recover { _ in return sendThroughStorageServer() } return sendMessage(message, targets: targets).recover { error -> Promise<Set<Promise<RawResponse>>> 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() return sendThroughStorageServer()

@ -8,10 +8,12 @@ NS_SWIFT_NAME(LokiAddressMessage)
- (instancetype)initInThread:(nullable TSThread *)thread - (instancetype)initInThread:(nullable TSThread *)thread
address:(NSString *)address address:(NSString *)address
port:(uint)port; port:(uint)port
isPing:(BOOL)isPing;
@property (nonatomic, readonly) NSString *address; @property (nonatomic, readonly) NSString *address;
@property (nonatomic, readonly) uint port; @property (nonatomic, readonly) uint port;
@property (nonatomic, readonly) BOOL isPing;
@end @end

@ -7,6 +7,7 @@
@property (nonatomic) NSString *address; @property (nonatomic) NSString *address;
@property (nonatomic) uint port; @property (nonatomic) uint port;
@property (nonatomic) BOOL isPing;
@end @end
@ -15,6 +16,7 @@
- (instancetype)initInThread:(nullable TSThread *)thread - (instancetype)initInThread:(nullable TSThread *)thread
address:(NSString *)address address:(NSString *)address
port:(uint)port port:(uint)port
isPing:(bool)isPing
{ {
self = [super initInThread:thread]; self = [super initInThread:thread];
if (!self) { if (!self) {
@ -23,6 +25,7 @@
_address = address; _address = address;
_port = port; _port = port;
_isPing = isPing;
return self; return self;
} }

@ -437,7 +437,7 @@ NS_ASSUME_NONNULL_BEGIN
if (contentProto.lokiAddressMessage) { if (contentProto.lokiAddressMessage) {
NSString *address = contentProto.lokiAddressMessage.ptpAddress; NSString *address = contentProto.lokiAddressMessage.ptpAddress;
uint32_t port = contentProto.lokiAddressMessage.ptpPort; 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) { if (contentProto.syncMessage) {

@ -44,6 +44,7 @@
#import "TSSocketManager.h" #import "TSSocketManager.h"
#import "TSThread.h" #import "TSThread.h"
#import "LKFriendRequestMessage.h" #import "LKFriendRequestMessage.h"
#import "LKAddressMessage.h"
#import <AxolotlKit/AxolotlExceptions.h> #import <AxolotlKit/AxolotlExceptions.h>
#import <AxolotlKit/CipherMessage.h> #import <AxolotlKit/CipherMessage.h>
#import <AxolotlKit/PreKeyBundle.h> #import <AxolotlKit/PreKeyBundle.h>
@ -1792,7 +1793,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
isSilent:false isSilent:false
isOnline:false isOnline:false
registrationId:0 registrationId:0
ttl:message.ttl]; ttl:message.ttl
isPing:false];
NSError *error; NSError *error;
NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error]; NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error];
@ -1879,6 +1881,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
BOOL isSilent = message.isSilent; BOOL isSilent = message.isSilent;
BOOL isOnline = message.isOnline; BOOL isOnline = message.isOnline;
LKAddressMessage *_Nullable addressMessage = [message as:[LKAddressMessage class]];
BOOL isPing = addressMessage != nil && addressMessage.isPing;
OWSMessageServiceParams *messageParams = OWSMessageServiceParams *messageParams =
[[OWSMessageServiceParams alloc] initWithType:messageType [[OWSMessageServiceParams alloc] initWithType:messageType
recipientId:recipientId recipientId:recipientId
@ -1887,7 +1892,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
isSilent:isSilent isSilent:isSilent
isOnline:isOnline isOnline:isOnline
registrationId:[cipher throws_remoteRegistrationId:transaction] registrationId:[cipher throws_remoteRegistrationId:transaction]
ttl:message.ttl]; ttl:message.ttl
isPing:isPing];
NSError *error; NSError *error;
NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error]; NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error];

@ -27,6 +27,9 @@ NS_ASSUME_NONNULL_BEGIN
// Loki: Message ttl // Loki: Message ttl
@property (nonatomic, readonly) uint ttl; @property (nonatomic, readonly) uint ttl;
// Loki: Wether this message is a p2p ping
@property (nonatomic, readonly) BOOL isPing;
- (instancetype)initWithType:(TSWhisperMessageType)type - (instancetype)initWithType:(TSWhisperMessageType)type
recipientId:(NSString *)destination recipientId:(NSString *)destination
device:(int)deviceId device:(int)deviceId
@ -34,7 +37,8 @@ NS_ASSUME_NONNULL_BEGIN
isSilent:(BOOL)isSilent isSilent:(BOOL)isSilent
isOnline:(BOOL)isOnline isOnline:(BOOL)isOnline
registrationId:(int)registrationId registrationId:(int)registrationId
ttl:(uint)ttl; ttl:(uint)ttl
isPing:(BOOL)isPing;
@end @end

@ -23,6 +23,7 @@ NS_ASSUME_NONNULL_BEGIN
isOnline:(BOOL)isOnline isOnline:(BOOL)isOnline
registrationId:(int)registrationId registrationId:(int)registrationId
ttl:(uint)ttl ttl:(uint)ttl
isPing:(BOOL)isPing
{ {
self = [super init]; self = [super init];
@ -38,6 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
_silent = isSilent; _silent = isSilent;
_online = isOnline; _online = isOnline;
_ttl = ttl; _ttl = ttl;
_isPing = isPing;
return self; return self;
} }

Loading…
Cancel
Save