Signal-iOS/SignalMessaging/profiles/OWSProfileManager.h
George Nachman 36119e4367 Introduce Refinery to help batch DB queries.
This PR is the first in a series that will
optimize looking up full names of group members.

The biggest source of slowness when opening a
group chat is looking up the full names of group
members in the search for duplicates. It is slow
because it requires multiple db queries for each
member.

The characterstic feature of this algorithm is the
iterative process of assigning names to signal
addresses. For example, some contacts' names may
be cached. For others, their profiles must be
fetched. For those without profiles, their phone
numbers must be formatted (which requires fetching
SignalAccounts). For those without phone numbers,
their user names must be formatted.

This PR creates a class called Refinery. Its job
is to make it easy to assign values to keys
through multiple passes, where each pass may
succeed only for a subset of keys.

This is useful because we will eventually issue a
single DB query for some of these passes.
2022-03-04 10:44:07 -08:00

167 lines
6.3 KiB
Objective-C

//
// Copyright (c) 2022 Open Whisper Systems. All rights reserved.
//
#import <SignalServiceKit/ProfileManagerProtocol.h>
NS_ASSUME_NONNULL_BEGIN
extern const NSUInteger kOWSProfileManager_MaxAvatarDiameterPixels;
extern const NSString *kNSNotificationKey_UserProfileWriter;
@class MessageSender;
@class OWSAES256Key;
@class OWSUserProfile;
@class SDSAnyReadTransaction;
@class SDSAnyWriteTransaction;
@class SDSDatabaseStorage;
@class SDSKeyValueStore;
@class SignalServiceAddress;
@class TSThread;
typedef void (^ProfileManagerFailureBlock)(NSError *error);
@interface OWSProfileSnapshot : NSObject
@property (nonatomic, readonly, nullable) NSString *givenName;
@property (nonatomic, readonly, nullable) NSString *familyName;
@property (nonatomic, readonly, nullable) NSString *fullName;
@property (nonatomic, readonly, nullable) NSString *bio;
@property (nonatomic, readonly, nullable) NSString *bioEmoji;
@property (nonatomic, readonly, nullable) NSString *username;
@property (nonatomic, readonly, nullable) NSData *avatarData;
@property (nonatomic, readonly, nullable) NSArray<OWSUserProfileBadgeInfo *> *profileBadgeInfo;
@end
#pragma mark -
// This class can be safely accessed and used from any thread.
@interface OWSProfileManager : NSObject <ProfileManagerProtocol>
@property (nonatomic, readonly) SDSKeyValueStore *whitelistedPhoneNumbersStore;
@property (nonatomic, readonly) SDSKeyValueStore *whitelistedUUIDsStore;
@property (nonatomic, readonly) SDSKeyValueStore *whitelistedGroupsStore;
@property (nonatomic, readonly) BadgeStore *badgeStore;
// This property is used by the Swift extension to ensure that
// only one profile update is in flight at a time. It should
// only be accessed on the main thread.
@property (nonatomic) BOOL isUpdatingProfileOnService;
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithDatabaseStorage:(SDSDatabaseStorage *)databaseStorage NS_DESIGNATED_INITIALIZER;
#pragma mark - Local Profile
- (nullable OWSUserProfile *)getLocalUserProfileWithTransaction:(SDSAnyReadTransaction *)transaction;
// These two methods should only be called from the main thread.
- (OWSAES256Key *)localProfileKey;
// localUserProfileExists is true if there is _ANY_ local profile.
- (BOOL)localProfileExistsWithTransaction:(SDSAnyReadTransaction *)transaction;
// hasLocalProfile is true if there is a local profile with a name or avatar.
- (BOOL)hasLocalProfile;
- (nullable NSString *)localGivenName;
- (nullable NSString *)localFamilyName;
- (nullable NSString *)localFullName;
- (nullable NSString *)localUsername;
- (nullable UIImage *)localProfileAvatarImage;
- (nullable NSData *)localProfileAvatarData;
- (OWSProfileSnapshot *)localProfileSnapshotWithShouldIncludeAvatar:(BOOL)shouldIncludeAvatar
NS_SWIFT_NAME(localProfileSnapshot(shouldIncludeAvatar:));
- (void)updateLocalUsername:(nullable NSString *)username
userProfileWriter:(UserProfileWriter)userProfileWriter
transaction:(SDSAnyWriteTransaction *)transaction;
- (BOOL)isProfileNameTooLong:(nullable NSString *)profileName;
+ (NSData *)avatarDataForAvatarImage:(UIImage *)image;
- (void)fetchLocalUsersProfile;
// The completions are invoked on the main thread.
- (void)fetchProfileForUsername:(NSString *)username
success:(void (^)(SignalServiceAddress *))successHandler
notFound:(void (^)(void))notFoundHandler
failure:(void (^)(NSError *))failureHandler;
#pragma mark - Local Profile Updates
- (void)writeAvatarToDiskWithData:(NSData *)avatarData
success:(void (^)(NSString *fileName))successBlock
failure:(ProfileManagerFailureBlock)failureBlock;
// OWSUserProfile is a private implementation detail of the profile manager.
//
// Only use this method in profile manager methods on the swift extension.
- (OWSUserProfile *)localUserProfile;
#pragma mark - Profile Whitelist
// These methods are for debugging.
- (void)clearProfileWhitelist;
- (void)removeThreadFromProfileWhitelist:(TSThread *)thread;
- (void)logProfileWhitelist;
- (void)debug_regenerateLocalProfileWithSneakyTransaction;
- (void)setLocalProfileKey:(OWSAES256Key *)key
userProfileWriter:(UserProfileWriter)userProfileWriter
transaction:(SDSAnyWriteTransaction *)transaction;
- (void)setContactAddresses:(NSArray<SignalServiceAddress *> *)contactAddresses;
#pragma mark - Other User's Profiles
// This method is for debugging.
- (void)logUserProfiles;
- (nullable NSString *)unfilteredGivenNameForAddress:(SignalServiceAddress *)address
transaction:(SDSAnyReadTransaction *)transaction;
- (nullable NSString *)givenNameForAddress:(SignalServiceAddress *)address
transaction:(SDSAnyReadTransaction *)transaction;
- (nullable NSString *)unfilteredFamilyNameForAddress:(SignalServiceAddress *)address
transaction:(SDSAnyReadTransaction *)transaction;
- (nullable NSString *)familyNameForAddress:(SignalServiceAddress *)address
transaction:(SDSAnyReadTransaction *)transaction;
- (nullable NSPersonNameComponents *)nameComponentsForAddress:(SignalServiceAddress *)address
transaction:(SDSAnyReadTransaction *)transaction;
- (nullable UIImage *)profileAvatarForAddress:(SignalServiceAddress *)address
transaction:(SDSAnyReadTransaction *)transaction;
- (nullable NSString *)usernameForAddress:(SignalServiceAddress *)address
transaction:(SDSAnyReadTransaction *)transaction;
- (nullable NSString *)profileBioForDisplayForAddress:(SignalServiceAddress *)address
transaction:(SDSAnyReadTransaction *)transaction;
#pragma mark - Clean Up
+ (NSSet<NSString *> *)allProfileAvatarFilePathsWithTransaction:(SDSAnyReadTransaction *)transaction;
#pragma mark -
// This method is only exposed for usage by the Swift extensions.
- (NSString *)generateAvatarFilename;
- (NSString *)groupKeyForGroupId:(NSData *)groupId;
#ifdef DEBUG
+ (void)discardAllProfileKeysWithTransaction:(SDSAnyWriteTransaction *)transaction;
- (void)logLocalProfile;
#endif
@end
NS_ASSUME_NONNULL_END