Merge branch 'mkirk/long-text-nondurable'

This commit is contained in:
Michael Kirk 2019-02-26 10:06:59 -07:00
commit e6ad6c85bf
5 changed files with 195 additions and 167 deletions

View file

@ -660,14 +660,20 @@ class NotificationActionHandler {
}
extension ThreadUtil {
static var dbReadConnection: YapDatabaseConnection {
return OWSPrimaryStorage.shared().dbReadConnection
}
class func sendMessageNonDurably(text: String, thread: TSThread, quotedReplyModel: OWSQuotedReplyModel?, messageSender: MessageSender) -> Promise<Void> {
return Promise { resolver in
self.sendMessageNonDurably(withText: text,
in: thread,
quotedReplyModel: quotedReplyModel,
messageSender: messageSender,
success: resolver.fulfill,
failure: resolver.reject)
self.dbReadConnection.read { transaction in
_ = self.sendMessageNonDurably(withText: text,
in: thread,
quotedReplyModel: quotedReplyModel,
transaction: transaction,
messageSender: messageSender,
completion: resolver.resolve)
}
}
}
}

View file

@ -30,7 +30,6 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
@property (nonatomic) TSThread *thread;
@property (nonatomic, readonly, weak) id<ShareViewDelegate> shareViewDelegate;
@property (nonatomic, readonly) UIProgressView *progressView;
@property (nonatomic, readonly) YapDatabaseConnection *editingDBConnection;
@property (atomic, nullable) TSOutgoingMessage *outgoingMessage;
@end
@ -46,13 +45,26 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
return self;
}
_editingDBConnection = [OWSPrimaryStorage.sharedManager newDatabaseConnection];
_shareViewDelegate = shareViewDelegate;
self.selectThreadViewDelegate = self;
return self;
}
#pragma mark - Dependencies
- (YapDatabaseConnection *)dbReadWriteConnection
{
return OWSPrimaryStorage.sharedManager.dbReadWriteConnection;
}
- (YapDatabaseConnection *)dbReadConnection
{
return OWSPrimaryStorage.sharedManager.dbReadConnection;
}
#pragma mark - UIViewController overrides
- (void)loadView
{
[super loadView];
@ -274,14 +286,18 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
// the sending operation. Alternatively, we could use a durable send, but do more to make sure the
// SAE runs as long as it needs.
// TODO ALBUMS - send album via SAE
outgoingMessage = [ThreadUtil sendMessageNonDurablyWithAttachments:attachments
inThread:self.thread
messageBody:messageText
quotedReplyModel:nil
messageSender:self.messageSender
completion:^(NSError *_Nullable error) {
sendCompletion(error, outgoingMessage);
}];
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
outgoingMessage = [ThreadUtil sendMessageNonDurablyWithText:messageText
mediaAttachments:attachments
inThread:self.thread
quotedReplyModel:nil
transaction:transaction
messageSender:self.messageSender
completion:^(NSError *_Nullable error) {
sendCompletion(error, outgoingMessage);
}];
}];
// This is necessary to show progress.
self.outgoingMessage = outgoingMessage;
@ -310,19 +326,22 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
// DURABLE CLEANUP - SAE uses non-durable sending to make sure the app is running long enough to complete
// the sending operation. Alternatively, we could use a durable send, but do more to make sure the
// SAE runs as long as it needs.
outgoingMessage = [ThreadUtil sendMessageNonDurablyWithText:messageText
inThread:self.thread
quotedReplyModel:nil
messageSender:self.messageSender
success:^{
sendCompletion(nil, outgoingMessage);
}
failure:^(NSError *_Nonnull error) {
sendCompletion(error, outgoingMessage);
}];
// This is necessary to show progress.
self.outgoingMessage = outgoingMessage;
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
outgoingMessage = [ThreadUtil sendMessageNonDurablyWithText:messageText
inThread:self.thread
quotedReplyModel:nil
transaction:transaction
messageSender:self.messageSender
completion:^(NSError *_Nullable error) {
if (error) {
sendCompletion(error, outgoingMessage);
} else {
sendCompletion(nil, outgoingMessage);
}
}];
// This is necessary to show progress.
self.outgoingMessage = outgoingMessage;
}];
}
fromViewController:approvalViewController];
}
@ -344,11 +363,12 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
OWSAssertIsOnMainThread();
// TODO - in line with QuotedReply and other message attachments, saving should happen as part of sending
// preparation rather than duplicated here and in the SAE
[self.editingDBConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
if (contactShare.avatarImage) {
[contactShare.dbRecord saveAvatarImage:contactShare.avatarImage transaction:transaction];
[self.dbReadWriteConnection
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
if (contactShare.avatarImage) {
[contactShare.dbRecord saveAvatarImage:contactShare.avatarImage transaction:transaction];
}
}
}
completionBlock:^{
__block TSOutgoingMessage *outgoingMessage = nil;
outgoingMessage = [ThreadUtil sendMessageNonDurablyWithContactShare:contactShare.dbRecord
@ -521,8 +541,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
OWSLogDebug(@"Confirming identity for recipient: %@", recipientId);
[OWSPrimaryStorage.sharedManager.newDatabaseConnection asyncReadWriteWithBlock:^(
YapDatabaseReadWriteTransaction *transaction) {
[self.dbReadWriteConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
OWSVerificationState verificationState =
[[OWSIdentityManager sharedManager] verificationStateForRecipientId:recipientId transaction:transaction];
switch (verificationState) {

View file

@ -63,26 +63,27 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Non-Durable Sending
// Used by SAE and "reply from lockscreen", otherwise we should use the durable `enqueue` counterpart
+ (TSOutgoingMessage *)sendMessageNonDurablyWithText:(NSString *)text
+ (TSOutgoingMessage *)sendMessageNonDurablyWithText:(NSString *)fullMessageText
inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
transaction:(YapDatabaseReadTransaction *)transaction
messageSender:(OWSMessageSender *)messageSender
success:(void (^)(void))successHandler
failure:(void (^)(NSError *error))failureHandler;
completion:(void (^)(NSError *_Nullable error))completion;
// Used by SAE, otherwise we should use the durable `enqueue` counterpart
+ (TSOutgoingMessage *)sendMessageNonDurablyWithAttachments:(NSArray<SignalAttachment *> *)attachments
inThread:(TSThread *)thread
messageBody:(nullable NSString *)messageBody
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
messageSender:(OWSMessageSender *)messageSender
completion:(void (^_Nullable)(NSError *_Nullable error))completion;
+ (TSOutgoingMessage *)sendMessageNonDurablyWithText:(NSString *)fullMessageText
mediaAttachments:(NSArray<SignalAttachment *> *)attachments
inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
transaction:(YapDatabaseReadTransaction *)transaction
messageSender:(OWSMessageSender *)messageSender
completion:(void (^)(NSError *_Nullable error))completion;
// Used by SAE, otherwise we should use the durable `enqueue` counterpart
+ (TSOutgoingMessage *)sendMessageNonDurablyWithContactShare:(OWSContact *)contactShare
inThread:(TSThread *)thread
messageSender:(OWSMessageSender *)messageSender
completion:(void (^_Nullable)(NSError *_Nullable error))completion;
completion:(void (^)(NSError *_Nullable error))completion;
#pragma mark - dynamic interactions

View file

@ -65,6 +65,10 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark -
typedef void (^BuildOutgoingMessageCompletionBlock)(TSOutgoingMessage *savedMessage,
NSMutableArray<OWSOutgoingAttachmentInfo *> *attachmentInfos,
YapDatabaseReadWriteTransaction *writeTransaction);
@implementation ThreadUtil
#pragma mark - Dependencies
@ -95,26 +99,8 @@ NS_ASSUME_NONNULL_BEGIN
transaction:transaction];
}
+ (nullable OWSLinkPreview *)linkPreviewForLinkPreviewDraft:(nullable OWSLinkPreviewDraft *)linkPreviewDraft
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssertDebug(transaction);
if (!linkPreviewDraft) {
return nil;
}
NSError *linkPreviewError;
OWSLinkPreview *_Nullable linkPreview = [OWSLinkPreview buildValidatedLinkPreviewFromInfo:linkPreviewDraft
transaction:transaction
error:&linkPreviewError];
if (linkPreviewError && ![OWSLinkPreview isNoPreviewError:linkPreviewError]) {
OWSLogError(@"linkPreviewError: %@", linkPreviewError);
}
return linkPreview;
}
+ (TSOutgoingMessage *)enqueueMessageWithText:(nullable NSString *)fullMessageText
mediaAttachments:(NSArray<SignalAttachment *> *)attachmentsParam
mediaAttachments:(NSArray<SignalAttachment *> *)mediaAttachments
inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
linkPreviewDraft:(nullable nullable OWSLinkPreviewDraft *)linkPreviewDraft
@ -123,8 +109,36 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssertIsOnMainThread();
OWSAssertDebug(thread);
return [self
buildOutgoingMessageWithText:fullMessageText
mediaAttachments:mediaAttachments
thread:thread
quotedReplyModel:quotedReplyModel
linkPreviewDraft:linkPreviewDraft
transaction:transaction
completion:^(TSOutgoingMessage *savedMessage,
NSMutableArray<OWSOutgoingAttachmentInfo *> *attachmentInfos,
YapDatabaseReadWriteTransaction *writeTransaction) {
if (attachmentInfos.count == 0) {
[self.messageSenderJobQueue addMessage:savedMessage transaction:writeTransaction];
} else {
[self.messageSenderJobQueue addMediaMessage:savedMessage
attachmentInfos:attachmentInfos
isTemporaryAttachment:NO];
}
}];
}
+ (TSOutgoingMessage *)buildOutgoingMessageWithText:(nullable NSString *)fullMessageText
mediaAttachments:(NSArray<SignalAttachment *> *)mediaAttachments
thread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
linkPreviewDraft:(nullable OWSLinkPreviewDraft *)linkPreviewDraft
transaction:(YapDatabaseReadTransaction *)transaction
completion:(BuildOutgoingMessageCompletionBlock)completionBlock;
{
NSString *_Nullable truncatedText;
NSArray<SignalAttachment *> *attachments = attachmentsParam;
NSArray<SignalAttachment *> *attachments = mediaAttachments;
if ([fullMessageText lengthOfBytesUsingEncoding:NSUTF8StringEncoding] <= kOversizeTextMessageSizeThreshold) {
truncatedText = fullMessageText;
} else {
@ -141,7 +155,7 @@ NS_ASSUME_NONNULL_BEGIN
if (dataSource) {
SignalAttachment *oversizeTextAttachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:kOversizeTextAttachmentUTI];
attachments = [attachmentsParam arrayByAddingObject:oversizeTextAttachment];
attachments = [mediaAttachments arrayByAddingObject:oversizeTextAttachment];
} else {
OWSFailDebug(@"dataSource was unexpectedly nil");
}
@ -188,21 +202,13 @@ NS_ASSUME_NONNULL_BEGIN
[message updateWithLinkPreview:linkPreview transaction:writeTransaction];
}
if (attachments.count == 0) {
[self.messageSenderJobQueue addMessage:message transaction:writeTransaction];
} else {
NSMutableArray<OWSOutgoingAttachmentInfo *> *attachmentInfos =
[NSMutableArray new];
for (SignalAttachment *attachment in attachments) {
OWSOutgoingAttachmentInfo *attachmentInfo =
[attachment buildOutgoingAttachmentInfoWithMessage:message];
[attachmentInfos addObject:attachmentInfo];
}
[self.messageSenderJobQueue addMediaMessage:message
attachmentInfos:attachmentInfos
isTemporaryAttachment:NO];
NSMutableArray<OWSOutgoingAttachmentInfo *> *attachmentInfos = [NSMutableArray new];
for (SignalAttachment *attachment in attachments) {
OWSOutgoingAttachmentInfo *attachmentInfo =
[attachment buildOutgoingAttachmentInfoWithMessage:message];
[attachmentInfos addObject:attachmentInfo];
}
completionBlock(message, attachmentInfos, writeTransaction);
}
completionBlock:benchmarkCompletion];
}];
@ -257,104 +263,86 @@ NS_ASSUME_NONNULL_BEGIN
// MARK: Non-Durable Sending
// We might want to generate a link preview here.
+ (TSOutgoingMessage *)sendMessageNonDurablyWithText:(NSString *)text
+ (TSOutgoingMessage *)sendMessageNonDurablyWithText:(NSString *)fullMessageText
inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
transaction:(YapDatabaseReadTransaction *)transaction
messageSender:(OWSMessageSender *)messageSender
success:(void (^)(void))successHandler
failure:(void (^)(NSError *error))failureHandler
completion:(void (^)(NSError *_Nullable error))completion
{
OWSAssertIsOnMainThread();
OWSAssertDebug(text.length > 0);
OWSAssertDebug(thread);
OWSAssertDebug(messageSender);
OWSAssertDebug(completion);
OWSDisappearingMessagesConfiguration *configuration =
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0);
TSOutgoingMessage *message =
[TSOutgoingMessage outgoingMessageInThread:thread
messageBody:text
attachmentId:nil
expiresInSeconds:expiresInSeconds
quotedMessage:[quotedReplyModel buildQuotedMessageForSending]
linkPreview:nil];
[messageSender sendMessage:message success:successHandler failure:failureHandler];
return message;
return [self sendMessageNonDurablyWithText:fullMessageText
mediaAttachments:@[]
inThread:thread
quotedReplyModel:quotedReplyModel
transaction:transaction
messageSender:messageSender
completion:completion];
}
+ (TSOutgoingMessage *)sendMessageNonDurablyWithAttachments:(NSArray<SignalAttachment *> *)attachments
inThread:(TSThread *)thread
messageBody:(nullable NSString *)messageBody
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
messageSender:(OWSMessageSender *)messageSender
completion:(void (^_Nullable)(NSError *_Nullable error))completion
+ (TSOutgoingMessage *)sendMessageNonDurablyWithText:(NSString *)fullMessageText
mediaAttachments:(NSArray<SignalAttachment *> *)mediaAttachments
inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
transaction:(YapDatabaseReadTransaction *)transaction
messageSender:(OWSMessageSender *)messageSender
completion:(void (^)(NSError *_Nullable error))completion
{
OWSAssertIsOnMainThread();
OWSAssertDebug(attachments.count > 0);
OWSAssertDebug(thread);
OWSAssertDebug(messageSender);
OWSAssertDebug(completion);
OWSDisappearingMessagesConfiguration *configuration =
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0);
BOOL isVoiceMessage = (attachments.count == 1 && attachments.firstObject.isVoiceMessage);
// MJK TODO - remove senderTimestamp
TSOutgoingMessage *message =
[[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageBody:messageBody
attachmentIds:[NSMutableArray new]
expiresInSeconds:expiresInSeconds
expireStartedAt:0
isVoiceMessage:isVoiceMessage
groupMetaMessage:TSGroupMetaMessageUnspecified
quotedMessage:[quotedReplyModel buildQuotedMessageForSending]
contactShare:nil
linkPreview:nil];
NSMutableArray<OWSOutgoingAttachmentInfo *> *attachmentInfos = [NSMutableArray new];
for (SignalAttachment *attachment in attachments) {
OWSAssertDebug([attachment mimeType].length > 0);
[attachmentInfos addObject:[attachment buildOutgoingAttachmentInfoWithMessage:message]];
}
[messageSender sendAttachments:attachmentInfos
inMessage:message
success:^{
OWSLogDebug(@"Successfully sent message attachment.");
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
completion(nil);
});
}
}
failure:^(NSError *error) {
OWSLogError(@"Failed to send message attachment with error: %@", error);
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
completion(error);
});
}
}];
return message;
return
[self buildOutgoingMessageWithText:fullMessageText
mediaAttachments:mediaAttachments
thread:thread
quotedReplyModel:quotedReplyModel
linkPreviewDraft:nil
transaction:transaction
completion:^(TSOutgoingMessage *_Nonnull savedMessage,
NSMutableArray<OWSOutgoingAttachmentInfo *> *_Nonnull attachmentInfos,
YapDatabaseReadWriteTransaction *_Nonnull writeTransaction) {
if (attachmentInfos.count == 0) {
[messageSender sendMessage:savedMessage
success:^{
dispatch_async(dispatch_get_main_queue(), ^(void) {
completion(nil);
});
}
failure:^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
completion(error);
});
}];
} else {
[messageSender sendAttachments:attachmentInfos
inMessage:savedMessage
success:^{
dispatch_async(dispatch_get_main_queue(), ^(void) {
completion(nil);
});
}
failure:^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
completion(error);
});
}];
}
}];
}
+ (TSOutgoingMessage *)sendMessageNonDurablyWithContactShare:(OWSContact *)contactShare
inThread:(TSThread *)thread
messageSender:(OWSMessageSender *)messageSender
completion:(void (^_Nullable)(NSError *_Nullable error))completion
completion:(void (^)(NSError *_Nullable error))completion
{
OWSAssertIsOnMainThread();
OWSAssertDebug(contactShare);
OWSAssertDebug(contactShare.ows_isValid);
OWSAssertDebug(thread);
OWSAssertDebug(messageSender);
OWSAssertDebug(completion);
OWSDisappearingMessagesConfiguration *configuration =
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
@ -377,24 +365,38 @@ NS_ASSUME_NONNULL_BEGIN
[messageSender sendMessage:message
success:^{
OWSLogDebug(@"Successfully sent contact share.");
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
completion(nil);
});
}
dispatch_async(dispatch_get_main_queue(), ^(void) {
completion(nil);
});
}
failure:^(NSError *error) {
OWSLogError(@"Failed to send contact share with error: %@", error);
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
completion(error);
});
}
dispatch_async(dispatch_get_main_queue(), ^(void) {
completion(error);
});
}];
return message;
}
+ (nullable OWSLinkPreview *)linkPreviewForLinkPreviewDraft:(nullable OWSLinkPreviewDraft *)linkPreviewDraft
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssertDebug(transaction);
if (!linkPreviewDraft) {
return nil;
}
NSError *linkPreviewError;
OWSLinkPreview *_Nullable linkPreview = [OWSLinkPreview buildValidatedLinkPreviewFromInfo:linkPreviewDraft
transaction:transaction
error:&linkPreviewError];
if (linkPreviewError && ![OWSLinkPreview isNoPreviewError:linkPreviewError]) {
OWSLogError(@"linkPreviewError: %@", linkPreviewError);
}
return linkPreview;
}
#pragma mark - Dynamic Interactions
+ (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread

View file

@ -234,7 +234,7 @@ void AssertIsOnSendingQueue()
- (void)didFailWithError:(NSError *)error
{
OWSLogDebug(@"failed with error: %@", error);
OWSLogError(@"failed with error: %@", error);
self.failureHandler(error);
}