diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index b06e2c143..48426240f 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -156,7 +156,7 @@ 3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496955B219B605E00DCFE74 /* PhotoLibrary.swift */; }; 3496956021A2FC8100DCFE74 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3496955F21A2FC8100DCFE74 /* CloudKit.framework */; }; 3496956E21A301A100DCFE74 /* OWSBackupExportJob.m in Sources */ = {isa = PBXBuildFile; fileRef = 3496956221A301A100DCFE74 /* OWSBackupExportJob.m */; }; - 3496956F21A301A100DCFE74 /* OWSBackupLazyRestoreJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496956321A301A100DCFE74 /* OWSBackupLazyRestoreJob.swift */; }; + 3496956F21A301A100DCFE74 /* OWSBackupLazyRestore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496956321A301A100DCFE74 /* OWSBackupLazyRestore.swift */; }; 3496957021A301A100DCFE74 /* OWSBackupIO.m in Sources */ = {isa = PBXBuildFile; fileRef = 3496956521A301A100DCFE74 /* OWSBackupIO.m */; }; 3496957121A301A100DCFE74 /* OWSBackupImportJob.m in Sources */ = {isa = PBXBuildFile; fileRef = 3496956621A301A100DCFE74 /* OWSBackupImportJob.m */; }; 3496957221A301A100DCFE74 /* OWSBackup.m in Sources */ = {isa = PBXBuildFile; fileRef = 3496956921A301A100DCFE74 /* OWSBackup.m */; }; @@ -812,7 +812,7 @@ 3496955B219B605E00DCFE74 /* PhotoLibrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoLibrary.swift; sourceTree = ""; }; 3496955F21A2FC8100DCFE74 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; }; 3496956221A301A100DCFE74 /* OWSBackupExportJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackupExportJob.m; sourceTree = ""; }; - 3496956321A301A100DCFE74 /* OWSBackupLazyRestoreJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSBackupLazyRestoreJob.swift; sourceTree = ""; }; + 3496956321A301A100DCFE74 /* OWSBackupLazyRestore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSBackupLazyRestore.swift; sourceTree = ""; }; 3496956421A301A100DCFE74 /* OWSBackup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackup.h; sourceTree = ""; }; 3496956521A301A100DCFE74 /* OWSBackupIO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackupIO.m; sourceTree = ""; }; 3496956621A301A100DCFE74 /* OWSBackupImportJob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackupImportJob.m; sourceTree = ""; }; @@ -1778,7 +1778,7 @@ 3496956521A301A100DCFE74 /* OWSBackupIO.m */, 3496956721A301A100DCFE74 /* OWSBackupJob.h */, 3496956A21A301A100DCFE74 /* OWSBackupJob.m */, - 3496956321A301A100DCFE74 /* OWSBackupLazyRestoreJob.swift */, + 3496956321A301A100DCFE74 /* OWSBackupLazyRestore.swift */, ); path = Backup; sourceTree = ""; @@ -3568,7 +3568,7 @@ 3427C64320F500E000EEC730 /* OWSMessageTimerView.m in Sources */, B90418E6183E9DD40038554A /* DateUtil.m in Sources */, 340FC8BD204DAC8D007AEB0F /* ShowGroupMembersViewController.m in Sources */, - 3496956F21A301A100DCFE74 /* OWSBackupLazyRestoreJob.swift in Sources */, + 3496956F21A301A100DCFE74 /* OWSBackupLazyRestore.swift in Sources */, 459311FC1D75C948008DD4F0 /* OWSDeviceTableViewCell.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index d75f217e0..9fb69a705 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -1212,11 +1212,6 @@ static NSTimeInterval launchStartedAt; [self.messageManager startObserving]; -#ifdef DEBUG - // Resume lazy restore. - [OWSBackupLazyRestoreJob runAsync]; -#endif - [self.udManager setup]; } diff --git a/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift b/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift index 4389d6a50..d1061461e 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift +++ b/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift @@ -88,7 +88,6 @@ public class ConversationMediaView: UIView { } guard attachmentPointer.pointerType == .incoming else { // TODO: Show "restoring" indicator and possibly progress. - owsFailDebug("Attachment is restoring from backup.") configure(forError: .missing) return } diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIBackup.m b/Signal/src/ViewControllers/DebugUI/DebugUIBackup.m index 880ec8bf8..0c6b49848 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIBackup.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIBackup.m @@ -100,7 +100,7 @@ NS_ASSUME_NONNULL_BEGIN [OWSBackup.sharedManager checkCanImportBackup:^(BOOL value) { - OWSLogInfo(@"has backup available for import? %d", value); + OWSLogInfo(@"has backup available for import? %d", value); } failure:^(NSError *error){ // Do nothing. diff --git a/Signal/src/ViewControllers/Registration/BackupRestoreViewController.swift b/Signal/src/ViewControllers/Registration/BackupRestoreViewController.swift index 5cddcac82..604e92ed7 100644 --- a/Signal/src/ViewControllers/Registration/BackupRestoreViewController.swift +++ b/Signal/src/ViewControllers/Registration/BackupRestoreViewController.swift @@ -123,7 +123,7 @@ public class BackupRestoreViewController: OWSTableViewController { backup.setHasPendingRestoreDecision(false) - dismiss(animated: true) + showHomeView() } @objc diff --git a/Signal/src/environment/AppEnvironment.swift b/Signal/src/environment/AppEnvironment.swift index 44368d989..b52a96160 100644 --- a/Signal/src/environment/AppEnvironment.swift +++ b/Signal/src/environment/AppEnvironment.swift @@ -58,6 +58,9 @@ import SignalMessaging @objc public var backup: OWSBackup + @objc + public var backupLazyRestore: BackupLazyRestore + private override init() { self.callMessageHandler = WebRTCCallMessageHandler() self.callService = CallService() @@ -70,6 +73,7 @@ import SignalMessaging self.pushManager = PushManager() self.sessionResetJobQueue = SessionResetJobQueue() self.backup = OWSBackup() + self.backupLazyRestore = BackupLazyRestore() super.init() diff --git a/Signal/src/util/Backup/OWSBackup.h b/Signal/src/util/Backup/OWSBackup.h index 38211f101..c81a55d6b 100644 --- a/Signal/src/util/Backup/OWSBackup.h +++ b/Signal/src/util/Backup/OWSBackup.h @@ -95,9 +95,7 @@ NSError *OWSBackupErrorWithDescription(NSString *description); - (NSArray *)attachmentIdsForLazyRestore; -- (void)lazyRestoreAttachment:(TSAttachmentPointer *)attachment - backupIO:(OWSBackupIO *)backupIO - completion:(OWSBackupBoolBlock)completion; +- (AnyPromise *)lazyRestoreAttachment:(TSAttachmentPointer *)attachment backupIO:(OWSBackupIO *)backupIO; @end diff --git a/Signal/src/util/Backup/OWSBackupAPI.swift b/Signal/src/util/Backup/OWSBackupAPI.swift index aa309577a..6981bcc36 100644 --- a/Signal/src/util/Backup/OWSBackupAPI.swift +++ b/Signal/src/util/Backup/OWSBackupAPI.swift @@ -63,14 +63,17 @@ import PromiseKit // complete. @objc public class func saveEphemeralFileToCloudObjc(recipientId: String, + label: String, fileUrl: URL) -> AnyPromise { return AnyPromise(saveEphemeralFileToCloud(recipientId: recipientId, + label: label, fileUrl: fileUrl)) } public class func saveEphemeralFileToCloud(recipientId: String, + label: String, fileUrl: URL) -> Promise { - let recordName = "\(recordNamePrefix(forRecipientId: recipientId))ephemeralFile-\(NSUUID().uuidString)" + let recordName = "\(recordNamePrefix(forRecipientId: recipientId))ephemeral-\(label)-\(NSUUID().uuidString)" return saveFileToCloud(fileUrl: fileUrl, recordName: recordName, recordType: signalBackupRecordType) @@ -209,6 +212,8 @@ import PromiseKit private class func saveRecordToCloud(record: CKRecord, remainingRetries: Int) -> Promise { + Logger.verbose("saveRecordToCloud \(record.recordID.recordName)") + return Promise { resolver in let saveOperation = CKModifyRecordsOperation(recordsToSave: [record ], recordIDsToDelete: nil) saveOperation.modifyRecordsCompletionBlock = { (records, recordIds, error) in @@ -389,6 +394,8 @@ import PromiseKit private class func checkForFileInCloud(recordName: String, remainingRetries: Int) -> Promise { + Logger.verbose("checkForFileInCloud \(recordName)") + let (promise, resolver) = Promise.pending() let recordId = CKRecordID(recordName: recordName) @@ -643,6 +650,8 @@ import PromiseKit private class func downloadFromCloud(recordName: String, remainingRetries: Int) -> Promise { + Logger.verbose("downloadFromCloud \(recordName)") + let (promise, resolver) = Promise.pending() let recordId = CKRecordID(recordName: recordName) diff --git a/Signal/src/util/Backup/OWSBackupExportJob.m b/Signal/src/util/Backup/OWSBackupExportJob.m index 5571b4ee0..d1524035b 100644 --- a/Signal/src/util/Backup/OWSBackupExportJob.m +++ b/Signal/src/util/Backup/OWSBackupExportJob.m @@ -717,6 +717,7 @@ NS_ASSUME_NONNULL_BEGIN // Add one for the manifest NSUInteger unsavedCount = (self.unsavedDatabaseItems.count + self.unsavedAttachmentExports.count + 1); NSUInteger savedCount = (self.savedDatabaseItems.count + self.savedAttachmentItems.count); + // Ignore localProfileAvatarItem for now. CGFloat progress = (savedCount / (CGFloat)(unsavedCount + savedCount)); [self updateProgressWithDescription:NSLocalizedString(@"BACKUP_EXPORT_PHASE_UPLOAD", @@ -756,8 +757,9 @@ NS_ASSUME_NONNULL_BEGIN return [OWSBackupAPI saveEphemeralFileToCloudObjcWithRecipientId:self.recipientId - fileUrl:[NSURL fileURLWithPath:item.encryptedItem - .filePath]]; + label:@"database" + fileUrl:[NSURL + fileURLWithPath:item.encryptedItem.filePath]]; }) .thenInBackground(^(NSString *recordName) { item.recordName = recordName; @@ -907,6 +909,7 @@ NS_ASSUME_NONNULL_BEGIN exportItem.encryptedItem = encryptedItem; return [OWSBackupAPI saveEphemeralFileToCloudObjcWithRecipientId:self.recipientId + label:@"local-profile-avatar" fileUrl:[NSURL fileURLWithPath:encryptedItem.filePath]] .thenInBackground(^(NSString *recordName) { exportItem.recordName = recordName; @@ -1029,6 +1032,12 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertDebug(![activeRecordNames containsObject:item.recordName]); [activeRecordNames addObject:item.recordName]; } + if (self.localProfileAvatarItem) { + OWSBackupExportItem *item = self.localProfileAvatarItem; + OWSAssertDebug(item.recordName.length > 0); + OWSAssertDebug(![activeRecordNames containsObject:item.recordName]); + [activeRecordNames addObject:item.recordName]; + } OWSAssertDebug(self.manifestItem.recordName.length > 0); OWSAssertDebug(![activeRecordNames containsObject:self.manifestItem.recordName]); [activeRecordNames addObject:self.manifestItem.recordName]; diff --git a/Signal/src/util/Backup/OWSBackupImportJob.m b/Signal/src/util/Backup/OWSBackupImportJob.m index 1f902e285..201d1439c 100644 --- a/Signal/src/util/Backup/OWSBackupImportJob.m +++ b/Signal/src/util/Backup/OWSBackupImportJob.m @@ -63,6 +63,11 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe return AppEnvironment.shared.backup; } +- (OWSBackupLazyRestore *)backupLazyRestore +{ + return AppEnvironment.shared.backupLazyRestore; +} + #pragma mark - - (NSArray *)databaseItems @@ -129,14 +134,21 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe OWSAssertDebug(self.databaseItems); OWSAssertDebug(self.attachmentsItems); + // These items should be downloaded immediately. NSMutableArray *allItems = [NSMutableArray new]; [allItems addObjectsFromArray:self.databaseItems]; - // TODO: We probably want to remove this. - [allItems addObjectsFromArray:self.attachmentsItems]; if (self.manifest.localProfileAvatarItem) { [allItems addObject:self.manifest.localProfileAvatarItem]; } + // Make a copy of the blockingItems before we add + // the attachment items. + NSArray *blockingItems = [allItems copy]; + + // Attachment items can be downloaded later; + // they will can be lazy-restored. + [allItems addObjectsFromArray:self.attachmentsItems]; + // Record metadata for all items, so that we can re-use them in incremental backups after the restore. [self.primaryStorage.newDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { for (OWSBackupFragment *item in allItems) { @@ -144,7 +156,7 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe } }]; - return [self downloadFilesFromCloud:allItems] + return [self downloadFilesFromCloud:blockingItems] .thenInBackground(^{ return [self restoreDatabase]; }) @@ -157,17 +169,18 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe .thenInBackground(^{ return [self restoreAttachmentFiles]; }) - .thenInBackground(^{ - // Kick off lazy restore. - [OWSBackupLazyRestoreJob runAsync]; + .then(^{ + // Kick off lazy restore on main thread. + [self.backupLazyRestore runIfNecessary]; [self.profileManager fetchLocalUsersProfile]; - - [self.tsAccountManager updateAccountAttributes]; // Make sure backup is enabled once we complete // a backup restore. [OWSBackup.sharedManager setIsBackupEnabled:YES]; + }) + .thenInBackground(^{ + [self.tsAccountManager updateAccountAttributes]; [self succeed]; }); @@ -187,7 +200,7 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe return [AnyPromise promiseWithValue:@(1)]; } -- (AnyPromise *)downloadFilesFromCloud:(NSMutableArray *)items +- (AnyPromise *)downloadFilesFromCloud:(NSArray *)items { OWSAssertDebug(items.count > 0); @@ -244,7 +257,7 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe - (AnyPromise *)restoreLocalProfile { - OWSLogVerbose(@": %zd", self.attachmentsItems.count); + OWSLogVerbose(@""); if (self.isComplete) { // Job was aborted. @@ -257,12 +270,7 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe if (self.manifest.localProfileAvatarItem) { OWSBackupFragment *item = self.manifest.localProfileAvatarItem; if (item.recordName.length < 1) { - OWSLogError(@"local profile avatar was not downloaded."); - // Ignore errors related to local profile. - return [AnyPromise promiseWithValue:@(1)]; - } - if (!item.uncompressedDataLength || item.uncompressedDataLength.unsignedIntValue < 1) { - OWSLogError(@"database snapshot missing size."); + OWSLogError(@"item was not downloaded."); // Ignore errors related to local profile. return [AnyPromise promiseWithValue:@(1)]; } @@ -286,6 +294,8 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe } } + OWSLogVerbose(@"local profile name: %@, avatar: %d", localProfileName, localProfileAvatar != nil); + if (localProfileName.length > 0 || localProfileAvatar) { AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { [self.profileManager updateLocalProfileName:localProfileName diff --git a/Signal/src/util/Backup/OWSBackupJob.m b/Signal/src/util/Backup/OWSBackupJob.m index 7c4e0c072..759b451ea 100644 --- a/Signal/src/util/Backup/OWSBackupJob.m +++ b/Signal/src/util/Backup/OWSBackupJob.m @@ -224,7 +224,7 @@ NSString *const kOWSBackup_KeychainService = @"kOWSBackup_KeychainService"; contents.localProfileAvatarItem = localProfileAvatarItems.firstObject; if ([localProfileName isKindOfClass:[NSString class]]) { contents.localProfileName = localProfileName; - } else { + } else if (localProfileName) { OWSFailDebug(@"Invalid localProfileName: %@", [localProfileName class]); } diff --git a/Signal/src/util/Backup/OWSBackupLazyRestore.swift b/Signal/src/util/Backup/OWSBackupLazyRestore.swift new file mode 100644 index 000000000..563c266cb --- /dev/null +++ b/Signal/src/util/Backup/OWSBackupLazyRestore.swift @@ -0,0 +1,141 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +import Foundation +import PromiseKit +import SignalServiceKit + +@objc(OWSBackupLazyRestore) +public class BackupLazyRestore: NSObject { + + // MARK: - Dependencies + + private var backup: OWSBackup { + return AppEnvironment.shared.backup + } + + private var primaryStorage: OWSPrimaryStorage { + return SSKEnvironment.shared.primaryStorage + } + + private var tsAccountManager: TSAccountManager { + return TSAccountManager.sharedInstance() + } + + // MARK: - + + private var isRunning = false + private var isComplete = false + + @objc + public required override init() { + super.init() + + SwiftSingletons.register(self) + + AppReadiness.runNowOrWhenAppDidBecomeReady { + self.runIfNecessary() + } + + NotificationCenter.default.addObserver(forName: .OWSApplicationDidBecomeActive, object: nil, queue: nil) { _ in + self.runIfNecessary() + } + NotificationCenter.default.addObserver(forName: .RegistrationStateDidChange, object: nil, queue: nil) { _ in + self.runIfNecessary() + } + NotificationCenter.default.addObserver(forName: .reachabilityChanged, object: nil, queue: nil) { _ in + self.runIfNecessary() + } + } + + // MARK: - + + private let backgroundQueue = DispatchQueue.global(qos: .background) + + @objc + public func runIfNecessary() { + AssertIsOnMainThread() + + guard CurrentAppContext().isMainAppAndActive else { + return + } + guard tsAccountManager.isRegisteredAndReady() else { + return + } + guard !isRunning, !isComplete else { + return + } + + isRunning = true + + backgroundQueue.async { + self.restoreAttachments() + } + } + + private func restoreAttachments() { + let temporaryDirectory = OWSTemporaryDirectory() + let jobTempDirPath = (temporaryDirectory as NSString).appendingPathComponent(NSUUID().uuidString) + + guard OWSFileSystem.ensureDirectoryExists(jobTempDirPath) else { + Logger.error("could not create temp directory.") + complete(errorCount: 1) + return + } + + let backupIO = OWSBackupIO(jobTempDirPath: jobTempDirPath) + + let attachmentIds = backup.attachmentIdsForLazyRestore() + guard attachmentIds.count > 0 else { + Logger.info("No attachments need lazy restore.") + complete(errorCount: 0) + return + } + Logger.info("Lazy restoring \(attachmentIds.count) attachments.") + tryToRestoreNextAttachment(attachmentIds: attachmentIds, errorCount: 0, backupIO: backupIO) + } + + private func tryToRestoreNextAttachment(attachmentIds: [String], errorCount: UInt, backupIO: OWSBackupIO) { + var attachmentIdsCopy = attachmentIds + guard let attachmentId = attachmentIdsCopy.popLast() else { + // This job is done. + Logger.verbose("job is done.") + complete(errorCount: errorCount) + return + } + guard let attachmentPointer = TSAttachment.fetch(uniqueId: attachmentId) as? TSAttachmentPointer else { + Logger.warn("could not load attachment.") + // Not necessarily an error. + // The attachment might have been deleted since the job began. + // Continue trying to restore the other attachments. + tryToRestoreNextAttachment(attachmentIds: attachmentIds, errorCount: errorCount + 1, backupIO: backupIO) + return + } + backup.lazyRestoreAttachment(attachmentPointer, + backupIO: backupIO) + .done(on: self.backgroundQueue) { _ in + Logger.info("Restored attachment.") + + // Continue trying to restore the other attachments. + self.tryToRestoreNextAttachment(attachmentIds: attachmentIdsCopy, errorCount: errorCount, backupIO: backupIO) + }.catch(on: self.backgroundQueue) { (error) in + Logger.error("Could not restore attachment: \(error)") + + // Continue trying to restore the other attachments. + self.tryToRestoreNextAttachment(attachmentIds: attachmentIdsCopy, errorCount: errorCount + 1, backupIO: backupIO) + }.retainUntilComplete() + } + + private func complete(errorCount: UInt) { + Logger.verbose("") + + DispatchQueue.main.async { + self.isRunning = false + + if errorCount == 0 { + self.isComplete = true + } + } + } +} diff --git a/Signal/src/util/Backup/OWSBackupLazyRestoreJob.swift b/Signal/src/util/Backup/OWSBackupLazyRestoreJob.swift deleted file mode 100644 index e58189cce..000000000 --- a/Signal/src/util/Backup/OWSBackupLazyRestoreJob.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PromiseKit -import SignalServiceKit - -@objc -public class OWSBackupLazyRestoreJob: NSObject { - - let primaryStorage: OWSPrimaryStorage - - private var jobTempDirPath: String? - - deinit { - if let jobTempDirPath = self.jobTempDirPath { - DispatchQueue.global().async { - OWSFileSystem.deleteFile(jobTempDirPath) - } - } - } - - @objc - public class func runAsync() { - OWSBackupLazyRestoreJob().runAsync() - } - - public override init() { - self.primaryStorage = OWSPrimaryStorage.shared() - } - - private func runAsync() { - AssertIsOnMainThread() - - DispatchQueue.global().async { - self.restoreAttachments() - } - } - - private func restoreAttachments() { - let temporaryDirectory = OWSTemporaryDirectory() - let jobTempDirPath = (temporaryDirectory as NSString).appendingPathComponent(NSUUID().uuidString) - - guard OWSFileSystem.ensureDirectoryExists(jobTempDirPath) else { - Logger.error("could not create temp directory.") - return - } - - self.jobTempDirPath = jobTempDirPath - - let backupIO = OWSBackupIO(jobTempDirPath: jobTempDirPath) - - let attachmentIds = OWSBackup.shared().attachmentIdsForLazyRestore() - guard attachmentIds.count > 0 else { - Logger.info("No attachments need lazy restore.") - return - } - Logger.info("Lazy restoring \(attachmentIds.count) attachments.") - self.tryToRestoreNextAttachment(attachmentIds: attachmentIds, backupIO: backupIO) - } - - private func tryToRestoreNextAttachment(attachmentIds: [String], backupIO: OWSBackupIO) { - var attachmentIdsCopy = attachmentIds - guard let attachmentId = attachmentIdsCopy.last else { - // This job is done. - Logger.verbose("job is done.") - return - } - attachmentIdsCopy.removeLast() - guard let attachmentPointer = TSAttachment.fetch(uniqueId: attachmentId) as? TSAttachmentPointer else { - Logger.warn("could not load attachment.") - // Not necessarily an error. - // The attachment might have been deleted since the job began. - // Continue trying to restore the other attachments. - tryToRestoreNextAttachment(attachmentIds: attachmentIds, backupIO: backupIO) - return - } - OWSBackup.shared().lazyRestoreAttachment(attachmentPointer, - backupIO: backupIO, - completion: { (success) in - if success { - Logger.info("restored attachment.") - } else { - Logger.warn("could not restore attachment.") - } - // Continue trying to restore the other attachments. - self.tryToRestoreNextAttachment(attachmentIds: attachmentIdsCopy, backupIO: backupIO) - }) - - } -} diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index 0766e0e0e..eb95ce2f5 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -1447,7 +1447,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); - (void)updateProfileAvatarCache:(nullable UIImage *)image filename:(NSString *)filename { OWSAssertDebug(filename.length > 0); - OWSAssertDebug(image); @synchronized(self.profileAvatarImageCache) {