session-ios/SignalServiceKit/src/Messages/OWSMessageSender.m

1390 lines
56 KiB
Mathematica
Raw Normal View History

//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSMessageSender.h"
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
#import "ContactsUpdater.h"
#import "NSData+keyVersionByte.h"
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
#import "NSData+messagePadding.h"
2017-04-03 20:42:04 +02:00
#import "OWSBlockingManager.h"
2017-02-16 00:32:27 +01:00
#import "OWSDevice.h"
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
#import "OWSDisappearingMessagesJob.h"
#import "OWSError.h"
#import "OWSIdentityManager.h"
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
#import "OWSMessageServiceParams.h"
#import "OWSOutgoingSentMessageTranscript.h"
#import "OWSOutgoingSyncMessage.h"
#import "OWSUploadingService.h"
#import "PreKeyBundle+jsonDict.h"
#import "SignalRecipient.h"
#import "TSAccountManager.h"
#import "TSAttachmentStream.h"
#import "TSContactThread.h"
#import "TSGroupThread.h"
#import "TSIncomingMessage.h"
#import "TSInfoMessage.h"
#import "TSInvalidIdentityKeySendingErrorMessage.h"
#import "TSNetworkManager.h"
#import "TSOutgoingMessage.h"
2017-02-10 19:20:11 +01:00
#import "TSPreKeyManager.h"
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
#import "TSStorageManager+PreKeyStore.h"
#import "TSStorageManager+SignedPreKeyStore.h"
#import "TSStorageManager+sessionStore.h"
#import "TSStorageManager.h"
#import "TSThread.h"
#import "Threading.h"
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
#import <AxolotlKit/AxolotlExceptions.h>
#import <AxolotlKit/CipherMessage.h>
#import <AxolotlKit/PreKeyBundle.h>
#import <AxolotlKit/SessionBuilder.h>
#import <AxolotlKit/SessionCipher.h>
#import <TwistedOakCollapsingFutures/CollapsingFutures.h>
#import <objc/runtime.h>
NS_ASSUME_NONNULL_BEGIN
void AssertIsOnSendingQueue()
{
2017-04-07 18:46:42 +02:00
#ifdef DEBUG
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(10, 0)) {
dispatch_assert_queue([OWSDispatch sendingQueue]);
} // else, skip assert as it's a development convenience.
2017-04-07 18:46:42 +02:00
#endif
}
static void *kNSError_MessageSender_IsRetryable = &kNSError_MessageSender_IsRetryable;
static void *kNSError_MessageSender_ShouldBeIgnoredForGroups = &kNSError_MessageSender_ShouldBeIgnoredForGroups;
static void *kNSError_MessageSender_IsFatal = &kNSError_MessageSender_IsFatal;
// isRetryable and isFatal are opposites but not redundant.
//
// If a group message send fails, the send will be retried if any of the errors were retryable UNLESS
// any of the errors were fatal. Fatal errors trump retryable errors.
@implementation NSError (OWSMessageSender)
- (BOOL)isRetryable
{
NSNumber *value = objc_getAssociatedObject(self, kNSError_MessageSender_IsRetryable);
// This value should always be set for all errors by the time OWSSendMessageOperation
// queries it's value. If not, default to retrying in production.
OWSAssert(value);
return value ? [value boolValue] : YES;
}
- (void)setIsRetryable:(BOOL)value
{
objc_setAssociatedObject(self, kNSError_MessageSender_IsRetryable, @(value), OBJC_ASSOCIATION_COPY);
}
- (BOOL)shouldBeIgnoredForGroups
{
NSNumber *value = objc_getAssociatedObject(self, kNSError_MessageSender_ShouldBeIgnoredForGroups);
// This value will NOT always be set for all errors by the time we query it's value.
// Default to NOT ignoring.
return value ? [value boolValue] : NO;
}
- (void)setShouldBeIgnoredForGroups:(BOOL)value
{
objc_setAssociatedObject(self, kNSError_MessageSender_ShouldBeIgnoredForGroups, @(value), OBJC_ASSOCIATION_COPY);
}
- (BOOL)isFatal
{
NSNumber *value = objc_getAssociatedObject(self, kNSError_MessageSender_IsFatal);
// This value will NOT always be set for all errors by the time we query it's value.
// Default to NOT fatal.
return value ? [value boolValue] : NO;
}
- (void)setIsFatal:(BOOL)value
{
objc_setAssociatedObject(self, kNSError_MessageSender_IsFatal, @(value), OBJC_ASSOCIATION_COPY);
}
@end
#pragma mark -
/**
* OWSSendMessageOperation encapsulates all the work associated with sending a message, e.g. uploading attachments,
* getting proper keys, and retrying upon failure.
*
* Used by `OWSMessageSender` to serialize message sending, ensuring that messages are emitted in the order they
* were sent.
*/
@interface OWSSendMessageOperation : NSOperation
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithMessage:(TSOutgoingMessage *)message
messageSender:(OWSMessageSender *)messageSender
success:(void (^)())successHandler
failure:(void (^)(NSError *_Nonnull error))failureHandler NS_DESIGNATED_INITIALIZER;
#pragma mark - background task mgmt
- (void)startBackgroundTask;
- (void)endBackgroundTask;
@end
#pragma mark -
typedef NS_ENUM(NSInteger, OWSSendMessageOperationState) {
OWSSendMessageOperationStateNew,
OWSSendMessageOperationStateExecuting,
OWSSendMessageOperationStateFinished
};
@interface OWSMessageSender (OWSSendMessageOperation)
- (void)attemptToSendMessage:(TSOutgoingMessage *)message
success:(void (^)())successHandler
failure:(RetryableFailureHandler)failureHandler;
@end
#pragma mark -
NSString *const OWSSendMessageOperationKeyIsExecuting = @"isExecuting";
NSString *const OWSSendMessageOperationKeyIsFinished = @"isFinished";
NSUInteger const OWSSendMessageOperationMaxRetries = 4;
@interface OWSSendMessageOperation ()
@property (nonatomic, readonly) TSOutgoingMessage *message;
@property (nonatomic, readonly) OWSMessageSender *messageSender;
@property (nonatomic, readonly) void (^successHandler)();
@property (nonatomic, readonly) void (^failureHandler)(NSError *_Nonnull error);
@property (nonatomic) OWSSendMessageOperationState operationState;
@property (nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier;
@end
#pragma mark -
@implementation OWSSendMessageOperation
- (instancetype)initWithMessage:(TSOutgoingMessage *)message
messageSender:(OWSMessageSender *)messageSender
success:(void (^)())aSuccessHandler
failure:(void (^)(NSError *_Nonnull error))aFailureHandler
{
self = [super init];
if (!self) {
return self;
}
_operationState = OWSSendMessageOperationStateNew;
_backgroundTaskIdentifier = UIBackgroundTaskInvalid;
_message = message;
_messageSender = messageSender;
__weak typeof(self) weakSelf = self;
_successHandler = ^{
typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
OWSProdCFail([OWSAnalyticsEvents messageSenderErrorSendOperationDidNotComplete]);
return;
}
[message updateWithMessageState:TSOutgoingMessageStateSentToService];
aSuccessHandler();
2017-06-17 19:41:29 +02:00
[strongSelf markAsComplete];
};
_failureHandler = ^(NSError *_Nonnull error) {
typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
OWSProdCFail([OWSAnalyticsEvents messageSenderErrorSendOperationDidNotComplete]);
return;
}
[strongSelf.message updateWithSendingError:error];
2017-04-10 18:35:30 +02:00
DDLogDebug(@"%@ failed with error: %@", strongSelf.tag, error);
aFailureHandler(error);
2017-06-17 19:41:29 +02:00
[strongSelf markAsComplete];
};
return self;
}
#pragma mark - background task mgmt
// We want to make sure to finish sending any in-flight messages when the app is backgrounded.
// We have to call `startBackgroundTask` *before* the task is enqueued, since we can't guarantee when the operation will
// be dequeued.
- (void)startBackgroundTask
{
AssertIsOnMainThread();
OWSAssert(self.backgroundTaskIdentifier == UIBackgroundTaskInvalid);
self.backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
DDLogWarn(@"%@ Timed out while in background trying to send message: %@", self.tag, self.message);
[self endBackgroundTask];
}];
}
- (void)endBackgroundTask
{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier];
}
- (void)setBackgroundTaskIdentifier:(UIBackgroundTaskIdentifier)backgroundTaskIdentifier
{
AssertIsOnMainThread();
// Should only be sent once per operation
OWSAssert(_backgroundTaskIdentifier == UIBackgroundTaskInvalid);
OWSAssert(backgroundTaskIdentifier != UIBackgroundTaskInvalid);
_backgroundTaskIdentifier = backgroundTaskIdentifier;
}
#pragma mark - NSOperation overrides
- (BOOL)isExecuting
{
return self.operationState == OWSSendMessageOperationStateExecuting;
}
- (BOOL)isFinished
{
return self.operationState == OWSSendMessageOperationStateFinished;
}
- (void)start
{
// Should call `startBackgroundTask` before enqueuing the operation
// to ensure we don't get suspended before the operation completes.
OWSAssert(self.backgroundTaskIdentifier != UIBackgroundTaskInvalid);
[self willChangeValueForKey:OWSSendMessageOperationKeyIsExecuting];
self.operationState = OWSSendMessageOperationStateExecuting;
[self didChangeValueForKey:OWSSendMessageOperationKeyIsExecuting];
[self main];
}
- (void)main
{
[self tryWithRemainingRetries:OWSSendMessageOperationMaxRetries];
}
#pragma mark - methods
- (void)tryWithRemainingRetries:(NSUInteger)remainingRetries
{
// Use this flag to ensure a given operation only succeeds or fails once.
__block BOOL onceFlag = NO;
RetryableFailureHandler retryableFailureHandler = ^(NSError *_Nonnull error) {
2017-07-10 18:52:22 +02:00
DDLogInfo(@"%@ Sending failed. Remaining retries: %lu", self.tag, (unsigned long)remainingRetries);
OWSAssert(!onceFlag);
onceFlag = YES;
if (![error isRetryable] || [error isFatal]) {
DDLogInfo(@"%@ Skipping retry due to terminal error: %@", self.tag, error);
self.failureHandler(error);
return;
}
if (remainingRetries > 0) {
[self tryWithRemainingRetries:remainingRetries - 1];
} else {
DDLogWarn(@"%@ Too many failures. Giving up sending.", self.tag);
self.failureHandler(error);
}
};
[self.messageSender attemptToSendMessage:self.message
success:^{
OWSAssert(!onceFlag);
onceFlag = YES;
self.successHandler();
}
failure:retryableFailureHandler];
}
- (void)markAsComplete
{
[self willChangeValueForKey:OWSSendMessageOperationKeyIsExecuting];
[self willChangeValueForKey:OWSSendMessageOperationKeyIsFinished];
2017-06-17 19:41:29 +02:00
// Ensure we call the success or failure handler exactly once.
@synchronized(self)
{
OWSAssert(self.operationState != OWSSendMessageOperationStateFinished);
self.operationState = OWSSendMessageOperationStateFinished;
}
[self didChangeValueForKey:OWSSendMessageOperationKeyIsExecuting];
[self didChangeValueForKey:OWSSendMessageOperationKeyIsFinished];
[self endBackgroundTask];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
int const OWSMessageSenderRetryAttempts = 3;
NSString *const OWSMessageSenderInvalidDeviceException = @"InvalidDeviceException";
NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
@interface OWSMessageSender ()
@property (nonatomic, readonly) TSNetworkManager *networkManager;
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
@property (nonatomic, readonly) TSStorageManager *storageManager;
2017-04-03 20:42:04 +02:00
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
@property (nonatomic, readonly) OWSUploadingService *uploadingService;
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
@property (nonatomic, readonly) id<ContactsManagerProtocol> contactsManager;
@property (nonatomic, readonly) ContactsUpdater *contactsUpdater;
2017-03-23 19:35:30 +01:00
@property (atomic, readonly) NSMutableDictionary<NSString *, NSOperationQueue *> *sendingQueueMap;
@end
@implementation OWSMessageSender
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
- (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager
storageManager:(TSStorageManager *)storageManager
contactsManager:(id<ContactsManagerProtocol>)contactsManager
contactsUpdater:(ContactsUpdater *)contactsUpdater
{
self = [super init];
if (!self) {
return self;
}
_networkManager = networkManager;
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
_storageManager = storageManager;
_contactsManager = contactsManager;
_contactsUpdater = contactsUpdater;
_sendingQueueMap = [NSMutableDictionary new];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
_uploadingService = [[OWSUploadingService alloc] initWithNetworkManager:networkManager];
_dbConnection = storageManager.newDatabaseConnection;
OWSSingletonAssert();
return self;
}
2017-04-03 20:42:04 +02:00
- (void)setBlockingManager:(OWSBlockingManager *)blockingManager
{
OWSAssert(blockingManager);
OWSAssert(!_blockingManager);
_blockingManager = blockingManager;
}
- (NSOperationQueue *)sendingQueueForMessage:(TSOutgoingMessage *)message
{
OWSAssert(message);
NSString *kDefaultQueueKey = @"kDefaultQueueKey";
NSString *queueKey = message.uniqueThreadId ?: kDefaultQueueKey;
OWSAssert(queueKey.length > 0);
@synchronized(self)
{
NSOperationQueue *sendingQueue = self.sendingQueueMap[queueKey];
if (!sendingQueue) {
sendingQueue = [NSOperationQueue new];
sendingQueue.qualityOfService = NSOperationQualityOfServiceUserInitiated;
sendingQueue.maxConcurrentOperationCount = 1;
self.sendingQueueMap[queueKey] = sendingQueue;
}
return sendingQueue;
}
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
- (void)sendMessage:(TSOutgoingMessage *)message
success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler
{
OWSAssert(message);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// This method will use a read/write transaction. This transaction
// will block until any open read/write transactions are complete.
//
// That's key - we don't want to send any messages in response
// to an incoming message until processing of that batch of messages
2017-09-21 23:25:13 +02:00
// is complete. For example, we wouldn't want to auto-reply to a
// group info request before that group info request's batch was
// finished processing. Otherwise, we might receive a delivery
// notice for a group update we hadn't yet saved to the db.
//
// So we're using YDB behavior to ensure this invariant, which is a bit
// unorthodox.
[message updateWithMessageState:TSOutgoingMessageStateAttemptingOut];
OWSSendMessageOperation *sendMessageOperation =
[[OWSSendMessageOperation alloc] initWithMessage:message
messageSender:self
success:successHandler
failure:failureHandler];
// startBackgroundTask must be called on the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
// We call `startBackgroundTask` here to prevent our app from suspending while being backgrounded
// until the operation is completed - at which point the OWSSendMessageOperation ends it's background task.
[sendMessageOperation startBackgroundTask];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSOperationQueue *sendingQueue = [self sendingQueueForMessage:message];
[sendingQueue addOperation:sendMessageOperation];
});
});
});
}
- (void)attemptToSendMessage:(TSOutgoingMessage *)message
success:(void (^)())successHandler
failure:(RetryableFailureHandler)failureHandler
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
{
[self ensureAnyAttachmentsUploaded:message
success:^() {
[self deliverMessage:message
success:successHandler
failure:^(NSError *error) {
DDLogDebug(@"%@ Message send attempt failed: %@", self.tag, message.debugDescription);
failureHandler(error);
}];
}
failure:^(NSError *error) {
DDLogDebug(@"%@ Attachment upload attempt failed: %@", self.tag, message.debugDescription);
failureHandler(error);
}];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
- (void)ensureAnyAttachmentsUploaded:(TSOutgoingMessage *)message
success:(void (^)())successHandler
failure:(RetryableFailureHandler)failureHandler
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
{
if (!message.hasAttachments) {
return successHandler();
}
TSAttachmentStream *attachmentStream =
[TSAttachmentStream fetchObjectWithUniqueID:message.attachmentIds.firstObject];
if (!attachmentStream) {
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotLoadAttachment]);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
// Not finding local attachment is a terminal failure.
[error setIsRetryable:NO];
return failureHandler(error);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
[self.uploadingService uploadAttachmentStream:attachmentStream
message:message
success:successHandler
failure:failureHandler];
}
2017-09-18 21:02:34 +02:00
- (void)sendTemporaryAttachmentData:(DataSource *)dataSource
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
contentType:(NSString *)contentType
inMessage:(TSOutgoingMessage *)message
success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler
{
OWSAssert(dataSource);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
void (^successWithDeleteHandler)() = ^() {
successHandler();
DDLogDebug(@"Removing temporary attachment message.");
[message remove];
};
void (^failureWithDeleteHandler)(NSError *error) = ^(NSError *error) {
failureHandler(error);
DDLogDebug(@"Removing temporary attachment message.");
[message remove];
};
[self sendAttachmentData:dataSource
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
contentType:contentType
sourceFilename:nil
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
inMessage:message
success:successWithDeleteHandler
failure:failureWithDeleteHandler];
}
2017-09-18 21:02:34 +02:00
- (void)sendAttachmentData:(DataSource *)dataSource
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
contentType:(NSString *)contentType
sourceFilename:(nullable NSString *)sourceFilename
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
inMessage:(TSOutgoingMessage *)message
success:(void (^)())successHandler
failure:(void (^)(NSError *error))failureHandler
{
OWSAssert(dataSource);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
dispatch_async([OWSDispatch attachmentsQueue], ^{
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:contentType
byteCount:dataSource.dataLength
sourceFilename:sourceFilename];
2017-05-12 15:11:43 +02:00
if (message.isVoiceMessage) {
attachmentStream.attachmentType = TSAttachmentTypeVoiceMessage;
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (![attachmentStream writeDataSource:dataSource]) {
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotWriteAttachment]);
NSError *error = OWSErrorMakeWriteAttachmentDataError();
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
return failureHandler(error);
}
[attachmentStream save];
[message.attachmentIds addObject:attachmentStream.uniqueId];
if (sourceFilename) {
message.attachmentFilenameMap[attachmentStream.uniqueId] = sourceFilename;
2017-04-13 18:54:03 +02:00
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[message save];
[self sendMessage:message success:successHandler failure:failureHandler];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
});
}
- (NSArray<SignalRecipient *> *)getRecipients:(NSArray<NSString *> *)identifiers error:(NSError **)error
{
NSMutableArray<SignalRecipient *> *recipients = [NSMutableArray new];
for (NSString *recipientId in identifiers) {
SignalRecipient *existingRecipient = [SignalRecipient recipientWithTextSecureIdentifier:recipientId];
if (existingRecipient) {
[recipients addObject:existingRecipient];
} else {
SignalRecipient *newRecipient = [self.contactsUpdater synchronousLookup:recipientId error:error];
if (newRecipient) {
[recipients addObject:newRecipient];
}
}
}
if (recipients.count == 0 && !*error) {
// error should be set in contactsUpater, but just in case.
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotFindContacts1]);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
*error = OWSErrorMakeFailedToSendOutgoingMessageError();
}
return [recipients copy];
}
- (void)deliverMessage:(TSOutgoingMessage *)message
success:(void (^)())successHandler
failure:(RetryableFailureHandler)failureHandler
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
{
dispatch_async([OWSDispatch sendingQueue], ^{
2017-09-29 03:12:02 +02:00
TSThread *thread = message.thread;
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if ([thread isKindOfClass:[TSGroupThread class]]) {
TSGroupThread *gThread = (TSGroupThread *)thread;
NSError *error;
NSArray<SignalRecipient *> *recipients =
[self getRecipients:gThread.groupModel.groupMemberIds error:&error];
if (recipients.count == 0) {
if (!error) {
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotFindContacts2]);
error = OWSErrorMakeFailedToSendOutgoingMessageError();
}
2017-04-17 22:45:22 +02:00
// If no recipients were found, there's no reason to retry. It will just fail again.
[error setIsRetryable:NO];
failureHandler(error);
return;
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
[self groupSend:recipients message:message thread:gThread success:successHandler failure:failureHandler];
} else if ([thread isKindOfClass:[TSContactThread class]]
|| [message isKindOfClass:[OWSOutgoingSyncMessage class]]) {
TSContactThread *contactThread = (TSContactThread *)thread;
if ([contactThread.contactIdentifier isEqualToString:[TSAccountManager localNumber]]
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
&& ![message isKindOfClass:[OWSOutgoingSyncMessage class]]) {
[self handleSendToMyself:message];
successHandler();
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
return;
}
NSString *recipientContactId = [message isKindOfClass:[OWSOutgoingSyncMessage class]]
? [TSAccountManager localNumber]
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
: contactThread.contactIdentifier;
// If we block a user, don't send 1:1 messages to them. The UI
// should prevent this from occurring, but in some edge cases
// you might, for example, have a pending outgoing message when
// you block them.
OWSAssert(recipientContactId.length > 0);
2017-09-20 17:48:37 +02:00
if ([_blockingManager isRecipientIdBlocked:recipientContactId]) {
2017-04-17 22:45:22 +02:00
DDLogInfo(@"%@ skipping 1:1 send to blocked contact: %@", self.tag, recipientContactId);
2017-04-05 23:34:47 +02:00
NSError *error = OWSErrorMakeMessageSendFailedToBlockListError();
// No need to retry - the user will continue to be blocked.
[error setIsRetryable:NO];
failureHandler(error);
return;
}
SignalRecipient *recipient = [SignalRecipient recipientWithTextSecureIdentifier:recipientContactId];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (!recipient) {
NSError *error;
// possibly returns nil.
recipient = [self.contactsUpdater synchronousLookup:recipientContactId error:&error];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (error) {
if (error.code == OWSErrorCodeNoSuchSignalRecipient) {
DDLogWarn(@"%@ recipient contact not found", self.tag);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[self unregisteredRecipient:recipient message:message thread:thread];
}
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotFindContacts3]);
// No need to repeat trying to find a failure. Apart from repeatedly failing, it would also cause us
// to print redundant error messages.
[error setIsRetryable:NO];
failureHandler(error);
return;
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
}
if (!recipient) {
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
DDLogWarn(@"recipient contact still not found after attempting lookup.");
// No need to repeat trying to find a failure. Apart from repeatedly failing, it would also cause us to
// print redundant error messages.
[error setIsRetryable:NO];
failureHandler(error);
return;
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
[self sendMessage:message
recipient:recipient
thread:thread
attempts:OWSMessageSenderRetryAttempts
success:successHandler
failure:failureHandler];
} else {
// Neither a group nor contact thread? This should never happen.
OWSFail(@"%@ Unknown message type: %@", self.tag, NSStringFromClass([message class]));
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
[error setIsRetryable:NO];
failureHandler(error);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
});
}
// For group sends, we're using chained futures to make the code more readable.
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
- (TOCFuture *)sendMessageFuture:(TSOutgoingMessage *)message
recipient:(SignalRecipient *)recipient
thread:(TSThread *)thread
{
TOCFutureSource *futureSource = [[TOCFutureSource alloc] init];
[self sendMessage:message
recipient:recipient
thread:thread
attempts:OWSMessageSenderRetryAttempts
success:^{
2017-05-02 17:31:29 +02:00
DDLogInfo(@"%@ Marking group message as sent to recipient: %@", self.tag, recipient.uniqueId);
[message updateWithSentRecipient:recipient.uniqueId];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[futureSource trySetResult:@1];
}
failure:^(NSError *error) {
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[futureSource trySetFailure:error];
}];
return futureSource.future;
}
- (void)groupSend:(NSArray<SignalRecipient *> *)recipients
message:(TSOutgoingMessage *)message
thread:(TSThread *)thread
success:(void (^)())successHandler
failure:(RetryableFailureHandler)failureHandler
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
{
[self saveGroupMessage:message inThread:thread];
NSMutableArray<TOCFuture *> *futures = [NSMutableArray array];
for (SignalRecipient *recipient in recipients) {
NSString *recipientId = recipient.recipientId;
// We don't need to send the message to ourselves...
if ([recipientId isEqualToString:[TSAccountManager localNumber]]) {
continue;
}
// We don't need to sent the message to all group members if
// it has a "single group recipient".
if (message.singleGroupRecipient && ![message.singleGroupRecipient isEqualToString:recipientId]) {
continue;
}
if ([message wasSentToRecipient:recipientId]) {
// Skip recipients we have already sent this message to (on an
// earlier retry, perhaps).
2017-05-02 17:31:29 +02:00
DDLogInfo(@"%@ Skipping group message recipient; already sent: %@", self.tag, recipient.uniqueId);
continue;
}
// ...otherwise we send.
[futures addObject:[self sendMessageFuture:message recipient:recipient thread:thread]];
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
TOCFuture *completionFuture = futures.toc_thenAll;
[completionFuture thenDo:^(id value) {
successHandler();
}];
[completionFuture catchDo:^(id failure) {
// failure from toc_thenAll yields an array of failed Futures, rather than the future's failure.
NSError *firstRetryableError = nil;
NSError *firstNonRetryableError = nil;
if ([failure isKindOfClass:[NSArray class]]) {
NSArray *groupSendFutures = (NSArray *)failure;
for (TOCFuture *groupSendFuture in groupSendFutures) {
if (groupSendFuture.hasFailed) {
id failureResult = groupSendFuture.forceGetFailure;
if ([failureResult isKindOfClass:[NSError class]]) {
NSError *error = failureResult;
// Some errors should be ignored when sending messages
// to groups. See discussion on
// NSError (OWSMessageSender) category.
if ([error shouldBeIgnoredForGroups]) {
continue;
}
// Some errors should never be retried, in order to avoid
// hitting rate limits, for example. Unfortunately, since
// group send retry is all-or-nothing, we need to fail
// immediately even if some of the other recipients had
// retryable errors.
if ([error isFatal]) {
failureHandler(error);
return;
}
if ([error isRetryable] && !firstRetryableError) {
firstRetryableError = error;
} else if (![error isRetryable] && !firstNonRetryableError) {
firstNonRetryableError = error;
}
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
}
}
// If any of the group send errors are retryable, we want to retry.
// Therefore, prefer to propagate a retryable error.
if (firstRetryableError) {
return failureHandler(firstRetryableError);
} else if (firstNonRetryableError) {
return failureHandler(firstNonRetryableError);
} else {
// If we only received errors that we should ignore,
2017-04-17 22:45:22 +02:00
// consider this send a success, unless the message could
// not be sent to any recipient.
if (message.sentRecipientsCount == 0) {
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageSendNoValidRecipients,
NSLocalizedString(@"ERROR_DESCRIPTION_NO_VALID_RECIPIENTS",
@"Error indicating that an outgoing message had no valid recipients."));
[error setIsRetryable:NO];
failureHandler(error);
} else {
successHandler();
}
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}];
}
- (void)unregisteredRecipient:(SignalRecipient *)recipient
message:(TSOutgoingMessage *)message
thread:(TSThread *)thread
{
[self.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[recipient removeWithTransaction:transaction];
2017-03-05 14:30:04 +01:00
[[TSInfoMessage userNotRegisteredMessageInThread:thread]
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
saveWithTransaction:transaction];
}];
}
- (void)sendMessage:(TSOutgoingMessage *)message
recipient:(SignalRecipient *)recipient
thread:(TSThread *)thread
attempts:(int)remainingAttempts
success:(void (^)())successHandler
failure:(RetryableFailureHandler)failureHandler
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
{
DDLogInfo(@"%@ attempting to send message: %@, timestamp: %llu, recipient: %@",
self.tag,
message.class,
message.timestamp,
recipient.uniqueId);
AssertIsOnSendingQueue();
2017-02-10 19:20:11 +01:00
if ([TSPreKeyManager isAppLockedDueToPreKeyUpdateFailures]) {
OWSProdError([OWSAnalyticsEvents messageSendErrorFailedDueToPrekeyUpdateFailures]);
2017-02-10 19:20:11 +01:00
// Retry prekey update every time user tries to send a message while app
// is disabled due to prekey update failures.
//
// Only try to update the signed prekey; updating it is sufficient to
// re-enable message sending.
[TSPreKeyManager registerPreKeysWithMode:RefreshPreKeysMode_SignedOnly
success:^{
DDLogInfo(@"%@ New prekeys registered with server.", self.tag);
}
failure:^(NSError *error) {
DDLogWarn(@"%@ Failed to update prekeys with the server: %@", self.tag, error);
}];
NSError *error = OWSErrorMakeMessageSendDisabledDueToPreKeyUpdateFailuresError();
[error setIsRetryable:YES];
return failureHandler(error);
2017-02-10 19:20:11 +01:00
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (remainingAttempts <= 0) {
// We should always fail with a specific error.
OWSProdFail([OWSAnalyticsEvents messageSenderErrorGenericSendFailure]);
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
[error setIsRetryable:YES];
return failureHandler(error);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
remainingAttempts -= 1;
NSArray<NSDictionary *> *deviceMessages;
@try {
deviceMessages = [self deviceMessages:message forRecipient:recipient];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
} @catch (NSException *exception) {
deviceMessages = @[];
if ([exception.name isEqualToString:UntrustedIdentityKeyException]) {
// This *can* happen under normal usage, but it should happen relatively rarely.
// We expect it to happen whenever Bob reinstalls, and Alice messages Bob before
// she can pull down his latest identity.
// If it's happening a lot, we should rethink our profile fetching strategy.
OWSProdInfo([OWSAnalyticsEvents messageSendErrorFailedDueToUntrustedKey]);
NSString *localizedErrorDescriptionFormat
= NSLocalizedString(@"FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_KEY",
@"action sheet header when re-sending message which failed because of untrusted identity keys");
NSString *localizedErrorDescription =
[NSString stringWithFormat:localizedErrorDescriptionFormat,
[self.contactsManager displayNameForPhoneIdentifier:recipient.recipientId]];
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeUntrustedIdentityKey, localizedErrorDescription);
// Key will continue to be unaccepted, so no need to retry. It'll only cause us to hit the Pre-Key request
// rate limit
[error setIsRetryable:NO];
// Avoid the "Too many failures with this contact" error rate limiting.
[error setIsFatal:YES];
PreKeyBundle *newKeyBundle = exception.userInfo[TSInvalidPreKeyBundleKey];
if (![newKeyBundle isKindOfClass:[PreKeyBundle class]]) {
OWSProdFail([OWSAnalyticsEvents messageSenderErrorUnexpectedKeyBundle]);
failureHandler(error);
return;
}
NSData *newIdentityKeyWithVersion = newKeyBundle.identityKey;
if (![newIdentityKeyWithVersion isKindOfClass:[NSData class]]) {
OWSProdFail([OWSAnalyticsEvents messageSenderErrorInvalidIdentityKeyType]);
failureHandler(error);
return;
}
// TODO migrate to storing the full 33 byte representation of the identity key.
if (newIdentityKeyWithVersion.length != kIdentityKeyLength) {
OWSProdFail([OWSAnalyticsEvents messageSenderErrorInvalidIdentityKeyLength]);
failureHandler(error);
return;
}
NSData *newIdentityKey = [newIdentityKeyWithVersion removeKeyType];
[[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey recipientId:recipient.recipientId];
failureHandler(error);
return;
}
if ([exception.name isEqualToString:OWSMessageSenderRateLimitedException]) {
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceRateLimited,
NSLocalizedString(@"FAILED_SENDING_BECAUSE_RATE_LIMIT",
@"action sheet header when re-sending message which failed because of too many attempts"));
// We're already rate-limited. No need to exacerbate the problem.
[error setIsRetryable:NO];
// Avoid exacerbating the rate limiting.
[error setIsFatal:YES];
return failureHandler(error);
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (remainingAttempts == 0) {
DDLogWarn(
@"%@ Terminal failure to build any device messages. Giving up with exception:%@", self.tag, exception);
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
// Since we've already repeatedly failed to build messages, it's unlikely that repeating the whole process
// will succeed.
[error setIsRetryable:NO];
return failureHandler(error);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
}
TSSubmitMessageRequest *request = [[TSSubmitMessageRequest alloc] initWithRecipient:recipient.uniqueId
messages:deviceMessages
relay:recipient.relay
timeStamp:message.timestamp];
[self.networkManager makeRequest:request
success:^(NSURLSessionDataTask *task, id responseObject) {
dispatch_async([OWSDispatch sendingQueue], ^{
[recipient save];
[self handleMessageSentLocally:message];
successHandler();
});
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
2017-05-19 15:39:10 +02:00
DDLogInfo(@"%@ sending to recipient: %@, failed with error: %@", self.tag, recipient.uniqueId, error);
[DDLog flushLog];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
long statuscode = response.statusCode;
NSData *responseData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
void (^retrySend)() = ^void() {
if (remainingAttempts <= 0) {
// Since we've already repeatedly failed to send to the messaging API,
// it's unlikely that repeating the whole process will succeed.
[error setIsRetryable:NO];
return failureHandler(error);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
dispatch_async([OWSDispatch sendingQueue], ^{
DDLogDebug(@"%@ Retrying: %@", self.tag, message.debugDescription);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[self sendMessage:message
recipient:recipient
thread:thread
attempts:remainingAttempts
success:successHandler
failure:failureHandler];
});
};
switch (statuscode) {
case 401: {
DDLogWarn(@"%@ Unable to send due to invalid credentials. Did the user's client get de-authed by registering elsewhere?", self.tag);
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceFailure, NSLocalizedString(@"ERROR_DESCRIPTION_SENDING_UNAUTHORIZED", @"Error message when attempting to send message"));
// No need to retry if we've been de-authed.
[error setIsRetryable:NO];
return failureHandler(error);
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
case 404: {
2017-05-02 17:31:29 +02:00
DDLogWarn(@"%@ Unregistered recipient: %@", self.tag, recipient.uniqueId);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[self unregisteredRecipient:recipient message:message thread:thread];
NSError *error = OWSErrorMakeNoSuchSignalRecipientError();
// No need to retry if the recipient is not registered.
[error setIsRetryable:NO];
// If one member of a group deletes their account,
// the group should ignore errors when trying to send
// messages to this ex-member.
[error setShouldBeIgnoredForGroups:YES];
return failureHandler(error);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
case 409: {
// Mismatched devices
2017-05-02 17:31:29 +02:00
DDLogWarn(@"%@ Mismatch Devices for recipient: %@", self.tag, recipient.uniqueId);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
NSError *error;
NSDictionary *serializedResponse =
[NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
if (error) {
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotParseMismatchedDevicesJson]);
[error setIsRetryable:YES];
return failureHandler(error);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
[self handleMismatchedDevices:serializedResponse recipient:recipient completion:retrySend];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
break;
}
case 410: {
// Stale devices
2017-05-02 17:31:29 +02:00
DDLogWarn(@"%@ Stale devices for recipient: %@", self.tag, recipient.uniqueId);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (!responseData) {
DDLogWarn(@"Stale devices but server didn't specify devices in response.");
NSError *error = OWSErrorMakeUnableToProcessServerResponseError();
[error setIsRetryable:YES];
return failureHandler(error);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
[self handleStaleDevicesWithResponse:responseData
recipientId:recipient.uniqueId
completion:retrySend];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
break;
}
default:
retrySend();
break;
}
}];
}
- (void)handleMismatchedDevices:(NSDictionary *)dictionary
recipient:(SignalRecipient *)recipient
completion:(void (^)())completionHandler
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
{
NSArray *extraDevices = [dictionary objectForKey:@"extraDevices"];
NSArray *missingDevices = [dictionary objectForKey:@"missingDevices"];
dispatch_async([OWSDispatch sessionStoreQueue], ^{
2017-05-02 17:31:29 +02:00
if (extraDevices.count < 1 && missingDevices.count < 1) {
OWSProdFail([OWSAnalyticsEvents messageSenderErrorNoMissingOrExtraDevices]);
2017-05-02 17:31:29 +02:00
}
if (extraDevices && extraDevices.count > 0) {
2017-05-02 17:31:29 +02:00
DDLogInfo(@"%@ removing extra devices: %@", self.tag, extraDevices);
for (NSNumber *extraDeviceId in extraDevices) {
[self.storageManager deleteSessionForContact:recipient.uniqueId deviceId:extraDeviceId.intValue];
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[recipient removeDevices:[NSSet setWithArray:extraDevices]];
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (missingDevices && missingDevices.count > 0) {
2017-05-02 17:31:29 +02:00
DDLogInfo(@"%@ Adding missing devices: %@", self.tag, missingDevices);
[recipient addDevices:[NSSet setWithArray:missingDevices]];
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[recipient save];
completionHandler();
});
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
- (void)handleMessageSentLocally:(TSOutgoingMessage *)message
{
if (message.shouldSyncTranscript) {
// TODO: I suspect we shouldn't optimistically set hasSyncedTranscript.
// We could set this in a success handler for [sendSyncTranscriptForMessage:].
[message updateWithHasSyncedTranscript:YES];
[self sendSyncTranscriptForMessage:message];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
[OWSDisappearingMessagesJob setExpirationForMessage:message];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
- (void)becomeConsistentWithDisappearingConfigurationForMessage:(TSOutgoingMessage *)outgoingMessage
{
[OWSDisappearingMessagesJob becomeConsistentWithConfigurationForMessage:outgoingMessage
contactsManager:self.contactsManager];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
- (void)handleSendToMyself:(TSOutgoingMessage *)outgoingMessage
{
[self handleMessageSentLocally:outgoingMessage];
if (!(outgoingMessage.body || outgoingMessage.hasAttachments)) {
DDLogDebug(
@"%@ Refusing to make incoming copy of non-standard message sent to self:%@", self.tag, outgoingMessage);
return;
}
// Getting the local number uses a transaction, so we need to do that before we
// create a new transaction to avoid deadlock.
NSString *contactId = [TSAccountManager localNumber];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
TSContactThread *cThread =
[TSContactThread getOrCreateThreadWithContactId:contactId transaction:transaction];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[cThread saveWithTransaction:transaction];
// We want the incoming message to appear after the outgoing message.
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
TSIncomingMessage *incomingMessage =
[[TSIncomingMessage alloc] initWithTimestamp:(outgoingMessage.timestamp + 1)
inThread:cThread
authorId:[cThread contactIdentifier]
2017-02-16 00:32:27 +01:00
sourceDeviceId:[OWSDevice currentDeviceId]
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
messageBody:outgoingMessage.body
attachmentIds:outgoingMessage.attachmentIds
expiresInSeconds:outgoingMessage.expiresInSeconds];
[incomingMessage saveWithTransaction:transaction];
}];
}
- (void)sendSyncTranscriptForMessage:(TSOutgoingMessage *)message
{
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
OWSOutgoingSentMessageTranscript *sentMessageTranscript =
[[OWSOutgoingSentMessageTranscript alloc] initWithOutgoingMessage:message];
[self sendMessage:sentMessageTranscript
recipient:[SignalRecipient selfRecipient]
thread:message.thread
attempts:OWSMessageSenderRetryAttempts
success:^{
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
DDLogInfo(@"Succesfully sent sync transcript.");
}
failure:^(NSError *error) {
// FIXME: We don't yet honor the isRetryable flag here, since sendSyncTranscriptForMessage
// isn't yet wrapped in our retryable SendMessageOperation. Addressing this would require
// a refactor to the MessageSender. Note that we *do* however continue to respect the
// OWSMessageSenderRetryAttempts, which is an "inner" retry loop, encompassing only the
// messaging API.
DDLogInfo(@"Failed to send sync transcript: %@ (isRetryable: %d)", error, [error isRetryable]);
}];
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
- (NSArray<NSDictionary *> *)deviceMessages:(TSOutgoingMessage *)message
forRecipient:(SignalRecipient *)recipient
{
OWSAssert(message);
OWSAssert(recipient);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
NSMutableArray *messagesArray = [NSMutableArray arrayWithCapacity:recipient.devices.count];
NSData *plainText = [message buildPlainTextData:recipient];
2017-07-28 23:58:40 +02:00
DDLogDebug(@"%@ built message: %@ plainTextData.length: %lu", self.tag, [message class], (unsigned long)plainText.length);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
for (NSNumber *deviceNumber in recipient.devices) {
@try {
__block NSDictionary *messageDict;
__block NSException *encryptionException;
// Mutating session state is not thread safe, so we operate on a serial queue, shared with decryption
// operations.
dispatch_sync([OWSDispatch sessionStoreQueue], ^{
@try {
messageDict = [self encryptedMessageWithPlaintext:plainText
toRecipient:recipient.uniqueId
deviceId:deviceNumber
keyingStorage:self.storageManager
isSilent:message.isSilent];
} @catch (NSException *exception) {
encryptionException = exception;
}
});
if (encryptionException) {
DDLogInfo(@"%@ Exception during encryption: %@", self.tag, encryptionException);
@throw encryptionException;
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (messageDict) {
[messagesArray addObject:messageDict];
} else {
@throw [NSException exceptionWithName:InvalidMessageException
reason:@"Failed to encrypt message"
userInfo:nil];
}
} @catch (NSException *exception) {
if ([exception.name isEqualToString:OWSMessageSenderInvalidDeviceException]) {
[recipient removeDevices:[NSSet setWithObject:deviceNumber]];
} else {
@throw exception;
}
}
}
return [messagesArray copy];
}
- (NSDictionary *)encryptedMessageWithPlaintext:(NSData *)plainText
toRecipient:(NSString *)identifier
deviceId:(NSNumber *)deviceNumber
keyingStorage:(TSStorageManager *)storage
isSilent:(BOOL)isSilent
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
{
OWSAssert(plainText);
OWSAssert(identifier.length > 0);
OWSAssert(deviceNumber);
OWSAssert(storage);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (![storage containsSession:identifier deviceId:[deviceNumber intValue]]) {
__block dispatch_semaphore_t sema = dispatch_semaphore_create(0);
__block PreKeyBundle *_Nullable bundle;
__block NSException *_Nullable exception;
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
[self.networkManager makeRequest:[[TSRecipientPrekeyRequest alloc] initWithRecipient:identifier
deviceId:[deviceNumber stringValue]]
success:^(NSURLSessionDataTask *task, id responseObject) {
bundle = [PreKeyBundle preKeyBundleFromDictionary:responseObject forDeviceNumber:deviceNumber];
dispatch_semaphore_signal(sema);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
2017-07-24 17:06:19 +02:00
if (!IsNSErrorNetworkFailure(error)) {
OWSProdError([OWSAnalyticsEvents messageSenderErrorRecipientPrekeyRequestFailed]);
2017-07-24 17:06:19 +02:00
}
DDLogError(@"Server replied to PreKeyBundle request with error: %@", error);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
if (response.statusCode == 404) {
// Can't throw exception from within callback as it's probabably a different thread.
exception = [NSException exceptionWithName:OWSMessageSenderInvalidDeviceException
reason:@"Device not registered"
userInfo:nil];
} else if (response.statusCode == 413) {
// Can't throw exception from within callback as it's probabably a different thread.
exception = [NSException exceptionWithName:OWSMessageSenderRateLimitedException
reason:@"Too many prekey requests"
userInfo:nil];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
}
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
if (exception) {
@throw exception;
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
if (!bundle) {
@throw [NSException exceptionWithName:InvalidVersionException
reason:@"Can't get a prekey bundle from the server with required information"
userInfo:nil];
} else {
SessionBuilder *builder = [[SessionBuilder alloc] initWithSessionStore:storage
preKeyStore:storage
signedPreKeyStore:storage
identityKeyStore:[OWSIdentityManager sharedManager]
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
recipientId:identifier
deviceId:[deviceNumber intValue]];
@try {
// Mutating session state is not thread safe.
@synchronized(self) {
[builder processPrekeyBundle:bundle];
}
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
} @catch (NSException *exception) {
if ([exception.name isEqualToString:UntrustedIdentityKeyException]) {
@throw [NSException
exceptionWithName:UntrustedIdentityKeyException
reason:nil
userInfo:@{ TSInvalidPreKeyBundleKey : bundle, TSInvalidRecipientKey : identifier }];
}
@throw exception;
}
}
}
SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storage
preKeyStore:storage
signedPreKeyStore:storage
identityKeyStore:[OWSIdentityManager sharedManager]
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
recipientId:identifier
deviceId:[deviceNumber intValue]];
id<CipherMessage> encryptedMessage = [cipher encryptMessage:[plainText paddedMessageBody]];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
NSData *serializedMessage = encryptedMessage.serialized;
TSWhisperMessageType messageType = [self messageTypeForCipherMessage:encryptedMessage];
OWSMessageServiceParams *messageParams = [[OWSMessageServiceParams alloc] initWithType:messageType
recipientId:identifier
device:[deviceNumber intValue]
content:serializedMessage
isSilent:isSilent
registrationId:cipher.remoteRegistrationId];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
NSError *error;
NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error];
if (error) {
OWSProdError([OWSAnalyticsEvents messageSendErrorCouldNotSerializeMessageJson]);
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
return nil;
}
return jsonDict;
}
- (TSWhisperMessageType)messageTypeForCipherMessage:(id<CipherMessage>)cipherMessage
{
if ([cipherMessage isKindOfClass:[PreKeyWhisperMessage class]]) {
return TSPreKeyWhisperMessageType;
} else if ([cipherMessage isKindOfClass:[WhisperMessage class]]) {
return TSEncryptedWhisperMessageType;
}
return TSUnknownMessageType;
}
- (void)saveGroupMessage:(TSOutgoingMessage *)message inThread:(TSThread *)thread
{
if (message.groupMetaMessage == TSGroupMessageDeliver) {
// TODO: Why is this necessary?
[message save];
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
} else if (message.groupMetaMessage == TSGroupMessageQuit) {
2017-09-21 23:25:13 +02:00
[[[TSInfoMessage alloc] initWithTimestamp:message.timestamp
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
inThread:thread
messageType:TSInfoMessageTypeGroupQuit
customMessage:message.customMessage] save];
} else {
2017-09-21 23:25:13 +02:00
[[[TSInfoMessage alloc] initWithTimestamp:message.timestamp
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
inThread:thread
messageType:TSInfoMessageTypeGroupUpdate
customMessage:message.customMessage] save];
}
}
// Called when the server indicates that the devices no longer exist - e.g. when the remote recipient has reinstalled.
- (void)handleStaleDevicesWithResponse:(NSData *)responseData
recipientId:(NSString *)identifier
completion:(void (^)())completionHandler
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
{
dispatch_async([OWSDispatch sendingQueue], ^{
NSDictionary *serialization = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
NSArray *devices = serialization[@"staleDevices"];
if (!([devices count] > 0)) {
return;
}
dispatch_async([OWSDispatch sessionStoreQueue], ^{
for (NSUInteger i = 0; i < [devices count]; i++) {
int deviceNumber = [devices[i] intValue];
[[TSStorageManager sharedManager] deleteSessionForContact:identifier deviceId:deviceNumber];
}
completionHandler();
});
Explain send failures for text and media messages Motivation ---------- We were often swallowing errors or yielding generic errors when it would be better to provide specific errors. We also didn't create an attachment when attachments failed to send, making it impossible to show the user what was happening with an in-progress or failed attachment. Primary Changes --------------- - Funnel all message sending through MessageSender, and remove message sending from MessagesManager. - Record most recent sending error so we can expose it in the UI - Can resend attachments. - Update message status for attachments, just like text messages - Extracted UploadingService from MessagesManager - Saving attachment stream before uploading gives uniform API for send vs. resend - update status for downloading transcript attachments - TSAttachments have a local id, separate from the server allocated id This allows us to save the attachment before the allocation request. Which is is good because: 1. can show feedback to user faster. 2. allows us to show an error when allocation fails. Code Cleanup ------------ - Replaced a lot of global singleton access with injected dependencies to make for easier testing. - Never save group meta messages. Rather than checking before (hopefully) every save, do it in the save method. - Don't use callbacks for sync code. - Handle errors on writing attachment data - Fix old long broken tests that weren't even running. =( - Removed dead code - Use constants vs define - Port flaky travis fixes from Signal-iOS // FREEBIE
2016-10-14 23:00:29 +02:00
});
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END