Pre-populate user ID cache as needed

This commit is contained in:
Niels Andriesse 2019-10-09 10:37:44 +11:00
parent a1d40a5933
commit 4d5ca1ce66
5 changed files with 43 additions and 26 deletions

View file

@ -7,7 +7,7 @@
<key>CarthageVersion</key>
<string>0.33.0</string>
<key>OSXVersion</key>
<string>10.14.6</string>
<string>10.15</string>
<key>WebRTCCommit</key>
<string>1445d719bf05280270e9f77576f80f973fd847f8 M73</string>
</dict>

View file

@ -709,23 +709,23 @@ NS_ASSUME_NONNULL_BEGIN
NSError *error1;
NSRegularExpression *regex1 = [[NSRegularExpression alloc] initWithPattern:@"@\\w*" options:0 error:&error1];
OWSAssertDebug(error1 == nil);
NSSet<NSString *> *knownUserIDs = LKAPI.userHexEncodedPublicKeyCache[threadID];
NSSet<NSString *> *knownUserIDs = LKAPI.userIDCache[threadID];
NSMutableSet<NSValue *> *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];
}
}

View file

@ -523,6 +523,8 @@ typedef enum : NSUInteger {
selector:@selector(reloadTimerDidFire)
userInfo:nil
repeats:YES];
[LKAPI populateUserIDCacheIfNeededFor:thread.uniqueId];
}
- (void)dealloc

View file

@ -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<String>] = [:] // 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,17 +296,30 @@ public final class LokiAPI : NSObject {
}
// MARK: User ID Caching
@objc static var userHexEncodedPublicKeyCache: [String:Set<String>] = [:] // 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<String> = []
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
}
}
// MARK: Error Handling

View file

@ -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