Ignore local profile restore failures.

pull/1/head
Matthew Chen 6 years ago
parent c3704931ec
commit 0a4f004935

@ -141,14 +141,17 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe
// These items should be downloaded immediately.
NSMutableArray<OWSBackupFragment *> *allItems = [NSMutableArray new];
[allItems addObjectsFromArray:self.databaseItems];
if (self.manifest.localProfileAvatarItem) {
[allItems addObject:self.manifest.localProfileAvatarItem];
}
// Make a copy of the blockingItems before we add
// the attachment items.
// the optional items.
NSArray<OWSBackupFragment *> *blockingItems = [allItems copy];
// Local profile avatars are optional in the sense that if their
// download fails, we want to proceed with the import.
if (self.manifest.localProfileAvatarItem) {
[allItems addObject:self.manifest.localProfileAvatarItem];
}
// Attachment items can be downloaded later;
// they will can be lazy-restored.
[allItems addObjectsFromArray:self.attachmentsItems];
@ -224,13 +227,35 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe
AnyPromise *promise = [AnyPromise promiseWithValue:@(1)];
for (OWSBackupFragment *item in items) {
promise = promise.thenInBackground(^{
CGFloat progress = (recordCount > 0 ? ((recordCount - items.count) / (CGFloat)recordCount) : 0.f);
[self updateProgressWithDescription:NSLocalizedString(@"BACKUP_IMPORT_PHASE_DOWNLOAD",
@"Indicates that the backup import data is being downloaded.")
progress:@(progress)];
});
promise = promise
.thenInBackground(^{
CGFloat progress
= (recordCount > 0 ? ((recordCount - items.count) / (CGFloat)recordCount) : 0.f);
[self updateProgressWithDescription:
NSLocalizedString(@"BACKUP_IMPORT_PHASE_DOWNLOAD",
@"Indicates that the backup import data is being downloaded.")
progress:@(progress)];
})
.thenInBackground(^{
return [self downloadFileFromCloud:item ignoreErrors:NO];
});
}
return promise;
}
- (AnyPromise *)downloadFileFromCloud:(OWSBackupFragment *)item ignoreErrors:(BOOL)ignoreErrors
{
OWSAssertDebug(item);
OWSLogVerbose(@"");
if (self.isComplete) {
// Job was aborted.
return [AnyPromise promiseWithValue:OWSBackupErrorWithDescription(@"Backup import no longer active.")];
}
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
// TODO: Use a predictable file path so that multiple "import backup" attempts
// will leverage successful file downloads from previous attempts.
//
@ -243,23 +268,51 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe
item.downloadFilePath = tempFilePath;
continue;
return resolve(@(1));
}
[OWSBackupAPI downloadFileFromCloudObjcWithRecordName:item.recordName
toFileUrl:[NSURL fileURLWithPath:tempFilePath]]
.thenInBackground(^{
[OWSFileSystem protectFileOrFolderAtPath:tempFilePath];
item.downloadFilePath = tempFilePath;
resolve(@(1));
})
.catchInBackground(^(NSError *error) {
if (ignoreErrors) {
resolve(@(1));
} else {
resolve(error);
}
});
}];
}
- (AnyPromise *)restoreLocalProfile
{
OWSLogVerbose(@"");
if (self.isComplete) {
// Job was aborted.
return [AnyPromise promiseWithValue:OWSBackupErrorWithDescription(@"Backup import no longer active.")];
}
AnyPromise *promise = [AnyPromise promiseWithValue:@(1)];
if (self.manifest.localProfileAvatarItem) {
promise = promise.thenInBackground(^{
return [OWSBackupAPI downloadFileFromCloudObjcWithRecordName:item.recordName
toFileUrl:[NSURL fileURLWithPath:tempFilePath]]
.thenInBackground(^{
[OWSFileSystem protectFileOrFolderAtPath:tempFilePath];
item.downloadFilePath = tempFilePath;
});
return [self downloadFileFromCloud:self.manifest.localProfileAvatarItem ignoreErrors:YES];
});
}
promise = promise.thenInBackground(^{
return [self applyLocalProfile];
});
return promise;
}
- (AnyPromise *)restoreLocalProfile
- (AnyPromise *)applyLocalProfile
{
OWSLogVerbose(@"");
@ -269,52 +322,60 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe
}
NSString *_Nullable localProfileName = self.manifest.localProfileName;
UIImage *_Nullable localProfileAvatar = nil;
UIImage *_Nullable localProfileAvatar = [self tryToLoadLocalProfileAvatar];
if (self.manifest.localProfileAvatarItem) {
OWSBackupFragment *item = self.manifest.localProfileAvatarItem;
if (item.recordName.length < 1) {
OWSLogError(@"item was not downloaded.");
// Ignore errors related to local profile.
return [AnyPromise promiseWithValue:@(1)];
}
OWSLogVerbose(@"local profile name: %@, avatar: %d", localProfileName, localProfileAvatar != nil);
@autoreleasepool {
NSData *_Nullable data =
[self.backupIO decryptFileAsData:item.downloadFilePath encryptionKey:item.encryptionKey];
if (!data) {
OWSLogError(@"could not decrypt local profile avatar.");
// Ignore errors related to local profile.
return [AnyPromise promiseWithValue:@(1)];
if (localProfileName.length < 1 && !localProfileAvatar) {
return [AnyPromise promiseWithValue:@(1)];
}
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[self.profileManager updateLocalProfileName:localProfileName
avatarImage:localProfileAvatar
success:^{
resolve(@(1));
}
// TODO: Verify that we're not compressing the profile avatar data.
UIImage *_Nullable image = [UIImage imageWithData:data];
if (!image) {
OWSLogError(@"could not decrypt local profile avatar.");
failure:^{
// Ignore errors related to local profile.
return [AnyPromise promiseWithValue:@(1)];
}
localProfileAvatar = image;
}
}
resolve(@(1));
}];
}];
}
OWSLogVerbose(@"local profile name: %@, avatar: %d", localProfileName, localProfileAvatar != nil);
- (nullable UIImage *)tryToLoadLocalProfileAvatar
{
if (!self.manifest.localProfileAvatarItem) {
return nil;
}
if (!self.manifest.localProfileAvatarItem.downloadFilePath) {
// Download of the avatar failed.
// We can safely ignore errors related to local profile.
OWSLogError(@"local profile avatar was not downloaded.");
return nil;
}
OWSBackupFragment *item = self.manifest.localProfileAvatarItem;
if (item.recordName.length < 1) {
OWSFailDebug(@"item missing record name.");
return nil;
}
if (localProfileName.length > 0 || localProfileAvatar) {
AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[self.profileManager updateLocalProfileName:localProfileName
avatarImage:localProfileAvatar
success:^{
resolve(@(1));
}
failure:^{
// Ignore errors related to local profile.
resolve(@(1));
}];
}];
return promise;
} else {
return [AnyPromise promiseWithValue:@(1)];
@autoreleasepool {
NSData *_Nullable data =
[self.backupIO decryptFileAsData:item.downloadFilePath encryptionKey:item.encryptionKey];
if (!data) {
OWSLogError(@"could not decrypt local profile avatar.");
// Ignore errors related to local profile.
return nil;
}
// TODO: Verify that we're not compressing the profile avatar data.
UIImage *_Nullable image = [UIImage imageWithData:data];
if (!image) {
OWSLogError(@"could not decrypt local profile avatar.");
// Ignore errors related to local profile.
return nil;
}
return image;
}
}

Loading…
Cancel
Save