Show when a message was sent using P2P

This commit is contained in:
Niels Andriesse 2019-05-27 15:06:54 +10:00
parent 209996f86d
commit 35f2354327
7 changed files with 50 additions and 33 deletions

View File

@ -218,7 +218,18 @@ NS_ASSUME_NONNULL_BEGIN
timestampLabelText = [DateUtil formatMessageTimestamp:viewItem.interaction.timestamp];
}
self.timestampLabel.text = timestampLabelText.localizedUppercaseString;
TSMessage *message = (TSMessage *)[viewItem.interaction as:TSMessage.class];
if (message != nil && message.isP2P) {
NSString *string = [timestampLabelText.localizedUppercaseString stringByAppendingString:@" · P2P"];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string];
NSRange range = [string rangeOfString:@"P2P"];
[attributedString beginEditing];
[attributedString addAttribute:NSFontAttributeName value:[UIFont.ows_dynamicTypeCaption1Font ows_bold] range:range];
[attributedString endEditing];
[self.timestampLabel setAttributedText:attributedString];
} else {
[self.timestampLabel setText:timestampLabelText.localizedUppercaseString];
}
}
- (CGSize)measureWithConversationViewItem:(id<ConversationViewItem>)viewItem

View File

@ -53,7 +53,7 @@ import PromiseKit
}.map { Set($0) }.retryingIfNeeded(maxRetryCount: maxRetryCount)
}
public static func sendSignalMessage(_ signalMessage: SignalMessage, to destination: String, with timestamp: UInt64) -> Promise<Set<RawResponsePromise>> {
public static func sendSignalMessage(_ signalMessage: SignalMessage, to destination: String, with timestamp: UInt64, onP2PSuccess: @escaping () -> Void) -> Promise<Set<RawResponsePromise>> {
guard let lokiMessage = Message.from(signalMessage: signalMessage, with: timestamp) else { return Promise(error: Error.messageConversionFailed) }
let destination = lokiMessage.destination
func sendLokiMessage(_ lokiMessage: Message, to target: Target) -> RawResponsePromise {
@ -65,12 +65,13 @@ import PromiseKit
let swarmPromise = getTargetSnodes(for: destination)
return when(fulfilled: powPromise, swarmPromise).map { lokiMessageWithPoW, swarm in
return Set(swarm.map { sendLokiMessage(lokiMessageWithPoW, to: $0) })
}
}.retryingIfNeeded(maxRetryCount: maxRetryCount)
}
if let p2pState = LokiP2PManager.getState(for: destination), (lokiMessage.isPing || p2pState.isOnline) {
let target = Target(address: p2pState.address, port: p2pState.port)
if let peer = LokiP2PManager.getInfo(for: destination), (lokiMessage.isPing || peer.isOnline) {
let target = Target(address: peer.address, port: peer.port)
return Promise.value([ target ]).mapValues { sendLokiMessage(lokiMessage, to: $0) }.map { Set($0) }.retryingIfNeeded(maxRetryCount: maxRetryCount).get { _ in
LokiP2PManager.markOnline(destination)
onP2PSuccess()
}.recover { error -> Promise<Set<RawResponsePromise>> in
LokiP2PManager.markOffline(destination)
if lokiMessage.isPing {
@ -82,16 +83,16 @@ import PromiseKit
throw error
}
}
return sendLokiMessageUsingSwarmAPI().retryingIfNeeded(maxRetryCount: maxRetryCount)
return sendLokiMessageUsingSwarmAPI()
}
} else {
return sendLokiMessageUsingSwarmAPI().retryingIfNeeded(maxRetryCount: maxRetryCount)
return sendLokiMessageUsingSwarmAPI()
}
}
// 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, with: timestamp).mapValues { AnyPromise.from($0) }.map { Set($0) }
@objc public static func objc_sendSignalMessage(_ signalMessage: SignalMessage, to destination: String, with timestamp: UInt64, onP2PSuccess: @escaping () -> Void) -> AnyPromise {
let promise = sendSignalMessage(signalMessage, to: destination, with: timestamp, onP2PSuccess: onP2PSuccess).mapValues { AnyPromise.from($0) }.map { Set($0) }
return AnyPromise.from(promise)
}

View File

