Further sender cleanup.

pull/1/head
Matthew Chen 7 years ago
parent fbf0c51e76
commit 61a99c3f87

@ -47,13 +47,21 @@ public class OWSMessageSend: NSObject {
@objc @objc
public let senderCertificate: SMKSenderCertificate? public let senderCertificate: SMKSenderCertificate?
@objc
public let success: () -> Void
@objc
public let failure: (Error) -> Void
@objc @objc
public init(message: TSOutgoingMessage, public init(message: TSOutgoingMessage,
thread: TSThread?, thread: TSThread?,
recipient: SignalRecipient, recipient: SignalRecipient,
senderCertificate: SMKSenderCertificate?, senderCertificate: SMKSenderCertificate?,
udManager: OWSUDManager, udManager: OWSUDManager,
localNumber: String) { localNumber: String,
success: @escaping () -> Void,
failure: @escaping (Error) -> Void) {
self.message = message self.message = message
self.thread = thread self.thread = thread
self.recipient = recipient self.recipient = recipient
@ -70,6 +78,9 @@ public class OWSMessageSend: NSObject {
self.udAccessKey = udAccessKey self.udAccessKey = udAccessKey
self.localNumber = localNumber self.localNumber = localNumber
self.isLocalNumber = isLocalNumber self.isLocalNumber = isLocalNumber
self.success = success
self.failure = failure
} }
@objc @objc

@ -58,6 +58,16 @@ NS_ASSUME_NONNULL_BEGIN
const NSUInteger kOversizeTextMessageSizeThreshold = 2 * 1024; const NSUInteger kOversizeTextMessageSizeThreshold = 2 * 1024;
NSError *SSKEnsureError(NSError *_Nullable error, OWSErrorCode fallbackCode, NSString *fallbackErrorDescription)
{
if (error) {
return error;
}
return OWSErrorWithCodeDescription(fallbackCode, fallbackErrorDescription);
}
#pragma mark -
void AssertIsOnSendingQueue() void AssertIsOnSendingQueue()
{ {
#ifdef DEBUG #ifdef DEBUG
@ -472,46 +482,32 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[self.udManager [self.udManager
ensureSenderCertificateObjCWithSuccess:^(SMKSenderCertificate *senderCertificate) { ensureSenderCertificateObjCWithSuccess:^(SMKSenderCertificate *senderCertificate) {
dispatch_async([OWSDispatch sendingQueue], ^{
[self sendMessageToService:message senderCertificate:senderCertificate success:success failure:failure]; [self sendMessageToService:message senderCertificate:senderCertificate success:success failure:failure];
});
} }
failure:^(NSError *error) { failure:^(NSError *error) {
OWSLogError(@"Could not obtain UD sender certificate: %@", error); OWSLogError(@"Could not obtain UD sender certificate: %@", error);
// Proceed using non-UD message sends. // Proceed using non-UD message sends.
dispatch_async([OWSDispatch sendingQueue], ^{
[self sendMessageToService:message senderCertificate:nil success:success failure:failure]; [self sendMessageToService:message senderCertificate:nil success:success failure:failure];
});
}]; }];
} }
- (void)sendMessageToService:(TSOutgoingMessage *)message - (nullable NSArray<NSString *> *)unsentRecipientsForMessage:(TSOutgoingMessage *)message
senderCertificate:(nullable SMKSenderCertificate *)senderCertificate thread:(nullable TSThread *)thread
success:(void (^)(void))successHandler error:(NSError **)errorHandle
failure:(RetryableFailureHandler)failureHandler
{ {
dispatch_async([OWSDispatch sendingQueue], ^{ OWSAssertDebug(message);
TSThread *_Nullable thread = message.thread; OWSAssertDebug(errorHandle);
// In the "self-send" special case, we ony need to send a sync message with a delivery receipt.
if ([thread isKindOfClass:[TSContactThread class]] &&
[((TSContactThread *)thread).contactIdentifier isEqualToString:[TSAccountManager localNumber]]) {
// Send to self.
OWSAssertDebug(message.recipientIds.count == 1);
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
for (NSString *recipientId in message.sendingRecipientIds) {
[message updateWithReadRecipientId:recipientId
readTimestamp:message.timestampForSorting
transaction:transaction];
}
}];
[self handleMessageSentLocally:message senderCertificate:senderCertificate];
successHandler();
return;
}
NSMutableSet<NSString *> *recipientIds = [NSMutableSet new]; NSMutableSet<NSString *> *recipientIds = [NSMutableSet new];
if (thread.isGroupThread) { if ([message isKindOfClass:[OWSOutgoingSyncMessage class]]) {
TSGroupThread *gThread = (TSGroupThread *)thread; [recipientIds addObject:[TSAccountManager localNumber]];
} else if (thread.isGroupThread) {
TSGroupThread *groupThread = (TSGroupThread *)thread;
// Send to the intersection of: // Send to the intersection of:
// //
@ -526,13 +522,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[recipientIds addObjectsFromArray:message.sendingRecipientIds]; [recipientIds addObjectsFromArray:message.sendingRecipientIds];
// Only send to members in the latest known group member list. // Only send to members in the latest known group member list.
[recipientIds intersectSet:[NSSet setWithArray:gThread.groupModel.groupMemberIds]]; [recipientIds intersectSet:[NSSet setWithArray:groupThread.groupModel.groupMemberIds]];
if ([recipientIds containsObject:TSAccountManager.localNumber]) { if ([recipientIds containsObject:TSAccountManager.localNumber]) {
OWSFailDebug(@"Message send recipients should not include self."); OWSFailDebug(@"Message send recipients should not include self.");
} }
} else if ([message isKindOfClass:[OWSOutgoingSyncMessage class]]) {
[recipientIds addObject:[TSAccountManager localNumber]];
} else if ([thread isKindOfClass:[TSContactThread class]]) { } else if ([thread isKindOfClass:[TSContactThread class]]) {
NSString *recipientContactId = ((TSContactThread *)thread).contactIdentifier; NSString *recipientContactId = ((TSContactThread *)thread).contactIdentifier;
@ -545,10 +539,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if ([self.blockingManager isRecipientIdBlocked:recipientContactId]) { if ([self.blockingManager isRecipientIdBlocked:recipientContactId]) {
OWSLogInfo(@"skipping 1:1 send to blocked contact: %@", recipientContactId); OWSLogInfo(@"skipping 1:1 send to blocked contact: %@", recipientContactId);
NSError *error = OWSErrorMakeMessageSendFailedToBlockListError(); NSError *error = OWSErrorMakeMessageSendFailedToBlockListError();
// No need to retry - the user will continue to be blocked.
[error setIsRetryable:NO]; [error setIsRetryable:NO];
failureHandler(error); *errorHandle = error;
return; return nil;
} }
[recipientIds addObject:recipientContactId]; [recipientIds addObject:recipientContactId];
@ -559,78 +552,52 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} else { } else {
// Neither a group nor contact thread? This should never happen. // Neither a group nor contact thread? This should never happen.
OWSFailDebug(@"Unknown message type: %@", [message class]); OWSFailDebug(@"Unknown message type: %@", [message class]);
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
[error setIsRetryable:NO]; [error setIsRetryable:NO];
failureHandler(error); *errorHandle = error;
return; return nil;
} }
[recipientIds minusSet:[NSSet setWithArray:self.blockingManager.blockedPhoneNumbers]]; [recipientIds minusSet:[NSSet setWithArray:self.blockingManager.blockedPhoneNumbers]];
return recipientIds.allObjects;
// Mark skipped recipients as such. We skip because:
//
// * Recipient is no longer in the group.
// * Recipient is blocked.
//
// Elsewhere, we skip recipient if their Signal account has been deactivated.
NSMutableSet<NSString *> *obsoleteRecipientIds = [NSMutableSet setWithArray:message.sendingRecipientIds];
[obsoleteRecipientIds minusSet:recipientIds];
if (obsoleteRecipientIds.count > 0) {
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
for (NSString *recipientId in obsoleteRecipientIds) {
// Mark this recipient as "skipped".
[message updateWithSkippedRecipient:recipientId transaction:transaction];
}
}];
} }
if (recipientIds.count < 1) { - (NSArray<SignalRecipient *> *)recipientsForRecipientIds:(NSArray<NSString *> *)recipientIds
// All recipients are already sent or can be skipped. {
successHandler(); OWSAssertDebug(recipientIds.count > 0);
return;
}
NSMutableArray<OWSMessageSend *> *messageSends = [NSMutableArray new]; NSMutableArray<SignalRecipient *> *recipients = [NSMutableArray new];
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
for (NSString *recipientId in recipientIds) { for (NSString *recipientId in recipientIds) {
SignalRecipient *recipient = SignalRecipient *recipient =
[SignalRecipient getOrBuildUnsavedRecipientForRecipientId:recipientId transaction:transaction]; [SignalRecipient getOrBuildUnsavedRecipientForRecipientId:recipientId transaction:transaction];
OWSMessageSend *messageSend = [recipients addObject:recipient];
[[OWSMessageSend alloc] initWithMessage:message
thread:thread
recipient:recipient
senderCertificate:senderCertificate
udManager:self.udManager
localNumber:self.tsAccountManager.localNumber];
[messageSends addObject:messageSend];
} }
}]; }];
OWSAssertDebug(messageSends.count == recipientIds.count); return [recipients copy];
OWSAssertDebug(messageSends.count > 0);
[self sendWithMessageSends:messageSends
isGroupSend:thread.isGroupThread
success:successHandler
failure:failureHandler];
});
} }
- (void)sendWithMessageSends:(NSArray<OWSMessageSend *> *)messageSends - (AnyPromise *)sendPromiseForRecipients:(NSArray<SignalRecipient *> *)recipients
isGroupSend:(BOOL)isGroupSend message:(TSOutgoingMessage *)message
success:(void (^)(void))successHandler thread:(nullable TSThread *)thread
failure:(RetryableFailureHandler)failureHandler senderCertificate:(nullable SMKSenderCertificate *)senderCertificate
sendErrors:(NSMutableArray<NSError *> *)sendErrors
{ {
OWSAssertDebug(messageSends.count > 0); OWSAssertDebug(recipients.count > 0);
AssertIsOnSendingQueue(); OWSAssertDebug(message);
OWSAssertDebug(sendErrors);
NSMutableArray<AnyPromise *> *sendPromises = [NSMutableArray array]; NSMutableArray<AnyPromise *> *sendPromises = [NSMutableArray array];
NSMutableArray<NSError *> *sendErrors = [NSMutableArray array];
for (OWSMessageSend *messageSend in messageSends) { for (SignalRecipient *recipient in recipients) {
// For group sends, we're using chained promises to make the code more readable. // Use chained promises to make the code more readable.
AnyPromise *sendPromise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { AnyPromise *sendPromise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[self sendMessageToRecipient:messageSend OWSMessageSend *messageSend = [[OWSMessageSend alloc] initWithMessage:message
thread:thread
recipient:recipient
senderCertificate:senderCertificate
udManager:self.udManager
localNumber:self.tsAccountManager.localNumber
success:^{ success:^{
// The value doesn't matter, we just need any non-NSError value. // The value doesn't matter, we just need any non-NSError value.
resolve(@(1)); resolve(@(1));
@ -641,6 +608,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
resolve(error); resolve(error);
}]; }];
[self sendMessageToRecipient:messageSend];
}]; }];
[sendPromises addObject:sendPromise]; [sendPromises addObject:sendPromise];
} }
@ -649,11 +617,82 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// completion promise to execute until _all_ send promises // completion promise to execute until _all_ send promises
// have either succeeded or failed. PMKWhen() executes as // have either succeeded or failed. PMKWhen() executes as
// soon as any of its input promises fail. // soon as any of its input promises fail.
AnyPromise *sendCompletionPromise = PMKJoin(sendPromises); return PMKJoin(sendPromises);
sendCompletionPromise.then(^(id value) { }
- (void)sendMessageToService:(TSOutgoingMessage *)message
senderCertificate:(nullable SMKSenderCertificate *)senderCertificate
success:(void (^)(void))successHandler
failure:(RetryableFailureHandler)failureHandler
{
AssertIsOnSendingQueue();
TSThread *_Nullable thread = message.thread;
// In the "self-send" special case, we ony need to send a sync message with a delivery receipt.
if ([thread isKindOfClass:[TSContactThread class]] &&
[((TSContactThread *)thread).contactIdentifier isEqualToString:[TSAccountManager localNumber]]) {
// Send to self.
OWSAssertDebug(message.recipientIds.count == 1);
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
for (NSString *recipientId in message.sendingRecipientIds) {
[message updateWithReadRecipientId:recipientId
readTimestamp:message.timestampForSorting
transaction:transaction];
}
}];
[self handleMessageSentLocally:message senderCertificate:senderCertificate];
successHandler();
return;
}
NSError *error;
NSArray<NSString *> *_Nullable recipientIds = [self unsentRecipientsForMessage:message thread:thread error:&error];
if (error || !recipientIds) {
error = SSKEnsureError(
error, OWSErrorCodeMessageSendNoValidRecipients, @"Could not build recipients list for message.");
[error setIsRetryable:NO];
return failureHandler(error);
}
// Mark skipped recipients as such. We skip because:
//
// * Recipient is no longer in the group.
// * Recipient is blocked.
//
// Elsewhere, we skip recipient if their Signal account has been deactivated.
NSMutableSet<NSString *> *obsoleteRecipientIds = [NSMutableSet setWithArray:message.sendingRecipientIds];
[obsoleteRecipientIds minusSet:[NSSet setWithArray:recipientIds]];
if (obsoleteRecipientIds.count > 0) {
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
for (NSString *recipientId in obsoleteRecipientIds) {
// Mark this recipient as "skipped".
[message updateWithSkippedRecipient:recipientId transaction:transaction];
}
}];
}
if (recipientIds.count < 1) {
// All recipients are already sent or can be skipped.
successHandler();
return;
}
NSArray<SignalRecipient *> *recipients = [self recipientsForRecipientIds:recipientIds];
BOOL isGroupSend = (thread && thread.isGroupThread);
NSMutableArray<NSError *> *sendErrors = [NSMutableArray array];
AnyPromise *sendPromise = [self sendPromiseForRecipients:recipients
message:message
thread:thread
senderCertificate:senderCertificate
sendErrors:sendErrors]
.then(^(id value) {
successHandler(); successHandler();
}); });
sendCompletionPromise.catch(^(id failure) { sendPromise.catch(^(id failure) {
NSError *firstRetryableError = nil; NSError *firstRetryableError = nil;
NSError *firstNonRetryableError = nil; NSError *firstNonRetryableError = nil;
@ -697,7 +736,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// If we only received errors that we should ignore, // If we only received errors that we should ignore,
// consider this send a success, unless the message could // consider this send a success, unless the message could
// not be sent to any recipient. // not be sent to any recipient.
if (messageSends.lastObject.message.sentRecipientsCount == 0) { if (message.sentRecipientsCount == 0) {
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageSendNoValidRecipients, NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageSendNoValidRecipients,
NSLocalizedString(@"ERROR_DESCRIPTION_NO_VALID_RECIPIENTS", NSLocalizedString(@"ERROR_DESCRIPTION_NO_VALID_RECIPIENTS",
@"Error indicating that an outgoing message had no valid recipients.")); @"Error indicating that an outgoing message had no valid recipients."));
@ -708,7 +747,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
} }
}); });
[sendCompletionPromise retainUntilComplete]; [sendPromise retainUntilComplete];
} }
- (void)unregisteredRecipient:(SignalRecipient *)recipient - (void)unregisteredRecipient:(SignalRecipient *)recipient
@ -835,8 +874,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
- (void)sendMessageToRecipient:(OWSMessageSend *)messageSend - (void)sendMessageToRecipient:(OWSMessageSend *)messageSend
success:(void (^)(void))successHandler
failure:(RetryableFailureHandler)failureHandler
{ {
OWSAssertDebug(messageSend); OWSAssertDebug(messageSend);
OWSAssertDebug(messageSend.thread || [messageSend.message isKindOfClass:[OWSOutgoingSyncMessage class]]); OWSAssertDebug(messageSend.thread || [messageSend.message isKindOfClass:[OWSOutgoingSyncMessage class]]);
@ -863,11 +900,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
OWSLogInfo(@"New prekeys registered with server."); OWSLogInfo(@"New prekeys registered with server.");
NSError *error = OWSErrorMakeMessageSendDisabledDueToPreKeyUpdateFailuresError(); NSError *error = OWSErrorMakeMessageSendDisabledDueToPreKeyUpdateFailuresError();
[error setIsRetryable:YES]; [error setIsRetryable:YES];
return failureHandler(error); return messageSend.failure(error);
} }
failure:^(NSError *error) { failure:^(NSError *error) {
OWSLogWarn(@"Failed to update prekeys with the server: %@", error); OWSLogWarn(@"Failed to update prekeys with the server: %@", error);
return failureHandler(error); return messageSend.failure(error);
}]; }];
} }
@ -877,7 +914,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
[error setIsRetryable:YES]; [error setIsRetryable:YES];
return failureHandler(error); return messageSend.failure(error);
} }
// Consume an attempt. // Consume an attempt.
@ -888,7 +925,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[self deviceMessagesForMessageSendSafe:messageSend error:&deviceMessagesError]; [self deviceMessagesForMessageSendSafe:messageSend error:&deviceMessagesError];
if (deviceMessagesError || !deviceMessages) { if (deviceMessagesError || !deviceMessages) {
OWSAssertDebug(deviceMessagesError); OWSAssertDebug(deviceMessagesError);
return failureHandler(deviceMessagesError); return messageSend.failure(deviceMessagesError);
} }
if (messageSend.isLocalNumber) { if (messageSend.isLocalNumber) {
@ -925,7 +962,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[message updateWithSkippedRecipient:messageSend.localNumber transaction:transaction]; [message updateWithSkippedRecipient:messageSend.localNumber transaction:transaction];
}]; }];
successHandler(); messageSend.success();
}); });
return; return;
@ -971,7 +1008,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (!messageSend.hasWebsocketSendFailed && TSSocketManager.canMakeRequests && !messageSend.isUDSend) { if (!messageSend.hasWebsocketSendFailed && TSSocketManager.canMakeRequests && !messageSend.isUDSend) {
[TSSocketManager.sharedManager makeRequest:request [TSSocketManager.sharedManager makeRequest:request
success:^(id _Nullable responseObject) { success:^(id _Nullable responseObject) {
[self messageSendDidSucceed:messageSend deviceMessages:deviceMessages success:successHandler]; [self messageSendDidSucceed:messageSend deviceMessages:deviceMessages];
} }
failure:^(NSInteger statusCode, NSData *_Nullable responseData, NSError *error) { failure:^(NSInteger statusCode, NSData *_Nullable responseData, NSError *error) {
dispatch_async([OWSDispatch sendingQueue], ^{ dispatch_async([OWSDispatch sendingQueue], ^{
@ -981,13 +1018,13 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// failure. Instead we fall back to REST, which will decrement retries. e.g. after linking a new // failure. Instead we fall back to REST, which will decrement retries. e.g. after linking a new
// device, sync messages will fail until the websocket re-opens. // device, sync messages will fail until the websocket re-opens.
messageSend.hasWebsocketSendFailed = YES; messageSend.hasWebsocketSendFailed = YES;
[self sendMessageToRecipient:messageSend success:successHandler failure:failureHandler]; [self sendMessageToRecipient:messageSend];
}); });
}]; }];
} else { } else {
[self.networkManager makeRequest:request [self.networkManager makeRequest:request
success:^(NSURLSessionDataTask *task, id responseObject) { success:^(NSURLSessionDataTask *task, id responseObject) {
[self messageSendDidSucceed:messageSend deviceMessages:deviceMessages success:successHandler]; [self messageSendDidSucceed:messageSend deviceMessages:deviceMessages];
} }
failure:^(NSURLSessionDataTask *task, NSError *error) { failure:^(NSURLSessionDataTask *task, NSError *error) {
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response; NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
@ -1003,7 +1040,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[self.udManager setSupportsUnidentifiedDelivery:NO recipientId:recipient.uniqueId]; [self.udManager setSupportsUnidentifiedDelivery:NO recipientId:recipient.uniqueId];
messageSend.hasUDAuthFailed = YES; messageSend.hasUDAuthFailed = YES;
dispatch_async([OWSDispatch sendingQueue], ^{ dispatch_async([OWSDispatch sendingQueue], ^{
[self sendMessageToRecipient:messageSend success:successHandler failure:failureHandler]; [self sendMessageToRecipient:messageSend];
}); });
return; return;
} }
@ -1012,20 +1049,16 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
deviceMessages:deviceMessages deviceMessages:deviceMessages
statusCode:statusCode statusCode:statusCode
error:error error:error
responseData:responseData responseData:responseData];
success:successHandler
failure:failureHandler];
}]; }];
} }
} }
- (void)messageSendDidSucceed:(OWSMessageSend *)messageSend - (void)messageSendDidSucceed:(OWSMessageSend *)messageSend
deviceMessages:(NSArray<NSDictionary *> *)deviceMessages deviceMessages:(NSArray<NSDictionary *> *)deviceMessages
success:(void (^)(void))successHandler
{ {
OWSAssertDebug(messageSend); OWSAssertDebug(messageSend);
OWSAssertDebug(deviceMessages); OWSAssertDebug(deviceMessages);
OWSAssertDebug(successHandler);
SignalRecipient *recipient = messageSend.recipient; SignalRecipient *recipient = messageSend.recipient;
@ -1053,7 +1086,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
}]; }];
[self handleMessageSentLocally:messageSend.message senderCertificate:messageSend.senderCertificate]; [self handleMessageSentLocally:messageSend.message senderCertificate:messageSend.senderCertificate];
successHandler(); messageSend.success();
}); });
} }
@ -1062,15 +1095,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
statusCode:(NSInteger)statusCode statusCode:(NSInteger)statusCode
error:(NSError *)responseError error:(NSError *)responseError
responseData:(nullable NSData *)responseData responseData:(nullable NSData *)responseData
success:(void (^)(void))successHandler
failure:(RetryableFailureHandler)failureHandler
{ {
OWSAssertDebug(messageSend); OWSAssertDebug(messageSend);
OWSAssertDebug(messageSend.thread || [messageSend.message isKindOfClass:[OWSOutgoingSyncMessage class]]); OWSAssertDebug(messageSend.thread || [messageSend.message isKindOfClass:[OWSOutgoingSyncMessage class]]);
OWSAssertDebug(deviceMessages); OWSAssertDebug(deviceMessages);
OWSAssertDebug(responseError); OWSAssertDebug(responseError);
OWSAssertDebug(successHandler);
OWSAssertDebug(failureHandler);
TSOutgoingMessage *message = messageSend.message; TSOutgoingMessage *message = messageSend.message;
SignalRecipient *recipient = messageSend.recipient; SignalRecipient *recipient = messageSend.recipient;
@ -1082,13 +1111,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// Since we've already repeatedly failed to send to the messaging API, // Since we've already repeatedly failed to send to the messaging API,
// it's unlikely that repeating the whole process will succeed. // it's unlikely that repeating the whole process will succeed.
[responseError setIsRetryable:NO]; [responseError setIsRetryable:NO];
return failureHandler(responseError); return messageSend.failure(responseError);
} }
dispatch_async([OWSDispatch sendingQueue], ^{ dispatch_async([OWSDispatch sendingQueue], ^{
OWSLogDebug(@"Retrying: %@", message.debugDescription); OWSLogDebug(@"Retrying: %@", message.debugDescription);
// TODO: Should this use sendMessageToRecipient or sendMessageToService? [self sendMessageToRecipient:messageSend];
[self sendMessageToRecipient:messageSend success:successHandler failure:failureHandler];
}); });
}; };
@ -1108,7 +1136,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// the group should ignore errors when trying to send // the group should ignore errors when trying to send
// messages to this ex-member. // messages to this ex-member.
[error setShouldBeIgnoredForGroups:YES]; [error setShouldBeIgnoredForGroups:YES];
failureHandler(error); messageSend.failure(error);
}); });
}; };
@ -1121,7 +1149,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
@"ERROR_DESCRIPTION_SENDING_UNAUTHORIZED", @"Error message when attempting to send message")); @"ERROR_DESCRIPTION_SENDING_UNAUTHORIZED", @"Error message when attempting to send message"));
// No need to retry if we've been de-authed. // No need to retry if we've been de-authed.
[error setIsRetryable:NO]; [error setIsRetryable:NO];
return failureHandler(error); return messageSend.failure(error);
} }
case 404: { case 404: {
handle404(); handle404();
@ -1139,7 +1167,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (error || !responseJson) { if (error || !responseJson) {
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotParseMismatchedDevicesJson]); OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotParseMismatchedDevicesJson]);
[error setIsRetryable:YES]; [error setIsRetryable:YES];
return failureHandler(error); return messageSend.failure(error);
} }
NSNumber *_Nullable errorCode = responseJson[@"code"]; NSNumber *_Nullable errorCode = responseJson[@"code"];
@ -1165,7 +1193,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
OWSLogWarn(@"Stale devices but server didn't specify devices in response."); OWSLogWarn(@"Stale devices but server didn't specify devices in response.");
NSError *error = OWSErrorMakeUnableToProcessServerResponseError(); NSError *error = OWSErrorMakeUnableToProcessServerResponseError();
[error setIsRetryable:YES]; [error setIsRetryable:YES];
return failureHandler(error); return messageSend.failure(error);
} }
[self handleStaleDevicesWithResponseJson:responseJson recipientId:recipient.uniqueId completion:retrySend]; [self handleStaleDevicesWithResponseJson:responseJson recipientId:recipient.uniqueId completion:retrySend];
@ -1260,9 +1288,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
recipient:recipient recipient:recipient
senderCertificate:senderCertificate senderCertificate:senderCertificate
udManager:self.udManager udManager:self.udManager
localNumber:self.tsAccountManager.localNumber]; localNumber:self.tsAccountManager.localNumber
[self sendMessageToRecipient:messageSend
success:^{ success:^{
OWSLogInfo(@"Successfully sent sync transcript."); OWSLogInfo(@"Successfully sent sync transcript.");
} }
@ -1274,6 +1300,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// messaging API. // messaging API.
OWSLogInfo(@"Failed to send sync transcript: %@ (isRetryable: %d)", error, [error isRetryable]); OWSLogInfo(@"Failed to send sync transcript: %@ (isRetryable: %d)", error, [error isRetryable]);
}]; }];
[self sendMessageToRecipient:messageSend];
} }
// NOTE: This method uses exceptions for control flow. // NOTE: This method uses exceptions for control flow.

Loading…
Cancel
Save