Respond to CR.

pull/1/head
Matthew Chen 7 years ago
parent 44d0ad34f5
commit 8bd21fd023

@ -72,7 +72,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)updateICloudStatus - (void)updateICloudStatus
{ {
__weak OWSBackupSettingsViewController *weakSelf = self; __weak OWSBackupSettingsViewController *weakSelf = self;
[[self.backup checkCloudKitAccess] [[self.backup ensureCloudKitAccess]
.then(^{ .then(^{
OWSAssertIsOnMainThread(); OWSAssertIsOnMainThread();

@ -88,7 +88,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssertDebug(success); OWSAssertDebug(success);
NSString *recipientId = self.tsAccountManager.localNumber; NSString *recipientId = self.tsAccountManager.localNumber;
[[self.backup checkCloudKitAccess].then(^{ [[self.backup ensureCloudKitAccess].then(^{
return return
[OWSBackupAPI saveTestFileToCloudObjcWithRecipientId:recipientId fileUrl:[NSURL fileURLWithPath:filePath]]; [OWSBackupAPI saveTestFileToCloudObjcWithRecipientId:recipientId fileUrl:[NSURL fileURLWithPath:filePath]];
}) retainUntilComplete]; }) retainUntilComplete];

@ -74,7 +74,7 @@ NSError *OWSBackupErrorWithDescription(NSString *description);
- (void)allRecipientIdsWithManifestsInCloud:(OWSBackupStringListBlock)success failure:(OWSBackupErrorBlock)failure; - (void)allRecipientIdsWithManifestsInCloud:(OWSBackupStringListBlock)success failure:(OWSBackupErrorBlock)failure;
- (AnyPromise *)checkCloudKitAccess; - (AnyPromise *)ensureCloudKitAccess;
- (AnyPromise *)checkCanExportBackup; - (AnyPromise *)checkCanExportBackup;

@ -217,7 +217,7 @@ NSError *OWSBackupErrorWithDescription(NSString *description)
_backupExportState = OWSBackupState_InProgress; _backupExportState = OWSBackupState_InProgress;
self.backupExportJob = [[OWSBackupExportJob alloc] initWithDelegate:self recipientId:recipientId]; self.backupExportJob = [[OWSBackupExportJob alloc] initWithDelegate:self recipientId:recipientId];
[self.backupExportJob startAsync]; [self.backupExportJob start];
[self postDidChangeNotification]; [self postDidChangeNotification];
} }
@ -369,7 +369,7 @@ NSError *OWSBackupErrorWithDescription(NSString *description)
self.backupExportJob = nil; self.backupExportJob = nil;
} else if (self.shouldHaveBackupExport && !self.backupExportJob) { } else if (self.shouldHaveBackupExport && !self.backupExportJob) {
self.backupExportJob = [[OWSBackupExportJob alloc] initWithDelegate:self recipientId:recipientId]; self.backupExportJob = [[OWSBackupExportJob alloc] initWithDelegate:self recipientId:recipientId];
[self.backupExportJob startAsync]; [self.backupExportJob start];
} }
// Update the state flag. // Update the state flag.
@ -423,10 +423,10 @@ NSError *OWSBackupErrorWithDescription(NSString *description)
- (AnyPromise *)checkCanExportBackup - (AnyPromise *)checkCanExportBackup
{ {
return [self checkCloudKitAccess]; return [self ensureCloudKitAccess];
} }
- (AnyPromise *)checkCloudKitAccess - (AnyPromise *)ensureCloudKitAccess
{ {
OWSAssertIsOnMainThread(); OWSAssertIsOnMainThread();
@ -452,7 +452,7 @@ NSError *OWSBackupErrorWithDescription(NSString *description)
return failWithUnexpectedError(); return failWithUnexpectedError();
} }
return [[OWSBackupAPI checkCloudKitAccessObjc] retainUntilComplete]; return [OWSBackupAPI ensureCloudKitAccessObjc];
} }
- (void)checkCanImportBackup:(OWSBackupBoolBlock)success failure:(OWSBackupErrorBlock)failure - (void)checkCanImportBackup:(OWSBackupBoolBlock)success failure:(OWSBackupErrorBlock)failure
@ -484,7 +484,7 @@ NSError *OWSBackupErrorWithDescription(NSString *description)
return failWithUnexpectedError(); return failWithUnexpectedError();
} }
[[OWSBackupAPI checkCloudKitAccessObjc] [[OWSBackupAPI ensureCloudKitAccessObjc]
.thenInBackground(^{ .thenInBackground(^{
return [OWSBackupAPI checkForManifestInCloudObjcWithRecipientId:recipientId]; return [OWSBackupAPI checkForManifestInCloudObjcWithRecipientId:recipientId];
}) })

@ -202,63 +202,61 @@ import PromiseKit
} }
public class func saveRecordToCloud(record: CKRecord) -> Promise<String> { public class func saveRecordToCloud(record: CKRecord) -> Promise<String> {
let (promise, resolver) = Promise<String>.pending() return saveRecordToCloud(record: record,
saveRecordToCloud(record: record, remainingRetries: maxRetries)
remainingRetries: maxRetries,
success: { (recordName) in
resolver.fulfill(recordName)
},
failure: { (error) in
resolver.reject(error)
})
return promise.retainUntilComplete()
} }
private class func saveRecordToCloud(record: CKRecord, private class func saveRecordToCloud(record: CKRecord,
remainingRetries: Int, remainingRetries: Int) -> Promise<String> {
success: @escaping (String) -> Void,
failure: @escaping (Error) -> Void) { return Promise { resolver in
let saveOperation = CKModifyRecordsOperation(recordsToSave: [record ], recordIDsToDelete: nil)
let saveOperation = CKModifyRecordsOperation(recordsToSave: [record ], recordIDsToDelete: nil) saveOperation.modifyRecordsCompletionBlock = { (records, recordIds, error) in
saveOperation.modifyRecordsCompletionBlock = { (records, recordIds, error) in
let outcome = outcomeForCloudKitError(error: error,
let outcome = outcomeForCloudKitError(error: error, remainingRetries: remainingRetries,
remainingRetries: remainingRetries, label: "Save Record")
label: "Save Record") switch outcome {
switch outcome { case .success:
case .success: let recordName = record.recordID.recordName
let recordName = record.recordID.recordName resolver.fulfill(recordName)
success(recordName) case .failureDoNotRetry(let outcomeError):
case .failureDoNotRetry(let outcomeError): resolver.reject(outcomeError)
failure(outcomeError) case .failureRetryAfterDelay(let retryDelay):
case .failureRetryAfterDelay(let retryDelay): DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + retryDelay, execute: {
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + retryDelay, execute: { saveRecordToCloud(record: record,
saveRecordToCloud(record: record, remainingRetries: remainingRetries - 1)
remainingRetries: remainingRetries - 1, .done { (recordName) in
success: success, resolver.fulfill(recordName)
failure: failure) }.catch { (error) in
}) resolver.reject(error)
case .failureRetryWithoutDelay: }.retainUntilComplete()
DispatchQueue.global().async { })
saveRecordToCloud(record: record, case .failureRetryWithoutDelay:
remainingRetries: remainingRetries - 1, DispatchQueue.global().async {
success: success, saveRecordToCloud(record: record,
failure: failure) remainingRetries: remainingRetries - 1)
.done { (recordName) in
resolver.fulfill(recordName)
}.catch { (error) in
resolver.reject(error)
}.retainUntilComplete()
}
case .unknownItem:
owsFailDebug("unexpected CloudKit response.")
resolver.reject(invalidServiceResponseError())
} }
case .unknownItem:
owsFailDebug("unexpected CloudKit response.")
failure(invalidServiceResponseError())
} }
} saveOperation.isAtomic = false
saveOperation.isAtomic = false
// These APIs are only available in iOS 9.3 and later. // These APIs are only available in iOS 9.3 and later.
if #available(iOS 9.3, *) { if #available(iOS 9.3, *) {
saveOperation.isLongLived = true saveOperation.isLongLived = true
saveOperation.qualityOfService = .background saveOperation.qualityOfService = .background
} }
database().add(saveOperation) database().add(saveOperation)
}
} }
// Compare: // Compare:
@ -422,7 +420,7 @@ import PromiseKit
resolver.fulfill(record) resolver.fulfill(record)
}.catch { (error) in }.catch { (error) in
resolver.reject(error) resolver.reject(error)
} }.retainUntilComplete()
}) })
case .failureRetryWithoutDelay: case .failureRetryWithoutDelay:
DispatchQueue.global().async { DispatchQueue.global().async {
@ -432,7 +430,7 @@ import PromiseKit
resolver.fulfill(record) resolver.fulfill(record)
}.catch { (error) in }.catch { (error) in
resolver.reject(error) resolver.reject(error)
} }.retainUntilComplete()
} }
case .unknownItem: case .unknownItem:
// Record not found. // Record not found.
@ -440,7 +438,7 @@ import PromiseKit
} }
} }
database().add(fetchOperation) database().add(fetchOperation)
return promise.retainUntilComplete() return promise
} }
@objc @objc
@ -701,13 +699,13 @@ import PromiseKit
} }
@objc @objc
public class func checkCloudKitAccessObjc() -> AnyPromise { public class func ensureCloudKitAccessObjc() -> AnyPromise {
return AnyPromise(checkCloudKitAccess()) return AnyPromise(ensureCloudKitAccess())
} }
public class func checkCloudKitAccess() -> Promise<Void> { public class func ensureCloudKitAccess() -> Promise<Void> {
let (promise, resolver) = Promise<Void>.pending() let (promise, resolver) = Promise<Void>.pending()
CKContainer.default().accountStatus(completionHandler: { (accountStatus, error) in CKContainer.default().accountStatus { (accountStatus, error) in
if let error = error { if let error = error {
Logger.error("Unknown error: \(String(describing: error)).") Logger.error("Unknown error: \(String(describing: error)).")
resolver.reject(error) resolver.reject(error)
@ -727,7 +725,7 @@ import PromiseKit
Logger.verbose("CloudKit access okay.") Logger.verbose("CloudKit access okay.")
resolver.fulfill(()) resolver.fulfill(())
} }
}) }
return promise return promise
} }

