diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 1b4f31e50..45fd3174e 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -302,7 +302,7 @@ static NSTimeInterval launchStartedAt; error = [OWSPrimaryStorage migrateToSharedData]; } if (!error) { - error = [OWSProfileManager migrateToSharedData]; + error = [OWSUserProfile migrateToSharedData]; } if (!error) { error = [TSAttachmentStream migrateToSharedData]; diff --git a/Signal/src/environment/SignalApp.m b/Signal/src/environment/SignalApp.m index 4d95b7d8d..f33802f2b 100644 --- a/Signal/src/environment/SignalApp.m +++ b/Signal/src/environment/SignalApp.m @@ -234,7 +234,7 @@ NS_ASSUME_NONNULL_BEGIN [DDLog flushLog]; [OWSStorage resetAllStorage]; - [[OWSProfileManager sharedManager] resetProfileStorage]; + [OWSUserProfile resetProfileStorage]; [Environment.preferences clear]; [self clearAllNotifications]; diff --git a/SignalMessaging/profiles/OWSProfileManager.h b/SignalMessaging/profiles/OWSProfileManager.h index d1b228d98..18a23b8b5 100644 --- a/SignalMessaging/profiles/OWSProfileManager.h +++ b/SignalMessaging/profiles/OWSProfileManager.h @@ -22,10 +22,6 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter; + (instancetype)sharedManager; -- (void)resetProfileStorage; - -+ (nullable NSError *)migrateToSharedData; - #pragma mark - Local Profile // These two methods should only be called from the main thread. diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index fcb94d05a..7d106790c 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -224,9 +224,6 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; OWSUserProfile *userProfile = self.localUserProfile; OWSAssert(userProfile); - NSString *_Nullable oldAvatarFilePath = - [self profileAvatarFilepathWithFilename:userProfile.avatarFileName]; - [userProfile updateWithProfileName:profileName avatarUrlPath:avatarUrlPath avatarFileName:avatarFileName @@ -236,8 +233,6 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; [self updateProfileAvatarCache:avatarImage filename:avatarFileName]; } - [OWSFileSystem deleteFileIfExists:oldAvatarFilePath]; - successBlock(); }]; } @@ -309,8 +304,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; OWSAssert(data); if (data) { NSString *fileName = [[NSUUID UUID].UUIDString stringByAppendingPathExtension:@"jpg"]; - NSString *_Nullable filePath = [self profileAvatarFilepathWithFilename:fileName]; - OWSAssert(filePath); + NSString *filePath = [OWSUserProfile profileAvatarFilepathWithFilename:fileName]; BOOL success = [data writeToFile:filePath atomically:YES]; OWSAssert(success); if (success) { @@ -363,13 +357,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; // the profile avatar blank, etc. void (^clearLocalAvatar)(void) = ^{ OWSUserProfile *userProfile = self.localUserProfile; - NSString *_Nullable oldAvatarFilePath = [self profileAvatarFilepathWithFilename:userProfile.avatarFileName]; - [userProfile updateWithAvatarUrlPath:nil - avatarFileName:nil - dbConnection:self.dbConnection - completion:^{ - [OWSFileSystem deleteFileIfExists:oldAvatarFilePath]; - }]; + [userProfile updateWithAvatarUrlPath:nil avatarFileName:nil dbConnection:self.dbConnection completion:nil]; }; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @@ -561,12 +549,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; - (void)regenerateLocalProfile { OWSUserProfile *userProfile = self.localUserProfile; - NSString *_Nullable oldAvatarFilePath = [self profileAvatarFilepathWithFilename:userProfile.avatarFileName]; - [userProfile clearWithProfileKey:[OWSAES256Key generateRandomKey] - dbConnection:self.dbConnection - completion:^{ - [OWSFileSystem deleteFileIfExists:oldAvatarFilePath]; - }]; + [userProfile clearWithProfileKey:[OWSAES256Key generateRandomKey] dbConnection:self.dbConnection completion:nil]; } - (void)addUserToProfileWhitelist:(NSString *)recipientId @@ -744,12 +727,9 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; return; } - NSString *_Nullable oldAvatarFilePath = [self profileAvatarFilepathWithFilename:userProfile.avatarFileName]; [userProfile clearWithProfileKey:profileKey dbConnection:self.dbConnection completion:^{ - [OWSFileSystem deleteFileIfExists:oldAvatarFilePath]; - dispatch_async(dispatch_get_main_queue(), ^(void) { [ProfileFetcherJob runWithRecipientId:recipientId networkManager:self.networkManager @@ -837,8 +817,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; OWSAES256Key *profileKeyAtStart = userProfile.profileKey; NSString *fileName = [[NSUUID UUID].UUIDString stringByAppendingPathExtension:@"jpg"]; - NSString *_Nullable filePath = [self profileAvatarFilepathWithFilename:fileName]; - OWSAssert(filePath); + NSString *filePath = [OWSUserProfile profileAvatarFilepathWithFilename:fileName]; @synchronized(self.currentAvatarDownloads) { @@ -895,13 +874,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; } else { [self updateProfileAvatarCache:image filename:fileName]; - NSString *_Nullable oldAvatarFilePath = - [self profileAvatarFilepathWithFilename:latestUserProfile.avatarFileName]; - [latestUserProfile updateWithAvatarFileName:fileName - dbConnection:self.dbConnection - completion:^{ - [OWSFileSystem deleteFileIfExists:oldAvatarFilePath]; - }]; + [latestUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:nil]; } // If we're updating the profile that corresponds to our local number, @@ -911,13 +884,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; OWSUserProfile *localUserProfile = self.localUserProfile; OWSAssert(localUserProfile); - NSString *_Nullable oldAvatarFilePath = - [self profileAvatarFilepathWithFilename:localUserProfile.avatarFileName]; - [localUserProfile updateWithAvatarFileName:fileName - dbConnection:self.dbConnection - completion:^{ - [OWSFileSystem deleteFileIfExists:oldAvatarFilePath]; - }]; + [localUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:nil]; [self updateProfileAvatarCache:image filename:fileName]; } @@ -968,15 +935,10 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; NSString *_Nullable profileName = [self decryptProfileNameData:profileNameEncrypted profileKey:userProfile.profileKey]; - { - NSString *_Nullable oldAvatarFilePath = [self profileAvatarFilepathWithFilename:userProfile.avatarFileName]; - [userProfile updateWithProfileName:profileName - avatarUrlPath:avatarUrlPath - dbConnection:self.dbConnection - completion:^{ - [OWSFileSystem deleteFileIfExists:oldAvatarFilePath]; - }]; - } + [userProfile updateWithProfileName:profileName + avatarUrlPath:avatarUrlPath + dbConnection:self.dbConnection + completion:nil]; // If we're updating the profile that corresponds to our local number, // update the local profile as well. @@ -985,15 +947,10 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; OWSUserProfile *localUserProfile = self.localUserProfile; OWSAssert(localUserProfile); - NSString *_Nullable oldAvatarFilePath = - [self profileAvatarFilepathWithFilename:localUserProfile.avatarFileName]; - [localUserProfile updateWithProfileName:profileName avatarUrlPath:avatarUrlPath dbConnection:self.dbConnection - completion:^{ - [OWSFileSystem deleteFileIfExists:oldAvatarFilePath]; - }]; + completion:nil]; } // Whenever we change avatarUrlPath, OWSUserProfile clears avatarFileName. @@ -1114,22 +1071,11 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; #pragma mark - Avatar Disk Cache -- (nullable NSString *)profileAvatarFilepathWithFilename:(nullable NSString *)filename -{ - if (!filename) { - return nil; - } - OWSAssert(filename.length > 0); - - return [self.profileAvatarsDirPath stringByAppendingPathComponent:filename]; -} - - (nullable NSData *)loadProfileDataWithFilename:(NSString *)filename { OWSAssert(filename.length > 0); - NSString *_Nullable filePath = [self profileAvatarFilepathWithFilename:filename]; - OWSAssert(filePath); + NSString *filePath = [OWSUserProfile profileAvatarFilepathWithFilename:filename]; return [NSData dataWithContentsOfFile:filePath]; } @@ -1172,49 +1118,6 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; } } -+ (NSString *)legacyProfileAvatarsDirPath -{ - return [[OWSFileSystem appDocumentDirectoryPath] stringByAppendingPathComponent:@"ProfileAvatars"]; -} - -+ (NSString *)sharedDataProfileAvatarsDirPath -{ - return [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"ProfileAvatars"]; -} - -+ (nullable NSError *)migrateToSharedData -{ - DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); - - return [OWSFileSystem moveAppFilePath:self.legacyProfileAvatarsDirPath - sharedDataFilePath:self.sharedDataProfileAvatarsDirPath]; -} - -- (NSString *)profileAvatarsDirPath -{ - static NSString *profileAvatarsDirPath = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - profileAvatarsDirPath = OWSProfileManager.sharedDataProfileAvatarsDirPath; - - [OWSFileSystem ensureDirectoryExists:profileAvatarsDirPath]; - }); - return profileAvatarsDirPath; -} - -// TODO: We may want to clean up this directory in the "orphan cleanup" logic. - -- (void)resetProfileStorage -{ - OWSAssertIsOnMainThread(); - - NSError *error; - [[NSFileManager defaultManager] removeItemAtPath:[self profileAvatarsDirPath] error:&error]; - if (error) { - DDLogError(@"Failed to delete database: %@", error.description); - } -} - #pragma mark - User Interface - (void)presentAddThreadToProfileWhitelist:(TSThread *)thread diff --git a/SignalMessaging/profiles/OWSUserProfile.h b/SignalMessaging/profiles/OWSUserProfile.h index 35402fff1..1d68916aa 100644 --- a/SignalMessaging/profiles/OWSUserProfile.h +++ b/SignalMessaging/profiles/OWSUserProfile.h @@ -65,6 +65,13 @@ extern NSString *const kLocalProfileUniqueId; dbConnection:(YapDatabaseConnection *)dbConnection completion:(nullable OWSUserProfileCompletion)completion; +#pragma mark - Profile Avatars Directory + ++ (NSString *)profileAvatarFilepathWithFilename:(NSString *)filename; ++ (nullable NSError *)migrateToSharedData; ++ (NSString *)profileAvatarsDirPath; ++ (void)resetProfileStorage; + @end NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/profiles/OWSUserProfile.m b/SignalMessaging/profiles/OWSUserProfile.m index 760573c4b..180ab4925 100644 --- a/SignalMessaging/profiles/OWSUserProfile.m +++ b/SignalMessaging/profiles/OWSUserProfile.m @@ -8,6 +8,7 @@ #import #import #import +#import #import #import #import @@ -37,6 +38,7 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; @implementation OWSUserProfile @synthesize avatarUrlPath = _avatarUrlPath; +@synthesize avatarFileName = _avatarFileName; @synthesize profileName = _profileName; + (NSString *)collection @@ -113,11 +115,38 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; if (didChange) { // If the avatarURL changed, the avatarFileName can't be valid. // Clear it. + self.avatarFileName = nil; } } } +- (nullable NSString *)avatarFileName +{ + @synchronized(self) { + return _avatarFileName; + } +} + +- (void)setAvatarFileName:(nullable NSString *)avatarFileName +{ + @synchronized(self) { + BOOL didChange = ![NSObject isNullableObject:_avatarFileName equalTo:avatarFileName]; + if (!didChange) { + return; + } + + if (_avatarFileName) { + NSString *oldAvatarFilePath = [OWSUserProfile profileAvatarFilepathWithFilename:_avatarFileName]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [OWSFileSystem deleteFileIfExists:oldAvatarFilePath]; + }); + } + + _avatarFileName = avatarFileName; + } +} + #pragma mark - Update With... Methods // Similar in spirit to [TSYapDatabaseObject applyChangeToSelfAndLatestCopy], @@ -356,6 +385,58 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId"; } } +#pragma mark - Profile Avatars Directory + ++ (NSString *)profileAvatarFilepathWithFilename:(NSString *)filename +{ + OWSAssert(filename.length > 0); + + return [self.profileAvatarsDirPath stringByAppendingPathComponent:filename]; +} + ++ (NSString *)legacyProfileAvatarsDirPath +{ + return [[OWSFileSystem appDocumentDirectoryPath] stringByAppendingPathComponent:@"ProfileAvatars"]; +} + ++ (NSString *)sharedDataProfileAvatarsDirPath +{ + return [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"ProfileAvatars"]; +} + ++ (nullable NSError *)migrateToSharedData +{ + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + return [OWSFileSystem moveAppFilePath:self.legacyProfileAvatarsDirPath + sharedDataFilePath:self.sharedDataProfileAvatarsDirPath]; +} + ++ (NSString *)profileAvatarsDirPath +{ + static NSString *profileAvatarsDirPath = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + profileAvatarsDirPath = self.sharedDataProfileAvatarsDirPath; + + [OWSFileSystem ensureDirectoryExists:profileAvatarsDirPath]; + }); + return profileAvatarsDirPath; +} + +// TODO: We may want to clean up this directory in the "orphan cleanup" logic. + ++ (void)resetProfileStorage +{ + OWSAssertIsOnMainThread(); + + NSError *error; + [[NSFileManager defaultManager] removeItemAtPath:[self profileAvatarsDirPath] error:&error]; + if (error) { + DDLogError(@"Failed to delete database: %@", error.description); + } +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Util/OWSFileSystem.h b/SignalServiceKit/src/Util/OWSFileSystem.h index 5ed5bc97b..b56e9f49d 100644 --- a/SignalServiceKit/src/Util/OWSFileSystem.h +++ b/SignalServiceKit/src/Util/OWSFileSystem.h @@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN + (BOOL)deleteFile:(NSString *)filePath; -+ (BOOL)deleteFileIfExists:(nullable NSString *)filePath; ++ (BOOL)deleteFileIfExists:(NSString *)filePath; + (NSArray *_Nullable)allFilesInDirectoryRecursive:(NSString *)dirPath error:(NSError **)error; diff --git a/SignalServiceKit/src/Util/OWSFileSystem.m b/SignalServiceKit/src/Util/OWSFileSystem.m index 12e67d775..88c53f091 100644 --- a/SignalServiceKit/src/Util/OWSFileSystem.m +++ b/SignalServiceKit/src/Util/OWSFileSystem.m @@ -253,11 +253,8 @@ NS_ASSUME_NONNULL_BEGIN return YES; } -+ (BOOL)deleteFileIfExists:(nullable NSString *)filePath ++ (BOOL)deleteFileIfExists:(NSString *)filePath { - if (!filePath) { - return YES; - } if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) { return YES; }