@ -8,7 +8,7 @@
private static let offlinePingTime = 2 * kMinuteInterval
/// A p2p state struct
internal struct P2PState {
internal struct PeerInfo {
var address: String
var port: UInt16
var isOnline: Bool
@ -20,7 +20,7 @@
private static var ourP2PAddress: LokiAPI.Target? = nil
/// This is where we store the p2p details of our contacts
private static var contactP2PStates = [String:P2PState]()
private static var peerInfo = [String:PeerInfo]()
// MARK: - Public functions
@ -46,12 +46,12 @@
}
guard let thread = contactThread else {
Logger.warn("[Loki][Ping] Failed to fetch thread for \(pubKey).")
Logger.warn("[Loki] Failed to fetch thread when attempting to ping: \(pubKey).")
return
}
guard let message = lokiAddressMessage(for: thread, isPing: true) else {
Logger.warn("[Loki][Ping] Failed to build ping message for \(pubKey).")
guard let message = createLokiAddressMessage(for: thread, isPing: true) else {
Logger.warn("[Loki] Failed to build ping message for \(pubKey).")
return
}
@ -77,8 +77,8 @@
///
/// - Parameter pubKey: The contact hex pubkey
/// - Returns: The P2P Details or nil if they don't exist
internal static func getState(for hexEncodedPublicKey: String) -> P2PState? {
return contactP2PStates[hexEncodedPublicKey]
internal static func getInfo(for hexEncodedPublicKey: String) -> PeerInfo? {
return peerInfo[hexEncodedPublicKey]
}
/// Get the `LokiAddressMessage` for the given thread.
@ -86,7 +86,7 @@
/// - Parameter thread: The contact thread.
/// - Returns: The `LokiAddressMessage` for that thread.
@objc public static func onlineBroadcastMessage(forThread thread: TSThread) -> LokiAddressMessage? {
return lokiAddressMessage(for: thread, isPing: false)
return createLokiAddressMessage(for: thread, isPing: false)
}
/// Handle P2P logic when we receive a `LokiAddressMessage`
@ -101,17 +101,17 @@
let timerDuration = pubKey < ourHexEncodedPubKey ? 1 * kMinuteInterval : 2 * kMinuteInterval
// Get out current contact details
let oldContactDetails = contactP2PStates[pubKey]
let oldContactInfo = peerInfo[pubKey]
// Set the new contact details
// A contact is always assumed to be offline unless the specific conditions below are met
let details = P2PState(address: address, port: port, isOnline: false, timerDuration: timerDuration, pingTimer: nil)
contactP2PStates[pubKey] = details
let info = PeerInfo(address: address, port: port, isOnline: false, timerDuration: timerDuration, pingTimer: nil)
peerInfo[pubKey] = info
// Set up our checks
let oldContactExists = oldContactDetails != nil
let wasOnline = oldContactDetails?.isOnline ?? false
let p2pDetailsMatch = oldContactDetails?.address == address && oldContactDetails?.port == port
let oldContactExists = oldContactInfo != nil
let wasOnline = oldContactInfo?.isOnline ?? false
let isPeerInfoMatching = oldContactInfo?.address == address && oldContactInfo?.port == port
/*
We need to check if we should ping the user.
@ -121,7 +121,7 @@
- The old contact was set as `Online`
- The new p2p details match the old one
*/
if oldContactExists && receivedThroughP2P && wasOnline && p2pDetailsMatch {
if oldContactExists && receivedThroughP2P && wasOnline && isPeerInfoMatching {
setOnline(true, forContact: pubKey)
return
}
@ -153,16 +153,16 @@
@objc internal static func setOnline(_ isOnline: Bool, forContact pubKey: String) {
// Make sure we are on the main thread
DispatchQueue.main.async {
guard var details = contactP2PStates[pubKey] else { return }
guard var info = peerInfo[pubKey] else { return }
let interval = isOnline ? details.timerDuration : offlinePingTime
let interval = isOnline ? info.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
info.pingTimer?.invalidate()
info.pingTimer = WeakTimer.scheduledTimer(timeInterval: interval, target: self, userInfo: nil, repeats: true) { _ in ping(contact: pubKey) }
info.isOnline = isOnline
contactP2PStates[pubKey] = details
peerInfo[pubKey] = info
}
}
@ -194,7 +194,7 @@
return friendThreadIds.compactMap { TSContactThread.fetch(uniqueId: $0) }
}
private static func lokiAddressMessage(for thread: TSThread, isPing: Bool) -> LokiAddressMessage? {
private static func createLokiAddressMessage(for thread: TSThread, isPing: Bool) -> LokiAddressMessage? {
guard let ourAddress = ourP2PAddress else {
Logger.error("P2P Address not set")
return nil

View File

@ -1,3 +1,2 @@
// This is basically OWSMessageServiceParams
public typealias SignalMessage = [String:Any]

View File

@ -45,6 +45,7 @@ typedef NS_ENUM(NSInteger, LKMessageFriendRequestStatus) {
@property (nonatomic) uint64_t friendRequestExpiresAt;
@property (nonatomic, readonly) BOOL isFriendRequest;
@property (nonatomic, readonly) BOOL hasFriendRequestStatusMessage;
@property (nonatomic) BOOL isP2P;
// ========
- (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE;

View File

@ -1371,6 +1371,8 @@ NS_ASSUME_NONNULL_BEGIN
linkPreview:linkPreview
serverTimestamp:serverTimestamp
wasReceivedByUD:wasReceivedByUD];
if (envelope.isPtpMessage) { incomingMessage.isP2P = YES; }
NSArray<TSAttachmentPointer *> *attachmentPointers =
[TSAttachmentPointer attachmentPointersFromProtos:dataMessage.attachments
@ -1443,6 +1445,8 @@ NS_ASSUME_NONNULL_BEGIN
serverTimestamp:serverTimestamp
wasReceivedByUD:wasReceivedByUD];
if (envelope.isPtpMessage) { incomingMessage.isP2P = YES; }
NSArray<TSAttachmentPointer *> *attachmentPointers =
[TSAttachmentPointer attachmentPointersFromProtos:dataMessage.attachments albumMessage:incomingMessage];
for (TSAttachmentPointer *pointer in attachmentPointers) {

View File

@ -1117,6 +1117,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
}
}];
// Convenience
void (^onP2PSuccess)() = ^() { message.isP2P = YES; };
void (^handleError)(NSError *error) = ^(NSError *error) {
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
// Update the thread if needed
@ -1144,7 +1145,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[self messageSendDidFail:messageSend deviceMessages:deviceMessages statusCode:statusCode error:error responseData:responseData];
};
// Convert the message to a Loki message and send it using the Loki API
[[LokiAPI objc_sendSignalMessage:signalMessage to:recipient.recipientId with:message.timestamp]
[[LokiAPI objc_sendSignalMessage:signalMessage to:recipient.recipientId with:message.timestamp onP2PSuccess:onP2PSuccess]
.thenOn(OWSDispatch.sendingQueue, ^(id result) {
NSSet<AnyPromise *> *promises = (NSSet<AnyPromise *> *)result;
__block BOOL isSuccess = NO;