@ -8,7 +8,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface OWSBackupExportJob : OWSBackupJob @interface OWSBackupExportJob : OWSBackupJob
- (void)startAsync; - (void)start;
@end @end

@ -337,7 +337,7 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - #pragma mark -
- (void)startAsync - (void)start
{ {
OWSAssertIsOnMainThread(); OWSAssertIsOnMainThread();
@ -347,24 +347,14 @@ NS_ASSUME_NONNULL_BEGIN
[self updateProgressWithDescription:nil progress:nil]; [self updateProgressWithDescription:nil progress:nil];
[[self.backup checkCloudKitAccess] [[self.backup ensureCloudKitAccess]
.thenInBackground(^{ .thenInBackground(^{
[self start]; [self updateProgressWithDescription:NSLocalizedString(@"BACKUP_EXPORT_PHASE_CONFIGURATION",
}) @"Indicates that the backup export is being configured.")
.catch(^(NSError *error) { progress:nil];
[self failWithErrorDescription:
NSLocalizedString(@"BACKUP_EXPORT_ERROR_COULD_NOT_EXPORT",
@"Error indicating the backup export could not export the user's data.")];
}) retainUntilComplete];
}
- (void)start
{
[self updateProgressWithDescription:NSLocalizedString(@"BACKUP_EXPORT_PHASE_CONFIGURATION",
@"Indicates that the backup export is being configured.")
progress:nil];
[[self configureExport] return [self configureExport];
})
.thenInBackground(^{ .thenInBackground(^{
return [self fetchAllRecords]; return [self fetchAllRecords];
}) })
@ -415,7 +405,7 @@ NS_ASSUME_NONNULL_BEGIN
// //
// We use an arbitrary request that requires authentication // We use an arbitrary request that requires authentication
// to verify our account state. // to verify our account state.
AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
TSRequest *currentSignedPreKey = [OWSRequestFactory currentSignedPreKeyRequest]; TSRequest *currentSignedPreKey = [OWSRequestFactory currentSignedPreKeyRequest];
[[TSNetworkManager sharedManager] makeRequest:currentSignedPreKey [[TSNetworkManager sharedManager] makeRequest:currentSignedPreKey
success:^(NSURLSessionDataTask *task, NSDictionary *responseObject) { success:^(NSURLSessionDataTask *task, NSDictionary *responseObject) {
@ -427,8 +417,6 @@ NS_ASSUME_NONNULL_BEGIN
resolve(error); resolve(error);
}]; }];
}]; }];
[promise retainUntilComplete];
return promise;
} }
- (AnyPromise *)fetchAllRecords - (AnyPromise *)fetchAllRecords
@ -439,7 +427,7 @@ NS_ASSUME_NONNULL_BEGIN
return [AnyPromise promiseWithValue:OWSBackupErrorWithDescription(@"Backup export no longer active.")]; return [AnyPromise promiseWithValue:OWSBackupErrorWithDescription(@"Backup export no longer active.")];
} }
AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[OWSBackupAPI fetchAllRecordNamesWithRecipientId:self.recipientId [OWSBackupAPI fetchAllRecordNamesWithRecipientId:self.recipientId
success:^(NSArray<NSString *> *recordNames) { success:^(NSArray<NSString *> *recordNames) {
if (self.isComplete) { if (self.isComplete) {
@ -452,8 +440,6 @@ NS_ASSUME_NONNULL_BEGIN
resolve(error); resolve(error);
}]; }];
}]; }];
[promise retainUntilComplete];
return promise;
} }
- (AnyPromise *)exportDatabase - (AnyPromise *)exportDatabase
@ -750,25 +736,23 @@ NS_ASSUME_NONNULL_BEGIN
for (OWSBackupExportItem *item in self.unsavedDatabaseItems) { for (OWSBackupExportItem *item in self.unsavedDatabaseItems) {
OWSAssertDebug(item.encryptedItem.filePath.length > 0); OWSAssertDebug(item.encryptedItem.filePath.length > 0);
promise = promise.thenInBackground(^{ promise
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { = promise
if (self.isComplete) { .thenInBackground(^{
return resolve(OWSBackupErrorWithDescription(@"Backup export no longer active.")); if (self.isComplete) {
} return [AnyPromise
resolve(@(1)); promiseWithValue:OWSBackupErrorWithDescription(@"Backup export no longer active.")];
}] }
.thenInBackground(^{
return [OWSBackupAPI return [OWSBackupAPI
saveEphemeralDatabaseFileToCloudObjcWithRecipientId:self.recipientId saveEphemeralDatabaseFileToCloudObjcWithRecipientId:self.recipientId
fileUrl:[NSURL fileURLWithPath:item.encryptedItem fileUrl:[NSURL fileURLWithPath:item.encryptedItem
.filePath]]; .filePath]];
}) })
.thenInBackground(^(NSString *recordName) { .thenInBackground(^(NSString *recordName) {
item.recordName = recordName; item.recordName = recordName;
[self.savedDatabaseItems addObject:item]; [self.savedDatabaseItems addObject:item];
return [AnyPromise promiseWithValue:@(1)]; });
});
});
} }
[self.unsavedDatabaseItems removeAllObjects]; [self.unsavedDatabaseItems removeAllObjects];
return promise; return promise;
@ -880,7 +864,6 @@ NS_ASSUME_NONNULL_BEGIN
OWSLogVerbose( OWSLogVerbose(
@"saved attachment: %@ as %@", attachmentExport.attachmentFilePath, attachmentExport.relativeFilePath); @"saved attachment: %@ as %@", attachmentExport.attachmentFilePath, attachmentExport.relativeFilePath);
return [AnyPromise promiseWithValue:@(1)];
}) })
.catchInBackground(^{ .catchInBackground(^{
if (![attachmentExport cleanUp]) { if (![attachmentExport cleanUp]) {
@ -914,7 +897,6 @@ NS_ASSUME_NONNULL_BEGIN
self.manifestItem = exportItem; self.manifestItem = exportItem;
// All files have been saved to the cloud. // All files have been saved to the cloud.
return [AnyPromise promiseWithValue:@(1)];
}); });
} }

