From 19ca10d4314201d86ae67908905079eb832ff669 Mon Sep 17 00:00:00 2001 From: Frederic Jacobs Date: Thu, 19 Feb 2015 01:04:32 +0100 Subject: [PATCH] Allows retry of failed downloads. --- .../number directory/GroupContactsResult.m | 2 +- .../src/textsecure/Account/TSPreKeyManager.m | 4 +- .../Attachements/TSAttachmentPointer.h | 4 ++ .../Attachements/TSAttachmentPointer.m | 4 +- .../Messages/TSMessagesManager+attachments.h | 6 ++- .../Messages/TSMessagesManager+attachments.m | 50 +++++++++++++++---- .../view controllers/MessagesViewController.m | 27 ++++++++++ .../src/view controllers/TSMessageAdapter.m | 18 +++++-- .../test/textsecure/TSMessageStorageTests.m | 4 +- 9 files changed, 96 insertions(+), 23 deletions(-) diff --git a/Signal/src/phone/signaling/number directory/GroupContactsResult.m b/Signal/src/phone/signaling/number directory/GroupContactsResult.m index b8a458ce0..31f20af71 100644 --- a/Signal/src/phone/signaling/number directory/GroupContactsResult.m +++ b/Signal/src/phone/signaling/number directory/GroupContactsResult.m @@ -110,7 +110,7 @@ NSString *identifier = [_knownNumbers objectAtIndex:[self knownNumbersIndexForIndexPath:indexPath]]; return [_associatedContactDict objectForKey:identifier]; } else { - NSAssert(NO, @"Trying to retreive contact from array at an index that is not a contact."); + NSAssert(NO, @"Trying to retrieve contact from array at an index that is not a contact."); return nil; } } diff --git a/Signal/src/textsecure/Account/TSPreKeyManager.m b/Signal/src/textsecure/Account/TSPreKeyManager.m index 7d2308af8..ddaab60d8 100644 --- a/Signal/src/textsecure/Account/TSPreKeyManager.m +++ b/Signal/src/textsecure/Account/TSPreKeyManager.m @@ -71,7 +71,7 @@ }]; } } failure:^(NSURLSessionDataTask *task, NSError *error) { - DDLogError(@"Failed to retreive the number of available prekeys."); + DDLogError(@"Failed to retrieve the number of available prekeys."); }]; } @@ -85,7 +85,7 @@ [self clearSignedPreKeyRecordsWithKeyId:keyId]; } failure:^(NSURLSessionDataTask *task, NSError *error) { - DDLogWarn(@"Failed to retreive current prekey."); + DDLogWarn(@"Failed to retrieve current prekey."); }]; } diff --git a/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.h b/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.h index 18d48619e..5a73660d0 100644 --- a/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.h +++ b/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.h @@ -25,4 +25,8 @@ @property NSString *relay; @property NSData *avatarOfGroupId; + +@property (getter=isDownloading) BOOL downloading; +@property (getter=hasFailed) BOOL failed; + @end diff --git a/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.m b/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.m index 4137334a2..a0ed70119 100644 --- a/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.m +++ b/Signal/src/textsecure/Messages/Attachements/TSAttachmentPointer.m @@ -18,7 +18,9 @@ self = [super initWithIdentifier:[[NSNumber numberWithUnsignedLongLong:identifier] stringValue] encryptionKey:key contentType:contentType]; if (self) { - self.relay = relay; + _failed = FALSE; + _downloading = FALSE; + _relay = relay; } return self; diff --git a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.h b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.h index 31a2164df..96755b415 100644 --- a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.h +++ b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.h @@ -7,7 +7,9 @@ // #import "TSMessagesManager.h" -#import "TSAttachment.h" + +@class TSAttachment; +@class TSAttachmentPointer; @interface TSMessagesManager (attachments) @@ -18,4 +20,6 @@ inMessage:(TSOutgoingMessage*)outgoingMessage thread:(TSThread*)thread; +- (void)retrieveAttachment:(TSAttachmentPointer*)attachment messageId:(NSString*)messageId; + @end diff --git a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m index 2696e1ef6..3d85f3006 100644 --- a/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m +++ b/Signal/src/textsecure/Messages/TSMessagesManager+attachments.m @@ -69,10 +69,13 @@ dispatch_queue_t attachmentsQueue() { [self handleReceivedMessage:message withContent:content attachments:retrievedAttachments completionBlock:^(NSString *messageIdentifier) { for (NSString *pointerId in retrievedAttachments) { dispatch_async(attachmentsQueue(), ^{ - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - TSAttachmentPointer *pointer = [TSAttachmentPointer fetchObjectWithUniqueID:pointerId transaction:transaction]; - [self retrieveAttachment:pointer messageId:messageIdentifier]; + __block TSAttachmentPointer *pointer; + + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + pointer = [TSAttachmentPointer fetchObjectWithUniqueID:pointerId transaction:transaction]; }]; + + [self retrieveAttachment:pointer messageId:messageIdentifier]; }); } }]; @@ -87,7 +90,7 @@ dispatch_queue_t attachmentsQueue() { NSDictionary *responseDict = (NSDictionary*)responseObject; NSString *attachementId = [(NSNumber*)[responseDict objectForKey:@"id"] stringValue]; NSString *location = [responseDict objectForKey:@"location"]; - + TSAttachmentEncryptionResult *result = [Cryptography encryptAttachment:attachmentData contentType:contentType identifier:attachementId]; [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { @@ -107,8 +110,6 @@ dispatch_queue_t attachmentsQueue() { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { result.pointer.isDownloaded = YES; [result.pointer saveWithTransaction:transaction]; - - NSLog(@"finished uploading"); }]; [self sendMessage:outgoingMessage inThread:thread]; } else{ @@ -130,6 +131,8 @@ dispatch_queue_t attachmentsQueue() { - (void)retrieveAttachment:(TSAttachmentPointer*)attachment messageId:(NSString*)messageId { + [self setAttachment:attachment isDownloadingInMessage:messageId]; + TSAttachmentRequest *attachmentRequest = [[TSAttachmentRequest alloc] initWithId:[attachment identifier] relay:attachment.relay]; @@ -137,14 +140,35 @@ dispatch_queue_t attachmentsQueue() { if ([responseObject isKindOfClass:[NSDictionary class]]) { dispatch_async(attachmentsQueue(), ^{ NSString *location = [(NSDictionary*)responseObject objectForKey:@"location"]; - NSData *data = [self downloadFromLocation:location]; + + NSData *data = [self downloadFromLocation:location pointer:attachment messageId:messageId]; if (data) { [self decryptedAndSaveAttachment:attachment data:data messageId:messageId]; } }); } } failure:^(NSURLSessionDataTask *task, NSError *error) { - DDLogError(@"Failed task %@ error: %@", task.description, error.description); + DDLogError(@"Failed retrieval of attachment with error: %@", error.description); + [self setFailedAttachment:attachment inMessage:messageId]; + }]; +} + +- (void)setAttachment:(TSAttachmentPointer*)pointer isDownloadingInMessage:(NSString*)messageId { + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [pointer setDownloading:YES]; + [pointer saveWithTransaction:transaction]; + TSMessage *message = [TSMessage fetchObjectWithUniqueID:messageId transaction:transaction]; + [message saveWithTransaction:transaction]; + }]; +} + +- (void)setFailedAttachment:(TSAttachmentPointer*)pointer inMessage:(NSString*)messageId { + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [pointer setDownloading:NO]; + [pointer setFailed:YES]; + [pointer saveWithTransaction:transaction]; + TSMessage *message = [TSMessage fetchObjectWithUniqueID:messageId transaction:transaction]; + [message saveWithTransaction:transaction]; }]; } @@ -157,6 +181,7 @@ dispatch_queue_t attachmentsQueue() { TSAttachmentStream *stream = [[TSAttachmentStream alloc] initWithIdentifier:attachment.uniqueId data:plaintext key:attachment.encryptionKey contentType:attachment.contentType]; + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [stream saveWithTransaction:transaction]; if([attachment.avatarOfGroupId length]!=0) { @@ -174,7 +199,7 @@ dispatch_queue_t attachmentsQueue() { } } -- (NSData*)downloadFromLocation:(NSString*)location { +- (NSData*)downloadFromLocation:(NSString*)location pointer:(TSAttachmentPointer*)pointer messageId:(NSString*)messageId{ __block NSData *data; AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; @@ -182,14 +207,17 @@ dispatch_queue_t attachmentsQueue() { [manager.requestSerializer setValue:@"application/octet-stream" forHTTPHeaderField:@"Content-Type"]; manager.responseSerializer = [AFHTTPResponseSerializer serializer]; manager.completionQueue = dispatch_get_main_queue(); - + dispatch_semaphore_t sema = dispatch_semaphore_create(0); [manager GET:location parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { data = responseObject; dispatch_semaphore_signal(sema); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { - DDLogError(@"Failed to retreive attachment with error: %@", error.description); + DDLogError(@"Failed to retrieve attachment with error: %@", error.description); + if (pointer && messageId) { + [self setFailedAttachment:pointer inMessage:messageId]; + } dispatch_semaphore_signal(sema); }]; diff --git a/Signal/src/view controllers/MessagesViewController.m b/Signal/src/view controllers/MessagesViewController.m index 7c44ff3a1..ed15d53cd 100644 --- a/Signal/src/view controllers/MessagesViewController.m +++ b/Signal/src/view controllers/MessagesViewController.m @@ -47,6 +47,7 @@ #import "TSIncomingMessage.h" #import "TSInteraction.h" #import "TSAttachmentAdapter.h" +#import "TSAttachmentPointer.h" #import "TSVideoAttachmentAdapter.h" #import "TSMessagesManager+sendMessages.h" @@ -913,6 +914,7 @@ typedef enum : NSUInteger { [self handleErrorMessageTap:(TSErrorMessage*)interaction]; break; case TSInfoMessageAdapter: + [self handleWarningTap:interaction]; break; case TSCallAdapter: break; @@ -921,6 +923,31 @@ typedef enum : NSUInteger { } } +- (void)handleWarningTap:(TSInteraction*)interaction { + + if ([interaction isKindOfClass:[TSIncomingMessage class]]) { + TSIncomingMessage *message = (TSIncomingMessage*) interaction; + + for (NSString *attachmentId in message.attachments) { + __block TSAttachment *attachment; + + [self.editingDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction]; + }]; + + if ([attachment isKindOfClass:[TSAttachmentPointer class]]) { + TSAttachmentPointer *pointer = (TSAttachmentPointer*)attachment; + + if (!pointer.isDownloading) { + [[TSMessagesManager sharedManager] retrieveAttachment:pointer messageId:message.uniqueId]; + } + } + } + + } + +} + -(void)moviePlayBackDidFinish:(id)sender { DDLogDebug(@"playback finished"); diff --git a/Signal/src/view controllers/TSMessageAdapter.m b/Signal/src/view controllers/TSMessageAdapter.m index 09154adf5..51b07ad09 100644 --- a/Signal/src/view controllers/TSMessageAdapter.m +++ b/Signal/src/view controllers/TSMessageAdapter.m @@ -115,13 +115,21 @@ } } else if ([attachment isKindOfClass:[TSAttachmentPointer class]]){ - // can do loading information here - //TSAttachmentPointer *pointer = (TSAttachmentPointer*)attachment; - //TODO: Change this status when download failed; - adapter.messageBody = @"Attachment is downloading"; + TSAttachmentPointer *pointer = (TSAttachmentPointer*)attachment; adapter.messageType = TSInfoMessageAdapter; + + if (pointer.isDownloading) { + adapter.messageBody = @"Attachment is downloading."; + } else { + if (pointer.hasFailed) { + adapter.messageBody = @"Attachment download failed, tap to retry."; + } else { + adapter.messageBody = @"New attachment queued for retrieval."; + } + } + } else { - DDLogError(@"We retreived an attachment that doesn't have a known type : %@", NSStringFromClass([attachment class])); + DDLogError(@"We retrieved an attachment that doesn't have a known type : %@", NSStringFromClass([attachment class])); } } } diff --git a/Signal/test/textsecure/TSMessageStorageTests.m b/Signal/test/textsecure/TSMessageStorageTests.m index 64e306d29..5978b38b2 100644 --- a/Signal/test/textsecure/TSMessageStorageTests.m +++ b/Signal/test/textsecure/TSMessageStorageTests.m @@ -88,8 +88,8 @@ attachments:nil]; [newMessage saveWithTransaction:transaction]; - TSIncomingMessage *retreived = [TSIncomingMessage fetchObjectWithUniqueID:[@(messageInt+50) stringValue] transaction:transaction]; - XCTAssert(retreived.timestamp == uniqueNewTimestamp); + TSIncomingMessage *retrieved = [TSIncomingMessage fetchObjectWithUniqueID:[@(messageInt+50) stringValue] transaction:transaction]; + XCTAssert(retrieved.timestamp == uniqueNewTimestamp); }]; }