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