@ -77,7 +77,7 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe
[self updateProgressWithDescription:nil progress:nil]; [self updateProgressWithDescription:nil progress:nil];
__weak OWSBackupImportJob *weakSelf = self; __weak OWSBackupImportJob *weakSelf = self;
[[self.backup checkCloudKitAccess] [[self.backup ensureCloudKitAccess]
.thenInBackground(^{ .thenInBackground(^{
[weakSelf start]; [weakSelf start];
}) })

@ -11,14 +11,12 @@ public extension AnyPromise {
* promise to self retain, until it completes to avoid the risk it's GC'd before completion. * promise to self retain, until it completes to avoid the risk it's GC'd before completion.
*/ */
@objc @objc
@discardableResult func retainUntilComplete() {
func retainUntilComplete() -> AnyPromise {
var retainCycle: AnyPromise? = self var retainCycle: AnyPromise? = self
_ = self.ensure { _ = self.ensure {
assert(retainCycle != nil) assert(retainCycle != nil)
retainCycle = nil retainCycle = nil
} }
return self
} }
} }
@ -27,14 +25,12 @@ public extension PMKFinalizer {
* Sometimes there isn't a straight forward candidate to retain a promise, in that case we tell the * Sometimes there isn't a straight forward candidate to retain a promise, in that case we tell the
* promise to self retain, until it completes to avoid the risk it's GC'd before completion. * promise to self retain, until it completes to avoid the risk it's GC'd before completion.
*/ */
@discardableResult func retainUntilComplete() {
func retainUntilComplete() -> PMKFinalizer {
var retainCycle: PMKFinalizer? = self var retainCycle: PMKFinalizer? = self
_ = self.finally { _ = self.finally {
assert(retainCycle != nil) assert(retainCycle != nil)
retainCycle = nil retainCycle = nil
} }
return self
} }
} }
@ -43,14 +39,12 @@ public extension Promise {
* Sometimes there isn't a straight forward candidate to retain a promise, in that case we tell the * Sometimes there isn't a straight forward candidate to retain a promise, in that case we tell the
* promise to self retain, until it completes to avoid the risk it's GC'd before completion. * promise to self retain, until it completes to avoid the risk it's GC'd before completion.
*/ */
@discardableResult func retainUntilComplete() {
func retainUntilComplete() -> Promise<T> {
var retainCycle: Promise<T>? = self var retainCycle: Promise<T>? = self
_ = self.ensure { _ = self.ensure {
assert(retainCycle != nil) assert(retainCycle != nil)
retainCycle = nil retainCycle = nil
} }
return self
} }
} }
@ -59,13 +53,11 @@ public extension Guarantee {
* Sometimes there isn't a straight forward candidate to retain a promise, in that case we tell the * Sometimes there isn't a straight forward candidate to retain a promise, in that case we tell the
* promise to self retain, until it completes to avoid the risk it's GC'd before completion. * promise to self retain, until it completes to avoid the risk it's GC'd before completion.
*/ */
@discardableResult func retainUntilComplete() {
func retainUntilComplete() -> Guarantee<T> {
var retainCycle: Guarantee<T>? = self var retainCycle: Guarantee<T>? = self
_ = self.done { _ in _ = self.done { _ in
assert(retainCycle != nil) assert(retainCycle != nil)
retainCycle = nil retainCycle = nil
} }
return self
} }
} }

Loading…
Cancel
Save