diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index 8a3860443..441eb1bd6 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -7,7 +7,7 @@ CarthageVersion 0.33.0 OSXVersion - 10.14.6 + 10.15 WebRTCCommit 1445d719bf05280270e9f77576f80f973fd847f8 M73 diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m index d80c21ebb..b6f7c7ac1 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m @@ -709,23 +709,23 @@ NS_ASSUME_NONNULL_BEGIN NSError *error1; NSRegularExpression *regex1 = [[NSRegularExpression alloc] initWithPattern:@"@\\w*" options:0 error:&error1]; OWSAssertDebug(error1 == nil); - NSSet *knownUserIDs = LKAPI.userHexEncodedPublicKeyCache[threadID]; + NSSet *knownUserIDs = LKAPI.userIDCache[threadID]; NSMutableSet *mentions = [NSMutableSet new]; - NSTextCheckingResult *match = [regex1 firstMatchInString:text options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(0, text.length)]; - if (match != nil) { + NSTextCheckingResult *match1 = [regex1 firstMatchInString:text options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(0, text.length)]; + if (match1 != nil) { while (YES) { - NSString *userID = [[text substringWithRange:match.range] stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""]; + NSString *userID = [[text substringWithRange:match1.range] stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""]; NSUInteger matchEnd; if ([knownUserIDs containsObject:userID]) { NSString *userDisplayName = [Environment.shared.contactsManager attributedContactOrProfileNameForPhoneIdentifier:userID primaryFont:font secondaryFont:font].string; - text = [text stringByReplacingCharactersInRange:match.range withString:[NSString stringWithFormat:@"@%@", userDisplayName]]; - [mentions addObject:[NSValue valueWithRange:NSMakeRange(match.range.location, userDisplayName.length + 1)]]; - matchEnd = match.range.location + userDisplayName.length; + text = [text stringByReplacingCharactersInRange:match1.range withString:[NSString stringWithFormat:@"@%@", userDisplayName]]; + [mentions addObject:[NSValue valueWithRange:NSMakeRange(match1.range.location, userDisplayName.length + 1)]]; + matchEnd = match1.range.location + userDisplayName.length; } else { - matchEnd = match.range.location + match.range.length; + matchEnd = match1.range.location + match1.range.length; } - match = [regex1 firstMatchInString:text options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(matchEnd, text.length - matchEnd)]; - if (match == nil) { break; } + match1 = [regex1 firstMatchInString:text options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(matchEnd, text.length - matchEnd)]; + if (match1 == nil) { break; } } } NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text attributes:@{ NSFontAttributeName : font, NSForegroundColorAttributeName : textColor }]; @@ -740,11 +740,11 @@ NS_ASSUME_NONNULL_BEGIN NSError *error2; NSRegularExpression *regex2 = [[NSRegularExpression alloc] initWithPattern:[NSRegularExpression escapedPatternForString:searchableText] options:NSRegularExpressionCaseInsensitive error:&error2]; OWSAssertDebug(error2 == nil); - for (NSTextCheckingResult *match in + for (NSTextCheckingResult *match2 in [regex2 matchesInString:text options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(0, text.length)]) { - OWSAssertDebug(match.range.length >= ConversationSearchController.kMinimumSearchTextLength); - [attributedText addAttribute:NSBackgroundColorAttributeName value:UIColor.yellowColor range:match.range]; - [attributedText addAttribute:NSForegroundColorAttributeName value:UIColor.ows_blackColor range:match.range]; + OWSAssertDebug(match2.range.length >= ConversationSearchController.kMinimumSearchTextLength); + [attributedText addAttribute:NSBackgroundColorAttributeName value:UIColor.yellowColor range:match2.range]; + [attributedText addAttribute:NSForegroundColorAttributeName value:UIColor.ows_blackColor range:match2.range]; } } diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index ac3929a03..b168cacc9 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -523,6 +523,8 @@ typedef enum : NSUInteger { selector:@selector(reloadTimerDidFire) userInfo:nil repeats:YES]; + + [LKAPI populateUserIDCacheIfNeededFor:thread.uniqueId]; } - (void)dealloc diff --git a/SignalServiceKit/src/Loki/API/LokiAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI.swift index 217a1df13..c05d840ef 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI.swift @@ -3,6 +3,7 @@ import PromiseKit @objc(LKAPI) public final class LokiAPI : NSObject { private static var lastDeviceLinkUpdate: [String:Date] = [:] // Hex encoded public key to date + @objc static var userIDCache: [String:Set] = [:] // Thread ID to set of user hex encoded public keys // MARK: Convenience internal static let storage = OWSPrimaryStorage.shared() @@ -14,8 +15,11 @@ public final class LokiAPI : NSObject { private static let defaultTimeout: TimeInterval = 20 private static let longPollingTimeout: TimeInterval = 40 private static let deviceLinkUpdateInterval: TimeInterval = 8 * 60 - public static let defaultMessageTTL: UInt64 = 24 * 60 * 60 * 1000 + private static let receivedMessageHashValuesKey = "receivedMessageHashValuesKey" + private static let receivedMessageHashValuesCollection = "receivedMessageHashValuesCollection" + private static var userIDScanLimit: UInt = 4096 internal static var powDifficulty: UInt = 4 + public static let defaultMessageTTL: UInt64 = 24 * 60 * 60 * 1000 // MARK: Types public typealias RawResponse = Any @@ -260,10 +264,7 @@ public final class LokiAPI : NSObject { } } - // MARK: Message Caching - private static let receivedMessageHashValuesKey = "receivedMessageHashValuesKey" - private static let receivedMessageHashValuesCollection = "receivedMessageHashValuesCollection" - + // MARK: Message Hash Caching private static func getLastMessageHashValue(for target: LokiAPITarget) -> String? { var result: String? = nil // Uses a read/write connection because getting the last message hash value also removes expired messages as needed @@ -295,16 +296,29 @@ public final class LokiAPI : NSObject { } // MARK: User ID Caching - @objc static var userHexEncodedPublicKeyCache: [String:Set] = [:] // Thread ID to set of user hex encoded public keys - - @objc public static func cache(_ userHexEncodedPublicKey: String, for thread: String) { - if let cache = userHexEncodedPublicKeyCache[thread] { + @objc public static func cache(_ userHexEncodedPublicKey: String, for threadID: String) { + if let cache = userIDCache[threadID] { var mutableCache = cache mutableCache.insert(userHexEncodedPublicKey) - userHexEncodedPublicKeyCache[thread] = mutableCache + userIDCache[threadID] = mutableCache } else { - userHexEncodedPublicKeyCache[thread] = [ userHexEncodedPublicKey ] + userIDCache[threadID] = [ userHexEncodedPublicKey ] + } + } + + @objc public static func populateUserIDCacheIfNeeded(for threadID: String) { + guard userIDCache[threadID] == nil else { return } + var result: Set = [] + storage.dbReadWriteConnection.readWrite { transaction in + guard let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return } + let interactions = transaction.ext(TSMessageDatabaseViewExtensionName) as! YapDatabaseViewTransaction + interactions.enumerateKeysAndObjects(inGroup: threadID) { _, _, object, index, _ in + guard let message = object as? TSIncomingMessage, index < userIDScanLimit else { return } + result.insert(message.authorId) + } } + result.insert(userHexEncodedPublicKey) + userIDCache[threadID] = result } } diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 81f8965dd..905dbd254 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1414,6 +1414,7 @@ NS_ASSUME_NONNULL_BEGIN } // Loki: Cache the user hex encoded public key (for mentions) + [LKAPI populateUserIDCacheIfNeededFor:oldGroupThread.uniqueId]; [LKAPI cache:incomingMessage.authorId for:oldGroupThread.uniqueId]; [self finalizeIncomingMessage:incomingMessage