Add download progress indicators.
This commit is contained in:
parent
a26086b303
commit
654325c6dc
|
@ -283,6 +283,7 @@
|
|||
34E5DC8220D8050D00C08145 /* RegistrationUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E5DC8120D8050D00C08145 /* RegistrationUtils.m */; };
|
||||
34E88D262098C5AE00A608F4 /* ContactViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E88D252098C5AE00A608F4 /* ContactViewController.swift */; };
|
||||
34E8A8D12085238A00B272B1 /* ProtoParsingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E8A8D02085238900B272B1 /* ProtoParsingTest.m */; };
|
||||
34EA69402194933900702471 /* AttachmentDownloadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EA693F2194933900702471 /* AttachmentDownloadView.swift */; };
|
||||
34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */; };
|
||||
34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */; };
|
||||
4503F1BE20470A5B00CEE724 /* classic-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */; };
|
||||
|
@ -981,6 +982,7 @@
|
|||
34E5DC8120D8050D00C08145 /* RegistrationUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RegistrationUtils.m; sourceTree = "<group>"; };
|
||||
34E88D252098C5AE00A608F4 /* ContactViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactViewController.swift; sourceTree = "<group>"; };
|
||||
34E8A8D02085238900B272B1 /* ProtoParsingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProtoParsingTest.m; sourceTree = "<group>"; };
|
||||
34EA693F2194933900702471 /* AttachmentDownloadView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentDownloadView.swift; sourceTree = "<group>"; };
|
||||
34F308A01ECB469700BB7697 /* OWSBezierPathView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBezierPathView.h; sourceTree = "<group>"; };
|
||||
34F308A11ECB469700BB7697 /* OWSBezierPathView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBezierPathView.m; sourceTree = "<group>"; };
|
||||
34FD936E1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAnyTouchGestureRecognizer.h; path = views/OWSAnyTouchGestureRecognizer.h; sourceTree = "<group>"; };
|
||||
|
@ -1828,6 +1830,7 @@
|
|||
34D1F0951F867BFC0066283D /* Cells */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
34EA693F2194933900702471 /* AttachmentDownloadView.swift */,
|
||||
34D1F0BB1F8D108C0066283D /* AttachmentUploadView.h */,
|
||||
34D1F0BC1F8D108C0066283D /* AttachmentUploadView.m */,
|
||||
3488F9352191CC4000E524CC /* ConversationMediaView.swift */,
|
||||
|
@ -3419,6 +3422,7 @@
|
|||
458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */,
|
||||
34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */,
|
||||
4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */,
|
||||
34EA69402194933900702471 /* AttachmentDownloadView.swift in Sources */,
|
||||
340FC8AB204DAC8D007AEB0F /* DomainFrontingCountryViewController.m in Sources */,
|
||||
3496744D2076768700080B5F /* OWSMessageBubbleView.m in Sources */,
|
||||
34B3F8751E8DF1700035BE1A /* CallViewController.swift in Sources */,
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc
|
||||
public class AttachmentDownloadView: UIView {
|
||||
|
||||
// MARK: - Dependencies
|
||||
|
||||
private var attachmentDownloads: OWSAttachmentDownloads {
|
||||
return SSKEnvironment.shared.attachmentDownloads
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
private let attachmentId: String
|
||||
private let radius: CGFloat
|
||||
private let shapeLayer = CAShapeLayer()
|
||||
|
||||
@objc
|
||||
public required init(attachmentId: String, radius: CGFloat) {
|
||||
self.attachmentId = attachmentId
|
||||
self.radius = radius
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
layer.addSublayer(shapeLayer)
|
||||
}
|
||||
|
||||
@available(*, unavailable, message: "use other init() instead.")
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
notImplemented()
|
||||
}
|
||||
|
||||
@objc public override var bounds: CGRect {
|
||||
didSet {
|
||||
if oldValue != bounds {
|
||||
updateLayers()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc public override var frame: CGRect {
|
||||
didSet {
|
||||
if oldValue != frame {
|
||||
updateLayers()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal func updateLayers() {
|
||||
AssertIsOnMainThread()
|
||||
|
||||
self.shapeLayer.frame = self.bounds
|
||||
|
||||
guard let progress = attachmentDownloads.downloadProgress(forAttachmentId: attachmentId) else {
|
||||
Logger.warn("No progress for attachment.")
|
||||
shapeLayer.path = nil
|
||||
return
|
||||
}
|
||||
|
||||
// Prevent the shape layer from animating changes.
|
||||
CATransaction.begin()
|
||||
CATransaction.setDisableActions(true)
|
||||
|
||||
let center = CGPoint(x: self.bounds.width * 0.5,
|
||||
y: self.bounds.height * 0.5)
|
||||
let outerRadius: CGFloat = radius * 1.0
|
||||
let innerRadius: CGFloat = radius * 0.9
|
||||
let startAngle: CGFloat = CGFloat.pi * 1.5
|
||||
let endAngle: CGFloat = CGFloat.pi * (1.5 + 2 * CGFloat(progress.floatValue))
|
||||
|
||||
let bezierPath = UIBezierPath()
|
||||
bezierPath.addArc(withCenter: center, radius: outerRadius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
|
||||
bezierPath.addArc(withCenter: center, radius: innerRadius, startAngle: endAngle, endAngle: startAngle, clockwise: false)
|
||||
|
||||
shapeLayer.path = bezierPath.cgPath
|
||||
shapeLayer.fillColor = UIColor.ows_gray60.cgColor
|
||||
|
||||
CATransaction.commit()
|
||||
}
|
||||
}
|
|
@ -6,9 +6,19 @@ import Foundation
|
|||
|
||||
@objc
|
||||
public class ConversationMediaView: UIView {
|
||||
|
||||
// MARK: - Dependencies
|
||||
|
||||
private var attachmentDownloads: OWSAttachmentDownloads {
|
||||
return SSKEnvironment.shared.attachmentDownloads
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
private let mediaCache: NSCache<NSString, AnyObject>
|
||||
private let attachment: TSAttachment
|
||||
private let isOutgoing: Bool
|
||||
private let maxMessageWidth: CGFloat
|
||||
private var loadBlock : (() -> Void)?
|
||||
private var unloadBlock : (() -> Void)?
|
||||
private var didFailToLoad = false
|
||||
|
@ -16,10 +26,12 @@ public class ConversationMediaView: UIView {
|
|||
@objc
|
||||
public required init(mediaCache: NSCache<NSString, AnyObject>,
|
||||
attachment: TSAttachment,
|
||||
isOutgoing: Bool) {
|
||||
isOutgoing: Bool,
|
||||
maxMessageWidth: CGFloat) {
|
||||
self.mediaCache = mediaCache
|
||||
self.attachment = attachment
|
||||
self.isOutgoing = isOutgoing
|
||||
self.maxMessageWidth = maxMessageWidth
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
|
@ -38,6 +50,7 @@ public class ConversationMediaView: UIView {
|
|||
AssertIsOnMainThread()
|
||||
|
||||
guard let attachmentStream = attachment as? TSAttachmentStream else {
|
||||
addDownloadProgressIfNecessary()
|
||||
return
|
||||
}
|
||||
if attachmentStream.isAnimated {
|
||||
|
@ -49,11 +62,39 @@ public class ConversationMediaView: UIView {
|
|||
} else {
|
||||
// TODO: Handle this case.
|
||||
owsFailDebug("Attachment has unexpected type.")
|
||||
configureForMissingOrInvalid()
|
||||
}
|
||||
}
|
||||
|
||||
private func addAttachmentUploadViewIfNecessary(_ subview: UIView,
|
||||
completion: @escaping (Bool) -> Void) {
|
||||
//
|
||||
typealias ProgressCallback = (Bool) -> Void
|
||||
|
||||
private func addDownloadProgressIfNecessary() {
|
||||
guard let attachmentPointer = attachment as? TSAttachmentPointer else {
|
||||
owsFailDebug("Attachment has unexpected type.")
|
||||
configureForMissingOrInvalid()
|
||||
return
|
||||
}
|
||||
guard let attachmentId = attachmentPointer.uniqueId else {
|
||||
owsFailDebug("Attachment stream missing unique ID.")
|
||||
configureForMissingOrInvalid()
|
||||
return
|
||||
}
|
||||
|
||||
guard let progress = attachmentDownloads.downloadProgress(forAttachmentId: attachmentId) else {
|
||||
// Not being downloaded.
|
||||
configureForMissingOrInvalid()
|
||||
return
|
||||
}
|
||||
|
||||
backgroundColor = UIColor.ows_gray05
|
||||
let progressView = AttachmentDownloadView(attachmentId: attachmentId, radius: maxMessageWidth * 0.1)
|
||||
self.addSubview(progressView)
|
||||
progressView.autoPinEdgesToSuperviewEdges()
|
||||
}
|
||||
|
||||
private func addUploadProgressIfNecessary(_ subview: UIView,
|
||||
progressCallback: @escaping ProgressCallback) {
|
||||
guard isOutgoing else {
|
||||
return
|
||||
}
|
||||
|
@ -63,7 +104,8 @@ public class ConversationMediaView: UIView {
|
|||
guard !attachmentStream.isUploaded else {
|
||||
return
|
||||
}
|
||||
let uploadView = AttachmentUploadView(attachment: attachmentStream) { (_) in
|
||||
let uploadView = AttachmentUploadView(attachment: attachmentStream) { (isAttachmentReady) in
|
||||
progressCallback(isAttachmentReady)
|
||||
}
|
||||
subview.addSubview(uploadView)
|
||||
uploadView.autoPinEdgesToSuperviewEdges()
|
||||
|
@ -85,7 +127,7 @@ public class ConversationMediaView: UIView {
|
|||
animatedImageView.backgroundColor = Theme.offBackgroundColor
|
||||
addSubview(animatedImageView)
|
||||
animatedImageView.autoPinEdgesToSuperviewEdges()
|
||||
addAttachmentUploadViewIfNecessary(animatedImageView) { (_) in
|
||||
addUploadProgressIfNecessary(animatedImageView) { (_) in
|
||||
}
|
||||
loadBlock = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
|
@ -134,7 +176,7 @@ public class ConversationMediaView: UIView {
|
|||
stillImageView.backgroundColor = Theme.offBackgroundColor
|
||||
addSubview(stillImageView)
|
||||
stillImageView.autoPinEdgesToSuperviewEdges()
|
||||
addAttachmentUploadViewIfNecessary(stillImageView) { (_) in
|
||||
addUploadProgressIfNecessary(stillImageView) { (_) in
|
||||
}
|
||||
loadBlock = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
|
@ -188,7 +230,7 @@ public class ConversationMediaView: UIView {
|
|||
|
||||
addSubview(stillImageView)
|
||||
stillImageView.autoPinEdgesToSuperviewEdges()
|
||||
addAttachmentUploadViewIfNecessary(stillImageView) { (isAttachmentReady) in
|
||||
addUploadProgressIfNecessary(stillImageView) { (isAttachmentReady) in
|
||||
videoPlayButton.isHidden = !isAttachmentReady
|
||||
}
|
||||
|
||||
|
@ -210,8 +252,8 @@ public class ConversationMediaView: UIView {
|
|||
Logger.error("Could not load thumbnail")
|
||||
})
|
||||
},
|
||||
cacheKey: cacheKey,
|
||||
canLoadAsync: true)
|
||||
cacheKey: cacheKey,
|
||||
canLoadAsync: true)
|
||||
guard let image = cachedValue as? UIImage else {
|
||||
return
|
||||
}
|
||||
|
@ -222,6 +264,12 @@ public class ConversationMediaView: UIView {
|
|||
}
|
||||
}
|
||||
|
||||
private func configureForMissingOrInvalid() {
|
||||
// TODO: Get final value from design.
|
||||
backgroundColor = UIColor.ows_gray45
|
||||
// TODO: Add error icon.
|
||||
}
|
||||
|
||||
private func tryToLoadMedia(loadMediaBlock: @escaping () -> AnyObject?,
|
||||
cacheKey: String,
|
||||
canLoadAsync: Bool) -> AnyObject? {
|
||||
|
|
|
@ -28,7 +28,8 @@ public class MediaAlbumCellView: UIStackView {
|
|||
self.itemViews = MediaAlbumCellView.itemsToDisplay(forItems: items).map {
|
||||
ConversationMediaView(mediaCache: mediaCache,
|
||||
attachment: $0.attachment,
|
||||
isOutgoing: isOutgoing)
|
||||
isOutgoing: isOutgoing,
|
||||
maxMessageWidth: maxMessageWidth)
|
||||
}
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
|
|
@ -804,9 +804,11 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
|
|||
OWSAssertDebug(self.attachmentStream);
|
||||
OWSAssertDebug([self.attachmentStream isVisualMedia]);
|
||||
|
||||
ConversationMediaView *mediaView = [[ConversationMediaView alloc] initWithMediaCache:self.cellMediaCache
|
||||
attachment:self.attachmentStream
|
||||
isOutgoing:self.isOutgoing];
|
||||
ConversationMediaView *mediaView =
|
||||
[[ConversationMediaView alloc] initWithMediaCache:self.cellMediaCache
|
||||
attachment:self.attachmentStream
|
||||
isOutgoing:self.isOutgoing
|
||||
maxMessageWidth:self.conversationStyle.maxMessageWidth];
|
||||
self.loadCellContentBlock = ^{
|
||||
[mediaView loadMedia];
|
||||
};
|
||||
|
|
|
@ -24,6 +24,8 @@ extern NSString *const kAttachmentDownloadAttachmentIDKey;
|
|||
*/
|
||||
@interface OWSAttachmentDownloads : NSObject
|
||||
|
||||
- (nullable NSNumber *)downloadProgressForAttachmentId:(NSString *)attachmentId;
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -45,6 +45,7 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
@property (nonatomic, readonly, nullable) TSMessage *message;
|
||||
@property (nonatomic, readonly) AttachmentDownloadSuccess success;
|
||||
@property (nonatomic, readonly) AttachmentDownloadFailure failure;
|
||||
@property (atomic) CGFloat progress;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -77,7 +78,7 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
@interface OWSAttachmentDownloads ()
|
||||
|
||||
// This property should only be accessed while synchronized on this class.
|
||||
@property (nonatomic, readonly) NSMutableSet<NSString *> *downloadingAttachmentIdSet;
|
||||
@property (nonatomic, readonly) NSMutableDictionary<NSString *, OWSAttachmentDownloadJob *> *downloadingJobMap;
|
||||
// This property should only be accessed while synchronized on this class.
|
||||
@property (nonatomic, readonly) NSMutableArray<OWSAttachmentDownloadJob *> *attachmentDownloadJobQueue;
|
||||
|
||||
|
@ -109,7 +110,7 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
return self;
|
||||
}
|
||||
|
||||
_downloadingAttachmentIdSet = [NSMutableSet new];
|
||||
_downloadingJobMap = [NSMutableDictionary new];
|
||||
_attachmentDownloadJobQueue = [NSMutableArray new];
|
||||
|
||||
return self;
|
||||
|
@ -117,6 +118,18 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
|
||||
#pragma mark -
|
||||
|
||||
- (nullable NSNumber *)downloadProgressForAttachmentId:(NSString *)attachmentId
|
||||
{
|
||||
|
||||
@synchronized(self) {
|
||||
OWSAttachmentDownloadJob *_Nullable job = self.downloadingJobMap[attachmentId];
|
||||
if (!job) {
|
||||
return nil;
|
||||
}
|
||||
return @(job.progress);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)downloadAttachmentsForMessage:(TSMessage *)message
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
success:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))success
|
||||
|
@ -253,20 +266,20 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
|
||||
@synchronized(self) {
|
||||
const NSUInteger kMaxSimultaneousDownloads = 4;
|
||||
if (self.downloadingAttachmentIdSet.count >= kMaxSimultaneousDownloads) {
|
||||
if (self.downloadingJobMap.count >= kMaxSimultaneousDownloads) {
|
||||
return;
|
||||
}
|
||||
job = self.attachmentDownloadJobQueue.firstObject;
|
||||
if (!job) {
|
||||
return;
|
||||
}
|
||||
if ([self.downloadingAttachmentIdSet containsObject:job.attachmentPointer.uniqueId]) {
|
||||
if (self.downloadingJobMap[job.attachmentPointer.uniqueId] != nil) {
|
||||
// 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.downloadingJobMap[job.attachmentPointer.uniqueId] = job;
|
||||
}
|
||||
|
||||
[self.primaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
|
@ -278,7 +291,7 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
}
|
||||
}];
|
||||
|
||||
[self retrieveAttachment:job.attachmentPointer
|
||||
[self retrieveAttachmentForJob:job
|
||||
success:^(TSAttachmentStream *attachmentStream) {
|
||||
OWSLogVerbose(@"Attachment download succeeded.");
|
||||
|
||||
|
@ -294,7 +307,7 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
job.success(attachmentStream);
|
||||
|
||||
@synchronized(self) {
|
||||
[self.downloadingAttachmentIdSet removeObject:job.attachmentPointer.uniqueId];
|
||||
[self.downloadingJobMap removeObjectForKey:job.attachmentPointer.uniqueId];
|
||||
}
|
||||
|
||||
[self startDownloadIfPossible];
|
||||
|
@ -314,7 +327,7 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
}];
|
||||
|
||||
@synchronized(self) {
|
||||
[self.downloadingAttachmentIdSet removeObject:job.attachmentPointer.uniqueId];
|
||||
[self.downloadingJobMap removeObjectForKey:job.attachmentPointer.uniqueId];
|
||||
}
|
||||
|
||||
job.failure(error);
|
||||
|
@ -326,11 +339,12 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
|
||||
#pragma mark -
|
||||
|
||||
- (void)retrieveAttachment:(TSAttachmentPointer *)attachment
|
||||
success:(void (^)(TSAttachmentStream *attachmentStream))successHandler
|
||||
failure:(void (^)(NSError *error))failureHandler
|
||||
- (void)retrieveAttachmentForJob:(OWSAttachmentDownloadJob *)job
|
||||
success:(void (^)(TSAttachmentStream *attachmentStream))successHandler
|
||||
failure:(void (^)(NSError *error))failureHandler
|
||||
{
|
||||
OWSAssertDebug(attachment);
|
||||
OWSAssertDebug(job);
|
||||
TSAttachmentPointer *attachmentPointer = job.attachmentPointer;
|
||||
|
||||
__block OWSBackgroundTask *_Nullable backgroundTask =
|
||||
[OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
|
||||
|
@ -353,10 +367,10 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
});
|
||||
};
|
||||
|
||||
if (attachment.serverId < 100) {
|
||||
OWSLogError(@"Suspicious attachment id: %llu", (unsigned long long)attachment.serverId);
|
||||
if (attachmentPointer.serverId < 100) {
|
||||
OWSLogError(@"Suspicious attachment id: %llu", (unsigned long long)attachmentPointer.serverId);
|
||||
}
|
||||
TSRequest *request = [OWSRequestFactory attachmentRequestWithAttachmentId:attachment.serverId];
|
||||
TSRequest *request = [OWSRequestFactory attachmentRequestWithAttachmentId:attachmentPointer.serverId];
|
||||
|
||||
[self.networkManager makeRequest:request
|
||||
success:^(NSURLSessionDataTask *task, id responseObject) {
|
||||
|
@ -374,22 +388,22 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
|
||||
dispatch_async([OWSDispatch attachmentsQueue], ^{
|
||||
[self downloadFromLocation:location
|
||||
pointer:attachment
|
||||
job:job
|
||||
success:^(NSString *encryptedDataFilePath) {
|
||||
[self decryptAttachmentPath:encryptedDataFilePath
|
||||
pointer:attachment
|
||||
attachmentPointer:attachmentPointer
|
||||
success:markAndHandleSuccess
|
||||
failure:markAndHandleFailure];
|
||||
}
|
||||
failure:^(NSURLSessionTask *_Nullable task, NSError *error) {
|
||||
if (attachment.serverId < 100) {
|
||||
if (attachmentPointer.serverId < 100) {
|
||||
// This looks like the symptom of the "frequent 404
|
||||
// downloading attachments with low server ids".
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
|
||||
NSInteger statusCode = [httpResponse statusCode];
|
||||
OWSFailDebug(@"%d Failure with suspicious attachment id: %llu, %@",
|
||||
(int)statusCode,
|
||||
(unsigned long long)attachment.serverId,
|
||||
(unsigned long long)attachmentPointer.serverId,
|
||||
error);
|
||||
}
|
||||
markAndHandleFailure(error);
|
||||
|
@ -401,14 +415,14 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
OWSProdError([OWSAnalyticsEvents errorAttachmentRequestFailed]);
|
||||
}
|
||||
OWSLogError(@"Failed retrieval of attachment with error: %@", error);
|
||||
if (attachment.serverId < 100) {
|
||||
if (attachmentPointer.serverId < 100) {
|
||||
// This _shouldn't_ be the symptom of the "frequent 404
|
||||
// downloading attachments with low server ids".
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
|
||||
NSInteger statusCode = [httpResponse statusCode];
|
||||
OWSFailDebug(@"%d Failure with suspicious attachment id: %llu, %@",
|
||||
(int)statusCode,
|
||||
(unsigned long long)attachment.serverId,
|
||||
(unsigned long long)attachmentPointer.serverId,
|
||||
error);
|
||||
}
|
||||
return markAndHandleFailure(error);
|
||||
|
@ -416,12 +430,12 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
}
|
||||
|
||||
- (void)decryptAttachmentPath:(NSString *)encryptedDataFilePath
|
||||
pointer:(TSAttachmentPointer *)attachment
|
||||
attachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
success:(void (^)(TSAttachmentStream *attachmentStream))success
|
||||
failure:(void (^)(NSError *error))failure
|
||||
{
|
||||
OWSAssertDebug(encryptedDataFilePath.length > 0);
|
||||
OWSAssertDebug(attachment);
|
||||
OWSAssertDebug(attachmentPointer);
|
||||
|
||||
// Use attachmentDecryptSerialQueue to ensure that we only load into memory
|
||||
// & decrypt a single attachment at a time.
|
||||
|
@ -435,7 +449,10 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
return failure(error);
|
||||
}
|
||||
|
||||
[self decryptAttachmentData:encryptedData pointer:attachment success:success failure:failure];
|
||||
[self decryptAttachmentData:encryptedData
|
||||
attachmentPointer:attachmentPointer
|
||||
success:success
|
||||
failure:failure];
|
||||
|
||||
if (![OWSFileSystem deleteFile:encryptedDataFilePath]) {
|
||||
OWSLogError(@"Could not delete temporary file.");
|
||||
|
@ -445,15 +462,17 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
}
|
||||
|
||||
- (void)decryptAttachmentData:(NSData *)cipherText
|
||||
pointer:(TSAttachmentPointer *)attachment
|
||||
attachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
success:(void (^)(TSAttachmentStream *attachmentStream))successHandler
|
||||
failure:(void (^)(NSError *error))failureHandler
|
||||
{
|
||||
OWSAssertDebug(attachmentPointer);
|
||||
|
||||
NSError *decryptError;
|
||||
NSData *_Nullable plaintext = [Cryptography decryptAttachment:cipherText
|
||||
withKey:attachment.encryptionKey
|
||||
digest:attachment.digest
|
||||
unpaddedSize:attachment.byteCount
|
||||
withKey:attachmentPointer.encryptionKey
|
||||
digest:attachmentPointer.digest
|
||||
unpaddedSize:attachmentPointer.byteCount
|
||||
error:&decryptError];
|
||||
|
||||
if (decryptError) {
|
||||
|
@ -469,7 +488,7 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
return;
|
||||
}
|
||||
|
||||
TSAttachmentStream *stream = [[TSAttachmentStream alloc] initWithPointer:attachment];
|
||||
TSAttachmentStream *stream = [[TSAttachmentStream alloc] initWithPointer:attachmentPointer];
|
||||
|
||||
NSError *writeError;
|
||||
[stream writeData:plaintext error:&writeError];
|
||||
|
@ -494,10 +513,13 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
}
|
||||
|
||||
- (void)downloadFromLocation:(NSString *)location
|
||||
pointer:(TSAttachmentPointer *)pointer
|
||||
job:(OWSAttachmentDownloadJob *)job
|
||||
success:(void (^)(NSString *encryptedDataPath))successHandler
|
||||
failure:(void (^)(NSURLSessionTask *_Nullable task, NSError *error))failureHandlerParam
|
||||
{
|
||||
OWSAssertDebug(job);
|
||||
TSAttachmentPointer *attachmentPointer = job.attachmentPointer;
|
||||
|
||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
||||
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
|
||||
[manager.requestSerializer setValue:OWSMimeTypeApplicationOctetStream forHTTPHeaderField:@"Content-Type"];
|
||||
|
@ -560,8 +582,10 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
|
|||
return;
|
||||
}
|
||||
|
||||
job.progress = progress.fractionCompleted;
|
||||
|
||||
[self fireProgressNotification:MAX(kAttachmentDownloadProgressTheta, progress.fractionCompleted)
|
||||
attachmentId:pointer.uniqueId];
|
||||
attachmentId:attachmentPointer.uniqueId];
|
||||
|
||||
// We only need to check the content length header once.
|
||||
if (hasCheckedContentLength) {
|
||||
|
|
Loading…
Reference in New Issue