|  |  | @ -159,6 +159,7 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4; | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic, readonly) void (^failureHandler)(NSError *_Nonnull error); |  |  |  | @property (nonatomic, readonly) void (^failureHandler)(NSError *_Nonnull error); | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic) OWSSendMessageOperationState operationState; |  |  |  | @property (nonatomic) OWSSendMessageOperationState operationState; | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier; |  |  |  | @property (nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | @property (nonatomic) BOOL hasCompleted; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | @end |  |  |  | @end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -190,6 +191,13 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4; | 
			
		
	
		
		
			
				
					
					|  |  |  |             return; |  |  |  |             return; | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // Ensure we call the success or failure handler exactly once. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         @synchronized(strongSelf) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             OWSCAssert(!strongSelf.hasCompleted); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             strongSelf.hasCompleted = YES; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         [message updateWithMessageState:TSOutgoingMessageStateSentToService]; |  |  |  |         [message updateWithMessageState:TSOutgoingMessageStateSentToService]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogDebug(@"%@ succeeded.", strongSelf.tag); |  |  |  |         DDLogDebug(@"%@ succeeded.", strongSelf.tag); | 
			
		
	
	
		
		
			
				
					|  |  | @ -204,6 +212,13 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4; | 
			
		
	
		
		
			
				
					
					|  |  |  |             return; |  |  |  |             return; | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // Ensure we call the success or failure handler exactly once. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         @synchronized(strongSelf) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             OWSCAssert(!strongSelf.hasCompleted); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             strongSelf.hasCompleted = YES; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         [strongSelf.message updateWithSendingError:error]; |  |  |  |         [strongSelf.message updateWithSendingError:error]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogDebug(@"%@ failed with error: %@", strongSelf.tag, error); |  |  |  |         DDLogDebug(@"%@ failed with error: %@", strongSelf.tag, error); | 
			
		
	
	
		
		
			
				
					|  |  | @ -281,9 +296,14 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4; | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     DDLogDebug(@"%@ remainingRetries: %lu", self.tag, (unsigned long)remainingRetries); |  |  |  |     DDLogDebug(@"%@ remainingRetries: %lu", self.tag, (unsigned long)remainingRetries); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // Use this flag to ensure a given operation only succeeds or fails once. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     __block BOOL onceFlag = NO; | 
			
		
	
		
		
			
				
					
					|  |  |  |     RetryableFailureHandler retryableFailureHandler = ^(NSError *_Nonnull error) { |  |  |  |     RetryableFailureHandler retryableFailureHandler = ^(NSError *_Nonnull error) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogInfo(@"%@ Sending failed.", self.tag); |  |  |  |         DDLogInfo(@"%@ Sending failed.", self.tag); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         OWSAssert(!onceFlag); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         onceFlag = YES; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (![error isRetryable] || [error isFatal]) { |  |  |  |         if (![error isRetryable] || [error isFatal]) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             DDLogInfo(@"%@ Skipping retry due to terminal error: %@", self.tag, error); |  |  |  |             DDLogInfo(@"%@ Skipping retry due to terminal error: %@", self.tag, error); | 
			
		
	
		
		
			
				
					
					|  |  |  |             self.failureHandler(error); |  |  |  |             self.failureHandler(error); | 
			
		
	
	
		
		
			
				
					|  |  | @ -299,7 +319,14 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4; | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     }; |  |  |  |     }; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self.messageSender attemptToSendMessage:self.message success:self.successHandler failure:retryableFailureHandler]; |  |  |  |     [self.messageSender attemptToSendMessage:self.message | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                      success:^{ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                          OWSAssert(!onceFlag); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                          onceFlag = YES; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                          self.successHandler(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                      } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                      failure:retryableFailureHandler]; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)markAsComplete |  |  |  | - (void)markAsComplete | 
			
		
	
	
		
		
			
				
					|  |  | @ -762,6 +789,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; | 
			
		
	
		
		
			
				
					
					|  |  |  |                         // retryable errors. |  |  |  |                         // retryable errors. | 
			
		
	
		
		
			
				
					
					|  |  |  |                         if ([error isFatal]) { |  |  |  |                         if ([error isFatal]) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                             failureHandler(error); |  |  |  |                             failureHandler(error); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             return; | 
			
		
	
		
		
			
				
					
					|  |  |  |                         } |  |  |  |                         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                         if ([error isRetryable] && !firstRetryableError) { |  |  |  |                         if ([error isRetryable] && !firstRetryableError) { | 
			
		
	
	
		
		
			
				
					|  |  | 
 |