Add OWSAttachmentDownloads.
This commit is contained in:
parent
b25f17a27c
commit
3daf7d4744
|
@ -86,7 +86,6 @@
|
|||
#import <SignalServiceKit/NSTimer+OWS.h>
|
||||
#import <SignalServiceKit/OWSAnalytics.h>
|
||||
#import <SignalServiceKit/OWSAnalyticsEvents.h>
|
||||
#import <SignalServiceKit/OWSAttachmentsProcessor.h>
|
||||
#import <SignalServiceKit/OWSBackgroundTask.h>
|
||||
#import <SignalServiceKit/OWSCallMessageHandler.h>
|
||||
#import <SignalServiceKit/OWSContactsOutputStream.h>
|
||||
|
|
|
@ -234,7 +234,6 @@ public class ConversationMediaView: UIView {
|
|||
AssertIsOnMainThread()
|
||||
|
||||
guard let loadBlock = loadBlock else {
|
||||
owsFailDebug("Missing loadBlock")
|
||||
return
|
||||
}
|
||||
loadBlock()
|
||||
|
@ -245,7 +244,6 @@ public class ConversationMediaView: UIView {
|
|||
AssertIsOnMainThread()
|
||||
|
||||
guard let unloadBlock = unloadBlock else {
|
||||
owsFailDebug("Missing unloadBlock")
|
||||
return
|
||||
}
|
||||
unloadBlock()
|
||||
|
|
|
@ -39,8 +39,7 @@ extern const UIDataDetectorTypes kOWSAllowedDataDetectorTypes;
|
|||
|
||||
- (void)didTapTruncatedTextMessage:(id<ConversationViewItem>)conversationItem;
|
||||
|
||||
- (void)didTapFailedIncomingAttachment:(id<ConversationViewItem>)viewItem
|
||||
attachmentPointer:(TSAttachmentPointer *)attachmentPointer;
|
||||
- (void)didTapFailedIncomingAttachment:(id<ConversationViewItem>)viewItem;
|
||||
|
||||
- (void)didTapConversationItem:(id<ConversationViewItem>)viewItem quotedReply:(OWSQuotedReplyModel *)quotedReply;
|
||||
- (void)didTapConversationItem:(id<ConversationViewItem>)viewItem
|
||||
|
|
|
@ -1402,7 +1402,7 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
OWSAssertDebug(attachmentPointer);
|
||||
|
||||
if (attachmentPointer.state == TSAttachmentPointerStateFailed) {
|
||||
[self.delegate didTapFailedIncomingAttachment:self.viewItem attachmentPointer:attachmentPointer];
|
||||
[self.delegate didTapFailedIncomingAttachment:self.viewItem];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
#import <SignalServiceKit/NSTimer+OWS.h>
|
||||
#import <SignalServiceKit/OWSAddToContactsOfferMessage.h>
|
||||
#import <SignalServiceKit/OWSAddToProfileWhitelistOfferMessage.h>
|
||||
#import <SignalServiceKit/OWSAttachmentsProcessor.h>
|
||||
#import <SignalServiceKit/OWSAttachmentDownloads.h>
|
||||
#import <SignalServiceKit/OWSBlockingManager.h>
|
||||
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
|
||||
#import <SignalServiceKit/OWSIdentityManager.h>
|
||||
|
@ -297,6 +297,11 @@ typedef enum : NSUInteger {
|
|||
return SSKEnvironment.shared.typingIndicators;
|
||||
}
|
||||
|
||||
- (OWSAttachmentDownloads *)attachmentDownloads
|
||||
{
|
||||
return SSKEnvironment.shared.attachmentDownloads;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)addNotificationListeners
|
||||
|
@ -1644,13 +1649,11 @@ typedef enum : NSUInteger {
|
|||
#pragma mark Bubble User Actions
|
||||
|
||||
- (void)handleFailedDownloadTapForMessage:(TSMessage *)message
|
||||
attachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
{
|
||||
OWSAttachmentsProcessor *processor =
|
||||
[[OWSAttachmentsProcessor alloc] initWithAttachmentPointers:@[ attachmentPointer ]];
|
||||
OWSAssert(message);
|
||||
|
||||
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[processor fetchAttachmentsForMessage:message
|
||||
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[self.attachmentDownloads downloadAttachmentsForMessage:message
|
||||
transaction:transaction
|
||||
success:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
OWSLogInfo(@"Successfully redownloaded attachment in thread: %@", message.thread);
|
||||
|
@ -2159,15 +2162,13 @@ typedef enum : NSUInteger {
|
|||
}
|
||||
|
||||
- (void)didTapFailedIncomingAttachment:(id<ConversationViewItem>)viewItem
|
||||
attachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(viewItem);
|
||||
OWSAssertDebug(attachmentPointer);
|
||||
|
||||
// Restart failed downloads
|
||||
TSMessage *message = (TSMessage *)viewItem.interaction;
|
||||
[self handleFailedDownloadTapForMessage:message attachmentPointer:attachmentPointer];
|
||||
[self handleFailedDownloadTapForMessage:message];
|
||||
}
|
||||
|
||||
- (void)didTapFailedOutgoingMessage:(TSOutgoingMessage *)message
|
||||
|
@ -2192,17 +2193,13 @@ typedef enum : NSUInteger {
|
|||
return;
|
||||
}
|
||||
|
||||
OWSAttachmentsProcessor *processor =
|
||||
[[OWSAttachmentsProcessor alloc] initWithAttachmentPointers:@[ attachmentPointer ]];
|
||||
|
||||
[self.editingDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[processor fetchAttachmentsForMessage:nil
|
||||
transaction:transaction
|
||||
[self.uiDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[self.attachmentDownloads downloadAttachmentPointer:attachmentPointer
|
||||
success:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
OWSAssertDebug(attachmentStreams.count == 1);
|
||||
TSAttachmentStream *attachmentStream = attachmentStreams.firstObject;
|
||||
[self.editingDatabaseConnection
|
||||
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *postSuccessTransaction) {
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *postSuccessTransaction) {
|
||||
[message setQuotedMessageThumbnailAttachmentStream:attachmentStream];
|
||||
[message saveWithTransaction:postSuccessTransaction];
|
||||
}];
|
||||
|
@ -2210,8 +2207,8 @@ typedef enum : NSUInteger {
|
|||
failure:^(NSError *error) {
|
||||
OWSLogWarn(@"Failed to redownload thumbnail with error: %@", error);
|
||||
[self.editingDatabaseConnection
|
||||
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *postSuccessTransaction) {
|
||||
[message touchWithTransaction:transaction];
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *postSuccessTransaction) {
|
||||
[message touchWithTransaction:postSuccessTransaction];
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
|
|
|
@ -694,7 +694,7 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele
|
|||
navigationController.pushViewController(viewController, animated: true)
|
||||
}
|
||||
|
||||
func didTapFailedIncomingAttachment(_ viewItem: ConversationViewItem, attachmentPointer: TSAttachmentPointer) {
|
||||
func didTapFailedIncomingAttachment(_ viewItem: ConversationViewItem) {
|
||||
// no - op
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#import <SignalMessaging/SignalMessaging-Swift.h>
|
||||
#import <SignalServiceKit/ContactDiscoveryService.h>
|
||||
#import <SignalServiceKit/OWS2FAManager.h>
|
||||
#import <SignalServiceKit/OWSAttachmentDownloads.h>
|
||||
#import <SignalServiceKit/OWSBackgroundTask.h>
|
||||
#import <SignalServiceKit/OWSBatchMessageProcessor.h>
|
||||
#import <SignalServiceKit/OWSBlockingManager.h>
|
||||
|
@ -86,6 +87,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSSyncManager *syncManager = [[OWSSyncManager alloc] initDefault];
|
||||
id<SSKReachabilityManager> reachabilityManager = [SSKReachabilityManagerImpl new];
|
||||
id<OWSTypingIndicators> typingIndicators = [[OWSTypingIndicatorsImpl alloc] init];
|
||||
OWSAttachmentDownloads *attachmentDownloads = [[OWSAttachmentDownloads alloc] init];
|
||||
|
||||
OWSAudioSession *audioSession = [OWSAudioSession new];
|
||||
OWSSounds *sounds = [[OWSSounds alloc] initWithPrimaryStorage:primaryStorage];
|
||||
|
@ -123,7 +125,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
outgoingReceiptManager:outgoingReceiptManager
|
||||
reachabilityManager:reachabilityManager
|
||||
syncManager:syncManager
|
||||
typingIndicators:typingIndicators]];
|
||||
typingIndicators:typingIndicators
|
||||
attachmentDownloads:attachmentDownloads]];
|
||||
|
||||
appSpecificSingletonBlock();
|
||||
|
||||
|
|
|
@ -5,24 +5,14 @@
|
|||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class OWSIncomingSentMessageTranscript;
|
||||
@class OWSPrimaryStorage;
|
||||
@class OWSReadReceiptManager;
|
||||
@class TSAttachmentStream;
|
||||
@class TSNetworkManager;
|
||||
@class YapDatabaseReadWriteTransaction;
|
||||
|
||||
@protocol ContactsManagerProtocol;
|
||||
|
||||
// This job is used to process "outgoing message" notifications from linked devices.
|
||||
@interface OWSRecordTranscriptJob : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithIncomingSentMessageTranscript:(OWSIncomingSentMessageTranscript *)incomingSentMessageTranscript;
|
||||
- (instancetype)initWithIncomingSentMessageTranscript:(OWSIncomingSentMessageTranscript *)incomingSentMessageTranscript
|
||||
networkManager:(TSNetworkManager *)networkManager
|
||||
primaryStorage:(OWSPrimaryStorage *)primaryStorage
|
||||
readReceiptManager:(OWSReadReceiptManager *)readReceiptManager
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)runWithAttachmentHandler:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))attachmentHandler
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
|
||||
#import "OWSRecordTranscriptJob.h"
|
||||
#import "OWSAttachmentsProcessor.h"
|
||||
#import "OWSAttachmentDownloads.h"
|
||||
#import "OWSDisappearingMessagesJob.h"
|
||||
#import "OWSIncomingSentMessageTranscript.h"
|
||||
#import "OWSPrimaryStorage+SessionStore.h"
|
||||
|
@ -19,31 +19,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@interface OWSRecordTranscriptJob ()
|
||||
|
||||
@property (nonatomic, readonly) TSNetworkManager *networkManager;
|
||||
@property (nonatomic, readonly) OWSPrimaryStorage *primaryStorage;
|
||||
@property (nonatomic, readonly) OWSReadReceiptManager *readReceiptManager;
|
||||
@property (nonatomic, readonly) id<ContactsManagerProtocol> contactsManager;
|
||||
|
||||
@property (nonatomic, readonly) OWSIncomingSentMessageTranscript *incomingSentMessageTranscript;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSRecordTranscriptJob
|
||||
|
||||
- (instancetype)initWithIncomingSentMessageTranscript:(OWSIncomingSentMessageTranscript *)incomingSentMessageTranscript
|
||||
{
|
||||
return [self initWithIncomingSentMessageTranscript:incomingSentMessageTranscript
|
||||
networkManager:TSNetworkManager.sharedManager
|
||||
primaryStorage:OWSPrimaryStorage.sharedManager
|
||||
readReceiptManager:OWSReadReceiptManager.sharedManager
|
||||
contactsManager:SSKEnvironment.shared.contactsManager];
|
||||
}
|
||||
|
||||
- (instancetype)initWithIncomingSentMessageTranscript:(OWSIncomingSentMessageTranscript *)incomingSentMessageTranscript
|
||||
networkManager:(TSNetworkManager *)networkManager
|
||||
primaryStorage:(OWSPrimaryStorage *)primaryStorage
|
||||
readReceiptManager:(OWSReadReceiptManager *)readReceiptManager
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
|
@ -51,14 +35,47 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
|
||||
_incomingSentMessageTranscript = incomingSentMessageTranscript;
|
||||
_networkManager = networkManager;
|
||||
_primaryStorage = primaryStorage;
|
||||
_readReceiptManager = readReceiptManager;
|
||||
_contactsManager = contactsManager;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Dependencies
|
||||
|
||||
- (OWSPrimaryStorage *)primaryStorage
|
||||
{
|
||||
OWSAssertDebug(SSKEnvironment.shared.primaryStorage);
|
||||
|
||||
return SSKEnvironment.shared.primaryStorage;
|
||||
}
|
||||
|
||||
- (TSNetworkManager *)networkManager
|
||||
{
|
||||
OWSAssertDebug(SSKEnvironment.shared.networkManager);
|
||||
|
||||
return SSKEnvironment.shared.networkManager;
|
||||
}
|
||||
|
||||
- (OWSReadReceiptManager *)readReceiptManager
|
||||
{
|
||||
OWSAssert(SSKEnvironment.shared.readReceiptManager);
|
||||
|
||||
return SSKEnvironment.shared.readReceiptManager;
|
||||
}
|
||||
|
||||
- (id<ContactsManagerProtocol>)contactsManager
|
||||
{
|
||||
OWSAssertDebug(SSKEnvironment.shared.contactsManager);
|
||||
|
||||
return SSKEnvironment.shared.contactsManager;
|
||||
}
|
||||
|
||||
- (OWSAttachmentDownloads *)attachmentDownloads
|
||||
{
|
||||
return SSKEnvironment.shared.attachmentDownloads;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)runWithAttachmentHandler:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))attachmentHandler
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
|
@ -107,22 +124,19 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
transaction:transaction];
|
||||
|
||||
if ([attachmentPointer isKindOfClass:[TSAttachmentPointer class]]) {
|
||||
OWSAttachmentsProcessor *attachmentProcessor =
|
||||
[[OWSAttachmentsProcessor alloc] initWithAttachmentPointers:@[ attachmentPointer ]];
|
||||
OWSLogDebug(@"downloading attachments for transcript: %lu", (unsigned long)transcript.timestamp);
|
||||
|
||||
OWSLogDebug(@"downloading thumbnail for transcript: %lu", (unsigned long)transcript.timestamp);
|
||||
[attachmentProcessor fetchAttachmentsForMessage:outgoingMessage
|
||||
transaction:transaction
|
||||
[self.attachmentDownloads downloadAttachmentPointer:attachmentPointer
|
||||
success:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
OWSAssertDebug(attachmentStreams.count == 1);
|
||||
TSAttachmentStream *attachmentStream = attachmentStreams.firstObject;
|
||||
[self.primaryStorage.newDatabaseConnection
|
||||
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[outgoingMessage setQuotedMessageThumbnailAttachmentStream:attachmentStream];
|
||||
[outgoingMessage saveWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
failure:^(NSError *_Nonnull error) {
|
||||
failure:^(NSError *error) {
|
||||
OWSLogWarn(@"failed to fetch thumbnail for transcript: %lu with error: %@",
|
||||
(unsigned long)transcript.timestamp,
|
||||
error);
|
||||
|
@ -161,15 +175,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self.readReceiptManager applyEarlyReadReceiptsForOutgoingMessageFromLinkedDevice:outgoingMessage
|
||||
transaction:transaction];
|
||||
|
||||
OWSAttachmentsProcessor *attachmentsProcessor =
|
||||
[[OWSAttachmentsProcessor alloc] initWithAttachmentPointers:attachmentPointers];
|
||||
[attachmentsProcessor
|
||||
fetchAttachmentsForMessage:outgoingMessage
|
||||
transaction:transaction
|
||||
success:attachmentHandler
|
||||
failure:^(NSError *_Nonnull error) {
|
||||
OWSLogError(@"failed to fetch transcripts attachments for message: %@", outgoingMessage);
|
||||
}];
|
||||
[self.attachmentDownloads
|
||||
downloadAttachmentsForMessage:outgoingMessage
|
||||
transaction:transaction
|
||||
success:attachmentHandler
|
||||
failure:^(NSError *error) {
|
||||
OWSLogError(
|
||||
@"failed to fetch transcripts attachments for message: %@", outgoingMessage);
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern NSString *const kAttachmentDownloadProgressNotification;
|
||||
extern NSString *const kAttachmentDownloadProgressKey;
|
||||
extern NSString *const kAttachmentDownloadAttachmentIDKey;
|
||||
|
||||
@class SSKProtoAttachmentPointer;
|
||||
@class TSAttachment;
|
||||
@class TSAttachmentPointer;
|
||||
@class TSAttachmentStream;
|
||||
@class TSMessage;
|
||||
@class YapDatabaseReadTransaction;
|
||||
@class YapDatabaseReadWriteTransaction;
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/**
|
||||
* Given incoming attachment protos, determines which we support.
|
||||
* It can download those that we support and notifies threads when it receives unsupported attachments.
|
||||
*/
|
||||
@interface OWSAttachmentDownloads : NSObject
|
||||
|
||||
// This will try to download all un-downloaded attachments for a given message.
|
||||
// Any attachments for the message which are already downloaded are skipped BUT
|
||||
// they are included in the success callback.
|
||||
//
|
||||
// success/failure are always called on a worker queue.
|
||||
- (void)downloadAttachmentsForMessage:(TSMessage *)message
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
success:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))success
|
||||
failure:(void (^)(NSError *error))failure;
|
||||
|
||||
// This will try to download a single attachment.
|
||||
//
|
||||
// success/failure are always called on a worker queue.
|
||||
- (void)downloadAttachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
success:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))success
|
||||
failure:(void (^)(NSError *error))failure;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -2,7 +2,7 @@
|
|||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSAttachmentsProcessor.h"
|
||||
#import "OWSAttachmentDownloads.h"
|
||||
#import "AppContext.h"
|
||||
#import "MIMETypeUtil.h"
|
||||
#import "NSNotificationCenter+OWS.h"
|
||||
|
@ -36,103 +36,307 @@ NSString *const kAttachmentDownloadAttachmentIDKey = @"kAttachmentDownloadAttach
|
|||
// indicator shows up as quickly as possible.
|
||||
static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
|
||||
|
||||
@interface OWSAttachmentsProcessor ()
|
||||
typedef void (^AttachmentDownloadSuccess)(TSAttachmentStream *attachmentStream);
|
||||
typedef void (^AttachmentDownloadFailure)(NSError *error);
|
||||
|
||||
@property (nonatomic, readonly) TSNetworkManager *networkManager;
|
||||
@interface OWSAttachmentDownloadJob : NSObject
|
||||
|
||||
@property (nonatomic, readonly) TSAttachmentPointer *attachmentPointer;
|
||||
@property (nonatomic, readonly, nullable) TSMessage *message;
|
||||
@property (nonatomic, readonly) AttachmentDownloadSuccess success;
|
||||
@property (nonatomic, readonly) AttachmentDownloadFailure failure;
|
||||
|
||||
@end
|
||||
|
||||
@implementation OWSAttachmentsProcessor
|
||||
#pragma mark -
|
||||
|
||||
- (instancetype)initWithAttachmentPointers:(NSArray<TSAttachmentPointer *> *)attachmentPointers
|
||||
@implementation OWSAttachmentDownloadJob
|
||||
|
||||
- (instancetype)initWithAttachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
message:(nullable TSMessage *)message
|
||||
success:(AttachmentDownloadSuccess)success
|
||||
failure:(AttachmentDownloadFailure)failure
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_attachmentPointers = attachmentPointers;
|
||||
_attachmentPointer = attachmentPointer;
|
||||
_message = message;
|
||||
_success = success;
|
||||
_failure = failure;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSAttachmentDownloads ()
|
||||
|
||||
// This property should only be accessed while synchronized on this class.
|
||||
@property (nonatomic, readonly) NSMutableSet<NSString *> *downloadingAttachmentIdSet;
|
||||
// This property should only be accessed while synchronized on this class.
|
||||
@property (nonatomic, readonly) NSMutableArray<OWSAttachmentDownloadJob *> *attachmentDownloadJobQueue;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSAttachmentDownloads
|
||||
|
||||
#pragma mark - Dependencies
|
||||
|
||||
- (OWSPrimaryStorage *)primaryStorage
|
||||
{
|
||||
return SSKEnvironment.shared.primaryStorage;
|
||||
}
|
||||
|
||||
- (TSNetworkManager *)networkManager
|
||||
{
|
||||
return SSKEnvironment.shared.networkManager;
|
||||
}
|
||||
|
||||
#pragma mark
|
||||
|
||||
- (void)fetchAttachmentsForMessage:(nullable TSMessage *)message
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
success:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))successHandler
|
||||
failure:(void (^)(NSError *error))failureHandler
|
||||
#pragma mark -
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
OWSAssertDebug(transaction);
|
||||
OWSAssertDebug(self.attachmentPointers.count > 0);
|
||||
|
||||
NSMutableArray<AnyPromise *> *promises = [NSMutableArray array];
|
||||
NSMutableArray<TSAttachmentStream *> *attachmentStreams = [NSMutableArray array];
|
||||
|
||||
for (TSAttachmentPointer *attachmentPointer in self.attachmentPointers) {
|
||||
AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
|
||||
[self retrieveAttachment:attachmentPointer
|
||||
message:message
|
||||
transaction:transaction
|
||||
success:^(TSAttachmentStream *attachmentStream) {
|
||||
OWSLogVerbose(@"Attachment download succeeded.");
|
||||
@synchronized(attachmentStreams) {
|
||||
[attachmentStreams addObject:attachmentStream];
|
||||
}
|
||||
resolve(@(1));
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
OWSLogError(@"Attachment download failed with error: %@", error);
|
||||
resolve(error);
|
||||
}];
|
||||
}];
|
||||
[promises addObject:promise];
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
// We use PMKJoin(), not PMKWhen(), because we don't want the
|
||||
// completion promise to execute until _all_ promises
|
||||
// have either succeeded or failed. PMKWhen() executes as
|
||||
// soon as any of its input promises fail.
|
||||
AnyPromise *completionPromise
|
||||
= PMKJoin(promises)
|
||||
.then(^(id value) {
|
||||
NSArray<TSAttachmentStream *> *attachmentStreamsCopy;
|
||||
@synchronized(attachmentStreams) {
|
||||
attachmentStreamsCopy = [attachmentStreams copy];
|
||||
}
|
||||
OWSLogInfo(@"Attachment downloads succeeded: %lu.", (unsigned long)attachmentStreamsCopy.count);
|
||||
successHandler(attachmentStreamsCopy);
|
||||
})
|
||||
.catch(^(NSError *error) {
|
||||
failureHandler(error);
|
||||
});
|
||||
[completionPromise retainUntilComplete];
|
||||
_downloadingAttachmentIdSet = [NSMutableSet new];
|
||||
_attachmentDownloadJobQueue = [NSMutableArray new];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)downloadAttachmentsForMessage:(TSMessage *)message
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
success:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))success
|
||||
failure:(void (^)(NSError *error))failure
|
||||
{
|
||||
OWSAssertDebug(transaction);
|
||||
OWSAssertDebug(message);
|
||||
|
||||
NSMutableArray<TSAttachmentStream *> *attachmentStreams = [NSMutableArray array];
|
||||
NSMutableArray<TSAttachmentPointer *> *attachmentPointers = [NSMutableArray new];
|
||||
|
||||
for (TSAttachment *attachment in [message attachmentsWithTransaction:transaction]) {
|
||||
if ([attachment isKindOfClass:[TSAttachmentStream class]]) {
|
||||
TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment;
|
||||
[attachmentStreams addObject:attachmentStream];
|
||||
} else if ([attachment isKindOfClass:[TSAttachmentPointer class]]) {
|
||||
TSAttachmentPointer *attachmentPointer = (TSAttachmentPointer *)attachment;
|
||||
[attachmentPointers addObject:attachmentPointer];
|
||||
} else {
|
||||
OWSFailDebug(@"Unexpected attachment type: %@", attachment.class);
|
||||
}
|
||||
}
|
||||
|
||||
[self enqueueJobsForAttachmentStreams:attachmentStreams
|
||||
attachmentPointers:attachmentPointers
|
||||
message:message
|
||||
success:success
|
||||
failure:failure];
|
||||
}
|
||||
|
||||
- (void)downloadAttachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
success:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))success
|
||||
failure:(void (^)(NSError *error))failure
|
||||
{
|
||||
OWSAssertDebug(attachmentPointer);
|
||||
|
||||
[self enqueueJobsForAttachmentStreams:@[]
|
||||
attachmentPointers:@[
|
||||
attachmentPointer,
|
||||
]
|
||||
message:nil
|
||||
success:success
|
||||
failure:failure];
|
||||
}
|
||||
|
||||
- (void)enqueueJobsForAttachmentStreams:(NSArray<TSAttachmentStream *> *)attachmentStreamsParam
|
||||
attachmentPointers:(NSArray<TSAttachmentPointer *> *)attachmentPointers
|
||||
message:(nullable TSMessage *)message
|
||||
success:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))successHandler
|
||||
failure:(void (^)(NSError *error))failureHandler
|
||||
{
|
||||
OWSAssertDebug(attachmentStreamsParam);
|
||||
OWSAssertDebug(attachmentPointers.count > 0);
|
||||
|
||||
// To avoid deadlocks, synchronize on self outside of the transaction.
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
if (attachmentPointers.count < 1) {
|
||||
OWSAssertDebug(attachmentStreamsParam.count > 0);
|
||||
successHandler(attachmentStreamsParam);
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableArray<TSAttachmentStream *> *attachmentStreams = [attachmentStreamsParam mutableCopy];
|
||||
NSMutableArray<AnyPromise *> *promises = [NSMutableArray array];
|
||||
for (TSAttachmentPointer *attachmentPointer in attachmentPointers) {
|
||||
AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
|
||||
[self enqueueJobForAttachmentPointer:attachmentPointer
|
||||
message:message
|
||||
success:^(TSAttachmentStream *attachmentStream) {
|
||||
@synchronized(attachmentStreams) {
|
||||
[attachmentStreams addObject:attachmentStream];
|
||||
}
|
||||
|
||||
resolve(@(1));
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
resolve(error);
|
||||
}];
|
||||
}];
|
||||
[promises addObject:promise];
|
||||
}
|
||||
|
||||
// We use PMKJoin(), not PMKWhen(), because we don't want the
|
||||
// completion promise to execute until _all_ promises
|
||||
// have either succeeded or failed. PMKWhen() executes as
|
||||
// soon as any of its input promises fail.
|
||||
AnyPromise *completionPromise
|
||||
= PMKJoin(promises)
|
||||
.then(^(id value) {
|
||||
NSArray<TSAttachmentStream *> *attachmentStreamsCopy;
|
||||
@synchronized(attachmentStreams) {
|
||||
attachmentStreamsCopy = [attachmentStreams copy];
|
||||
}
|
||||
OWSLogInfo(@"Attachment downloads succeeded: %lu.", (unsigned long)attachmentStreamsCopy.count);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
successHandler(attachmentStreamsCopy);
|
||||
});
|
||||
})
|
||||
.catch(^(NSError *error) {
|
||||
OWSLogError(@"Attachment downloads failed.");
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
failureHandler(error);
|
||||
});
|
||||
});
|
||||
[completionPromise retainUntilComplete];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)enqueueJobForAttachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
message:(nullable TSMessage *)message
|
||||
success:(void (^)(TSAttachmentStream *attachmentStream))success
|
||||
failure:(void (^)(NSError *error))failure
|
||||
{
|
||||
OWSAssertDebug(attachmentPointer);
|
||||
|
||||
OWSAttachmentDownloadJob *job = [[OWSAttachmentDownloadJob alloc] initWithAttachmentPointer:attachmentPointer
|
||||
message:message
|
||||
success:success
|
||||
failure:failure];
|
||||
|
||||
@synchronized(self) {
|
||||
[self.attachmentDownloadJobQueue addObject:job];
|
||||
}
|
||||
|
||||
[self startDownloadIfPossible];
|
||||
}
|
||||
|
||||
- (void)startDownloadIfPossible
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
OWSAttachmentDownloadJob *_Nullable job;
|
||||
|
||||
@synchronized(self) {
|
||||
const NSUInteger kMaxSimultaneousDownloads = 4;
|
||||
if (self.downloadingAttachmentIdSet.count >= kMaxSimultaneousDownloads) {
|
||||
return;
|
||||
}
|
||||
job = self.attachmentDownloadJobQueue.firstObject;
|
||||
if (!job) {
|
||||
return;
|
||||
}
|
||||
if ([self.downloadingAttachmentIdSet containsObject:job.attachmentPointer.uniqueId]) {
|
||||
// Ensure we only have one download in flight at a time for a given attachment.
|
||||
OWSLogWarn(@"Ignoring duplicate download.");
|
||||
return;
|
||||
}
|
||||
[self.attachmentDownloadJobQueue removeObjectAtIndex:0];
|
||||
[self.downloadingAttachmentIdSet addObject:job.attachmentPointer.uniqueId];
|
||||
}
|
||||
|
||||
[self.primaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
job.attachmentPointer.state = TSAttachmentPointerStateDownloading;
|
||||
[job.attachmentPointer saveWithTransaction:transaction];
|
||||
|
||||
if (job.message) {
|
||||
[job.message touchWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
|
||||
[self retrieveAttachment:job.attachmentPointer
|
||||
success:^(TSAttachmentStream *attachmentStream) {
|
||||
OWSLogVerbose(@"Attachment download succeeded.");
|
||||
|
||||
[self.primaryStorage.dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[attachmentStream saveWithTransaction:transaction];
|
||||
|
||||
if (job.message) {
|
||||
[job.message touchWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
|
||||
job.success(attachmentStream);
|
||||
|
||||
@synchronized(self) {
|
||||
[self.downloadingAttachmentIdSet removeObject:job.attachmentPointer.uniqueId];
|
||||
}
|
||||
|
||||
[self startDownloadIfPossible];
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
OWSLogError(@"Attachment download failed with error: %@", error);
|
||||
|
||||
[self.primaryStorage.dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
job.attachmentPointer.mostRecentFailureLocalizedText = error.localizedDescription;
|
||||
job.attachmentPointer.state = TSAttachmentPointerStateFailed;
|
||||
[job.attachmentPointer saveWithTransaction:transaction];
|
||||
|
||||
if (job.message) {
|
||||
[job.message touchWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
|
||||
@synchronized(self) {
|
||||
[self.downloadingAttachmentIdSet removeObject:job.attachmentPointer.uniqueId];
|
||||
}
|
||||
|
||||
job.failure(error);
|
||||
|
||||
[self startDownloadIfPossible];
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)retrieveAttachment:(TSAttachmentPointer *)attachment
|
||||
message:(nullable TSMessage *)message
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
success:(void (^)(TSAttachmentStream *attachmentStream))successHandler
|
||||
failure:(void (^)(NSError *error))failureHandler
|
||||
{
|
||||
OWSAssertDebug(transaction);
|
||||
OWSAssertDebug(attachment);
|
||||
|
||||
__block OWSBackgroundTask *_Nullable backgroundTask =
|
||||
[OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
|
||||
|
||||
[self setAttachment:attachment isDownloadingInMessage:message transaction:transaction];
|
||||
|
||||
void (^markAndHandleFailure)(NSError *) = ^(NSError *error) {
|
||||
// Ensure enclosing transaction is complete.
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[self setAttachment:attachment didFailInMessage:message error:error];
|
||||
failureHandler(error);
|
||||
|
||||
OWSAssertDebug(backgroundTask);
|
||||
|
@ -141,12 +345,8 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
|
|||
};
|
||||
|
||||
void (^markAndHandleSuccess)(TSAttachmentStream *attachmentStream) = ^(TSAttachmentStream *attachmentStream) {
|
||||
// Ensure enclosing transaction is complete.
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
successHandler(attachmentStream);
|
||||
if (message) {
|
||||
[message touch];
|
||||
}
|
||||
|
||||
OWSAssertDebug(backgroundTask);
|
||||
backgroundTask = nil;
|
||||
|
@ -263,7 +463,8 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
|
|||
}
|
||||
|
||||
if (!plaintext) {
|
||||
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, NSLocalizedString(@"ERROR_MESSAGE_INVALID_MESSAGE", @""));
|
||||
NSError *error = OWSErrorWithCodeDescription(
|
||||
OWSErrorCodeFailedToDecryptMessage, NSLocalizedString(@"ERROR_MESSAGE_INVALID_MESSAGE", @""));
|
||||
failureHandler(error);
|
||||
return;
|
||||
}
|
||||
|
@ -278,7 +479,6 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
|
|||
return;
|
||||
}
|
||||
|
||||
[stream save];
|
||||
successHandler(stream);
|
||||
}
|
||||
|
||||
|
@ -299,7 +499,7 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
|
|||
failure:(void (^)(NSURLSessionTask *_Nullable task, NSError *error))failureHandlerParam
|
||||
{
|
||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
||||
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
|
||||
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
|
||||
[manager.requestSerializer setValue:OWSMimeTypeApplicationOctetStream forHTTPHeaderField:@"Content-Type"];
|
||||
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
|
||||
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
|
@ -451,31 +651,6 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)setAttachment:(TSAttachmentPointer *)pointer
|
||||
isDownloadingInMessage:(nullable TSMessage *)message
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssertDebug(transaction);
|
||||
|
||||
pointer.state = TSAttachmentPointerStateDownloading;
|
||||
[pointer saveWithTransaction:transaction];
|
||||
if (message) {
|
||||
[message touchWithTransaction:transaction];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setAttachment:(TSAttachmentPointer *)pointer
|
||||
didFailInMessage:(nullable TSMessage *)message
|
||||
error:(NSError *)error
|
||||
{
|
||||
pointer.mostRecentFailureLocalizedText = error.localizedDescription;
|
||||
pointer.state = TSAttachmentPointerStateFailed;
|
||||
[pointer save];
|
||||
if (message) {
|
||||
[message touch];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -107,6 +107,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
(NSArray<SSKProtoAttachmentPointer *> *)attachmentProtos
|
||||
albumMessage:(TSMessage *)albumMessage
|
||||
{
|
||||
OWSAssertDebug(attachmentProtos);
|
||||
OWSAssertDebug(albumMessage);
|
||||
|
||||
NSMutableArray *attachmentPointers = [NSMutableArray new];
|
||||
for (SSKProtoAttachmentPointer *attachmentProto in attachmentProtos) {
|
||||
TSAttachmentPointer *_Nullable attachmentPointer =
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#import "MimeTypeUtil.h"
|
||||
#import "NSNotificationCenter+OWS.h"
|
||||
#import "NotificationsProtocol.h"
|
||||
#import "OWSAttachmentsProcessor.h"
|
||||
#import "OWSAttachmentDownloads.h"
|
||||
#import "OWSBlockingManager.h"
|
||||
#import "OWSCallMessageHandler.h"
|
||||
#import "OWSContact.h"
|
||||
|
@ -164,6 +164,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return SSKEnvironment.shared.typingIndicators;
|
||||
}
|
||||
|
||||
- (OWSAttachmentDownloads *)attachmentDownloads
|
||||
{
|
||||
return SSKEnvironment.shared.attachmentDownloads;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)startObserving
|
||||
|
@ -729,13 +734,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return;
|
||||
}
|
||||
|
||||
TSAttachmentPointer *avatarPointer =
|
||||
TSAttachmentPointer *_Nullable avatarPointer =
|
||||
[TSAttachmentPointer attachmentPointerFromProto:dataMessage.group.avatar albumMessage:nil];
|
||||
OWSAttachmentsProcessor *attachmentsProcessor =
|
||||
[[OWSAttachmentsProcessor alloc] initWithAttachmentPointers:@[ avatarPointer ]];
|
||||
|
||||
[attachmentsProcessor fetchAttachmentsForMessage:nil
|
||||
transaction:transaction
|
||||
if (!avatarPointer) {
|
||||
OWSLogWarn(@"received unsupported group avatar envelope");
|
||||
return;
|
||||
}
|
||||
[self.attachmentDownloads downloadAttachmentPointer:avatarPointer
|
||||
success:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
OWSAssertDebug(attachmentStreams.count == 1);
|
||||
TSAttachmentStream *attachmentStream = attachmentStreams.firstObject;
|
||||
|
@ -771,35 +777,26 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return;
|
||||
}
|
||||
|
||||
TSIncomingMessage *_Nullable createdMessage = [self handleReceivedEnvelope:envelope
|
||||
withDataMessage:dataMessage
|
||||
transaction:transaction];
|
||||
if (!createdMessage) {
|
||||
TSIncomingMessage *_Nullable message =
|
||||
[self handleReceivedEnvelope:envelope withDataMessage:dataMessage transaction:transaction];
|
||||
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray<TSAttachmentPointer *> *attachmentPointers =
|
||||
[TSAttachmentPointer attachmentPointersFromProtos:dataMessage.attachments albumMessage:createdMessage];
|
||||
for (TSAttachmentPointer *pointer in attachmentPointers) {
|
||||
[pointer saveWithTransaction:transaction];
|
||||
[createdMessage.attachmentIds addObject:pointer.uniqueId];
|
||||
}
|
||||
[createdMessage saveWithTransaction:transaction];
|
||||
[message saveWithTransaction:transaction];
|
||||
|
||||
OWSLogDebug(@"incoming attachment message: %@", createdMessage.debugDescription);
|
||||
OWSLogDebug(@"incoming attachment message: %@", message.debugDescription);
|
||||
|
||||
OWSAttachmentsProcessor *attachmentsProcessor =
|
||||
[[OWSAttachmentsProcessor alloc] initWithAttachmentPointers:attachmentPointers];
|
||||
|
||||
[attachmentsProcessor fetchAttachmentsForMessage:createdMessage
|
||||
[self.attachmentDownloads downloadAttachmentsForMessage:message
|
||||
transaction:transaction
|
||||
success:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
OWSLogDebug(@"successfully fetched attachments: %lu for message: %@",
|
||||
(unsigned long)attachmentStreams.count,
|
||||
createdMessage);
|
||||
message);
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
OWSLogError(@"failed to fetch attachments for message: %@ with error: %@", createdMessage, error);
|
||||
OWSLogError(@"failed to fetch attachments for message: %@ with error: %@", message, error);
|
||||
}];
|
||||
}
|
||||
|
||||
|
@ -1264,6 +1261,22 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
serverTimestamp:serverTimestamp
|
||||
wasReceivedByUD:wasReceivedByUD];
|
||||
|
||||
NSArray<TSAttachmentPointer *> *attachmentPointers =
|
||||
[TSAttachmentPointer attachmentPointersFromProtos:dataMessage.attachments
|
||||
albumMessage:incomingMessage];
|
||||
for (TSAttachmentPointer *pointer in attachmentPointers) {
|
||||
[pointer saveWithTransaction:transaction];
|
||||
[incomingMessage.attachmentIds addObject:pointer.uniqueId];
|
||||
}
|
||||
|
||||
if (body.length == 0 && attachmentPointers.count < 1 && !contact) {
|
||||
OWSLogWarn(@"ignoring empty incoming message from: %@ for group: %@ with timestamp: %lu",
|
||||
envelopeAddress(envelope),
|
||||
groupId,
|
||||
(unsigned long)timestamp);
|
||||
return nil;
|
||||
}
|
||||
|
||||
[self finalizeIncomingMessage:incomingMessage
|
||||
thread:oldGroupThread
|
||||
envelope:envelope
|
||||
|
@ -1298,6 +1311,20 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
serverTimestamp:serverTimestamp
|
||||
wasReceivedByUD:wasReceivedByUD];
|
||||
|
||||
NSArray<TSAttachmentPointer *> *attachmentPointers =
|
||||
[TSAttachmentPointer attachmentPointersFromProtos:dataMessage.attachments albumMessage:incomingMessage];
|
||||
for (TSAttachmentPointer *pointer in attachmentPointers) {
|
||||
[pointer saveWithTransaction:transaction];
|
||||
[incomingMessage.attachmentIds addObject:pointer.uniqueId];
|
||||
}
|
||||
|
||||
if (body.length == 0 && attachmentPointers.count < 1 && !contact) {
|
||||
OWSLogWarn(@"ignoring empty incoming message from: %@ with timestamp: %lu",
|
||||
envelopeAddress(envelope),
|
||||
(unsigned long)timestamp);
|
||||
return nil;
|
||||
}
|
||||
|
||||
[self finalizeIncomingMessage:incomingMessage
|
||||
thread:thread
|
||||
envelope:envelope
|
||||
|
@ -1344,16 +1371,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
transaction:transaction];
|
||||
|
||||
if ([attachmentPointer isKindOfClass:[TSAttachmentPointer class]]) {
|
||||
OWSAttachmentsProcessor *attachmentProcessor =
|
||||
[[OWSAttachmentsProcessor alloc] initWithAttachmentPointers:@[ attachmentPointer ]];
|
||||
|
||||
OWSLogDebug(@"downloading thumbnail for message: %lu", (unsigned long)incomingMessage.timestamp);
|
||||
[attachmentProcessor fetchAttachmentsForMessage:incomingMessage
|
||||
transaction:transaction
|
||||
[self.attachmentDownloads downloadAttachmentPointer:attachmentPointer
|
||||
success:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
OWSAssertDebug(attachmentStreams.count == 1);
|
||||
TSAttachmentStream *attachmentStream = attachmentStreams.firstObject;
|
||||
[self.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[incomingMessage setQuotedMessageThumbnailAttachmentStream:attachmentStream];
|
||||
[incomingMessage saveWithTransaction:transaction];
|
||||
}];
|
||||
|
@ -1374,14 +1397,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
if (![attachmentPointer isKindOfClass:[TSAttachmentPointer class]]) {
|
||||
OWSFailDebug(@"avatar attachmentPointer was unexpectedly nil");
|
||||
} else {
|
||||
OWSAttachmentsProcessor *attachmentProcessor =
|
||||
[[OWSAttachmentsProcessor alloc] initWithAttachmentPointers:@[ attachmentPointer ]];
|
||||
|
||||
OWSLogDebug(@"downloading contact avatar for message: %lu", (unsigned long)incomingMessage.timestamp);
|
||||
[attachmentProcessor fetchAttachmentsForMessage:incomingMessage
|
||||
transaction:transaction
|
||||
|
||||
[self.attachmentDownloads downloadAttachmentPointer:attachmentPointer
|
||||
success:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
[self.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[incomingMessage touchWithTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@class ContactDiscoveryService;
|
||||
@class ContactsUpdater;
|
||||
@class OWS2FAManager;
|
||||
@class OWSAttachmentDownloads;
|
||||
@class OWSBatchMessageProcessor;
|
||||
@class OWSBlockingManager;
|
||||
@class OWSDisappearingMessagesJob;
|
||||
|
@ -60,7 +61,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
outgoingReceiptManager:(OWSOutgoingReceiptManager *)outgoingReceiptManager
|
||||
reachabilityManager:(id<SSKReachabilityManager>)reachabilityManager
|
||||
syncManager:(id<OWSSyncManagerProtocol>)syncManager
|
||||
typingIndicators:(id<OWSTypingIndicators>)typingIndicators NS_DESIGNATED_INITIALIZER;
|
||||
typingIndicators:(id<OWSTypingIndicators>)typingIndicators
|
||||
attachmentDownloads:(OWSAttachmentDownloads *)attachmentDownloads NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
|
@ -97,6 +99,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (nonatomic, readonly) id<OWSSyncManagerProtocol> syncManager;
|
||||
@property (nonatomic, readonly) id<SSKReachabilityManager> reachabilityManager;
|
||||
@property (nonatomic, readonly) id<OWSTypingIndicators> typingIndicators;
|
||||
@property (nonatomic, readonly) OWSAttachmentDownloads *attachmentDownloads;
|
||||
|
||||
// This property is configured after Environment is created.
|
||||
@property (atomic, nullable) id<OWSCallMessageHandler> callMessageHandler;
|
||||
|
|
|
@ -35,6 +35,7 @@ static SSKEnvironment *sharedSSKEnvironment;
|
|||
@property (nonatomic) id<OWSSyncManagerProtocol> syncManager;
|
||||
@property (nonatomic) id<SSKReachabilityManager> reachabilityManager;
|
||||
@property (nonatomic) id<OWSTypingIndicators> typingIndicators;
|
||||
@property (nonatomic) OWSAttachmentDownloads *attachmentDownloads;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -73,6 +74,7 @@ static SSKEnvironment *sharedSSKEnvironment;
|
|||
reachabilityManager:(id<SSKReachabilityManager>)reachabilityManager
|
||||
syncManager:(id<OWSSyncManagerProtocol>)syncManager
|
||||
typingIndicators:(id<OWSTypingIndicators>)typingIndicators
|
||||
attachmentDownloads:(OWSAttachmentDownloads *)attachmentDownloads
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
|
@ -103,6 +105,7 @@ static SSKEnvironment *sharedSSKEnvironment;
|
|||
OWSAssertDebug(syncManager);
|
||||
OWSAssertDebug(reachabilityManager);
|
||||
OWSAssertDebug(typingIndicators);
|
||||
OWSAssertDebug(attachmentDownloads);
|
||||
|
||||
_contactsManager = contactsManager;
|
||||
_messageSender = messageSender;
|
||||
|
@ -128,6 +131,7 @@ static SSKEnvironment *sharedSSKEnvironment;
|
|||
_syncManager = syncManager;
|
||||
_reachabilityManager = reachabilityManager;
|
||||
_typingIndicators = typingIndicators;
|
||||
_attachmentDownloads = attachmentDownloads;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#import "MockSSKEnvironment.h"
|
||||
#import "ContactDiscoveryService.h"
|
||||
#import "OWS2FAManager.h"
|
||||
#import "OWSAttachmentDownloads.h"
|
||||
#import "OWSBatchMessageProcessor.h"
|
||||
#import "OWSBlockingManager.h"
|
||||
#import "OWSDisappearingMessagesJob.h"
|
||||
|
@ -76,6 +77,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
id<SSKReachabilityManager> reachabilityManager = [SSKReachabilityManagerImpl new];
|
||||
id<OWSSyncManagerProtocol> syncManager = [[OWSMockSyncManager alloc] init];
|
||||
id<OWSTypingIndicators> typingIndicators = [[OWSTypingIndicatorsImpl alloc] init];
|
||||
OWSAttachmentDownloads *attachmentDownloads = [[OWSAttachmentDownloads alloc] init];
|
||||
|
||||
self = [super initWithContactsManager:contactsManager
|
||||
messageSender:messageSender
|
||||
|
@ -100,7 +102,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
outgoingReceiptManager:outgoingReceiptManager
|
||||
reachabilityManager:reachabilityManager
|
||||
syncManager:syncManager
|
||||
typingIndicators:typingIndicators];
|
||||
typingIndicators:typingIndicators
|
||||
attachmentDownloads:attachmentDownloads];
|
||||
|
||||
if (!self) {
|
||||
return nil;
|
||||
|
|
Loading…
Reference in New Issue