Merge branch 'charlesmchen/lazyLoadAttachmentsCR'

This commit is contained in:
Matthew Chen 2017-09-19 09:36:21 -04:00
commit 90eebb3d7d
14 changed files with 184 additions and 78 deletions

View File

@ -369,7 +369,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
return NO;
}
id<DataSource> _Nullable dataSource = [DataSourcePath dataSourceWithURL:url];
DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithURL:url];
if (!dataSource) {
DDLogError(@"Application opened with URL with unloadable content: %@", url);
[OWSAlerts showAlertWithTitle:

View File

@ -72,7 +72,10 @@ class SignalAttachment: NSObject {
return dataSource.dataUrl()
}
public var sourceFilename: String? {
return dataSource.sourceFilename()
return dataSource.sourceFilename
}
public var isValidImage: Bool {
return dataSource.isValidImage()
}
// Attachment types are identified using UTIs.
@ -288,18 +291,6 @@ class SignalAttachment: NSObject {
return SignalAttachment.audioUTISet.contains(dataUTI)
}
public var isValidImage: Bool {
if let dataPath = dataSource.dataPathIfOnDisk() {
// if ows_isValidImage is given a file path, it will
// avoid loading most of the data into memory, which
// is considerably more performant, so try to do that.
return NSData.ows_isValidImage(atPath:dataPath)
}
let data = dataSource.data()
return (data as NSData).ows_isValidImage()
}
public class func pasteboardHasPossibleAttachment() -> Bool {
return UIPasteboard.general.numberOfItems > 0
}
@ -471,7 +462,7 @@ class SignalAttachment: NSObject {
}
Logger.verbose("\(TAG) Compressing attachment as image/jpeg")
return compressImageAsJPEG(image : image, attachment : attachment, filename:dataSource.sourceFilename())
return compressImageAsJPEG(image : image, attachment : attachment, filename:dataSource.sourceFilename)
}
}
@ -512,7 +503,7 @@ class SignalAttachment: NSObject {
guard let image = image else {
let dataSource = DataSourceValue.emptyDataSource()
dataSource.setSourceFilename(filename)
dataSource.sourceFilename = filename
let attachment = SignalAttachment(dataSource:dataSource, dataUTI: dataUTI)
attachment.error = .missingData
return attachment
@ -520,7 +511,7 @@ class SignalAttachment: NSObject {
// Make a placeholder attachment on which to hang errors if necessary.
let dataSource = DataSourceValue.emptyDataSource()
dataSource.setSourceFilename(filename)
dataSource.sourceFilename = filename
let attachment = SignalAttachment(dataSource : dataSource, dataUTI: dataUTI)
attachment.image = image
@ -550,7 +541,7 @@ class SignalAttachment: NSObject {
attachment.error = .couldNotConvertToJpeg
return attachment
}
dataSource.setSourceFilename(filename)
dataSource.sourceFilename = filename
if UInt(jpgImageData.count) <= kMaxFileSizeImage {
let recompressedAttachment = SignalAttachment(dataSource : dataSource, dataUTI: kUTTypeJPEG as String)

View File

@ -1681,7 +1681,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread];
TSOutgoingMessage *message;
if ([text lengthOfBytesUsingEncoding:NSUTF8StringEncoding] >= kOversizeTextMessageSizeThreshold) {
id<DataSource> _Nullable dataSource = [DataSourceValue dataSourceWithOversizeText:text];
DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithOversizeText:text];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:kOversizeTextAttachmentUTI];
message =
@ -3206,7 +3206,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
OWSAssert(type);
OWSAssert(filename);
id<DataSource> _Nullable dataSource = [DataSourcePath dataSourceWithURL:url];
DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithURL:url];
if (!dataSource) {
OWSFail(@"%@ attachment data was unexpectedly empty for picked document url: %@", self.tag, url);
@ -3386,7 +3386,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
}
OWSAssert([NSThread isMainThread]);
id<DataSource> _Nullable dataSource =
DataSource *_Nullable dataSource =
[DataSourceValue dataSourceWithData:imageData utiType:dataUTI];
[dataSource setSourceFilename:filename];
SignalAttachment *attachment =
@ -3477,9 +3477,11 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
}
[modalActivityIndicator dismissWithCompletion:^{
id<DataSource> _Nullable dataSource =
DataSource *_Nullable dataSource =
[DataSourcePath dataSourceWithURL:compressedVideoUrl];
[dataSource setSourceFilename:filename];
// Remove temporary file when complete.
[dataSource setShouldDeleteOnDeallocation];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource
dataUTI:(NSString *)kUTTypeMPEG4];
@ -3523,6 +3525,8 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
- (void)yapDatabaseModified:(NSNotification *)notification
{
OWSAssert([NSThread isMainThread]);
// Currently, we update thread and message state every time
// the database is modified. That doesn't seem optimal, but
// in practice it's efficient enough.
@ -3642,6 +3646,8 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
}
}
completion:^(BOOL success) {
OWSAssert([NSThread isMainThread]);
if (!success) {
[self resetContentAndLayout];
}
@ -3859,7 +3865,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
return;
}
id<DataSource> _Nullable dataSource = [DataSourcePath dataSourceWithURL:self.audioRecorder.url];
DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithURL:self.audioRecorder.url];
self.audioRecorder = nil;
if (!dataSource) {
@ -3871,6 +3877,8 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
NSString *filename = [NSLocalizedString(@"VOICE_MESSAGE_FILE_NAME", @"Filename for voice messages.")
stringByAppendingPathExtension:@"m4a"];
[dataSource setSourceFilename:filename];
// Remove temporary file when complete.
[dataSource setShouldDeleteOnDeallocation];
SignalAttachment *attachment =
[SignalAttachment voiceMessageAttachmentWithDataSource:dataSource dataUTI:(NSString *)kUTTypeMPEG4Audio];
if (!attachment || [attachment hasError]) {
@ -4091,7 +4099,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
if (newGroupModel.groupImage) {
NSData *data = UIImagePNGRepresentation(newGroupModel.groupImage);
id<DataSource> _Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"];
DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"];
[self.messageSender sendAttachmentData:dataSource
contentType:OWSMimeTypeImagePng
sourceFilename:nil

View File

@ -325,7 +325,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSMessageSender *messageSender = [Environment getCurrent].messageSender;
NSString *filename = [filePath lastPathComponent];
NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:filename.pathExtension];
id<DataSource> _Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath];
DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath];
[dataSource setSourceFilename:filename];
SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType];
OWSAssert(attachment);
@ -585,7 +585,7 @@ NS_ASSUME_NONNULL_BEGIN
@"lorem, in rhoncus nisi."];
}
id<DataSource> _Nullable dataSource = [DataSourceValue dataSourceWithOversizeText:message];
DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithOversizeText:message];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:kOversizeTextAttachmentUTI];
[ThreadUtil sendMessageWithAttachment:attachment inThread:thread messageSender:messageSender];
@ -611,7 +611,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (void)sendRandomAttachment:(TSThread *)thread uti:(NSString *)uti length:(NSUInteger)length
{
OWSMessageSender *messageSender = [Environment getCurrent].messageSender;
id<DataSource> _Nullable dataSource =
DataSource *_Nullable dataSource =
[DataSourceValue dataSourceWithData:[self createRandomNSDataOfSize:length] utiType:uti];
SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:uti];
[ThreadUtil sendMessageWithAttachment:attachment inThread:thread messageSender:messageSender ignoreErrors:YES];

View File

@ -497,7 +497,7 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
if (model.groupImage) {
NSData *data = UIImagePNGRepresentation(model.groupImage);
id<DataSource> _Nullable dataSource =
DataSource *_Nullable dataSource =
[DataSourceValue dataSourceWithData:data fileExtension:@"png"];
[self.messageSender sendAttachmentData:dataSource
contentType:OWSMimeTypeImagePng

View File

@ -113,7 +113,7 @@ NSString *const kTSStorageManagerOWSContactsSyncingLastMessageKey =
self.isRequestInFlight = YES;
id<DataSource> dataSource =
DataSource *dataSource =
[DataSourceValue dataSourceWithSyncMessage:[syncContactsMessage buildPlainTextAttachmentData]];
[self.messageSender sendTemporaryAttachmentData:dataSource
contentType:OWSMimeTypeApplicationOctetStream

View File

@ -44,7 +44,7 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable NSData *)readDataFromFileWithError:(NSError **)error;
- (BOOL)writeData:(NSData *)data error:(NSError **)error;
- (BOOL)writeDataSource:(id<DataSource>)dataSource;
- (BOOL)writeDataSource:(DataSource *)dataSource;
+ (void)deleteAttachments;
+ (NSString *)attachmentsFolder;

View File

@ -158,7 +158,7 @@ NS_ASSUME_NONNULL_BEGIN
return [data writeToFile:filePath options:0 error:error];
}
- (BOOL)writeDataSource:(id<DataSource>)dataSource
- (BOOL)writeDataSource:(DataSource *)dataSource
{
OWSAssert(dataSource);

View File

@ -72,7 +72,7 @@ NS_SWIFT_NAME(MessageSender)
* Takes care of allocating and uploading the attachment, then sends the message.
* Only necessary to call once. If sending fails, retry with `sendMessage:`.
*/
- (void)sendAttachmentData:(id<DataSource>)dataSource
- (void)sendAttachmentData:(DataSource *)dataSource
contentType:(NSString *)contentType
sourceFilename:(nullable NSString *)sourceFilename
inMessage:(TSOutgoingMessage *)outgoingMessage
@ -83,7 +83,7 @@ NS_SWIFT_NAME(MessageSender)
* Same as `sendAttachmentData:`, but deletes the local copy of the attachment after sending.
* Used for sending sync request data, not for user visible attachments.
*/
- (void)sendTemporaryAttachmentData:(id<DataSource>)dataSource
- (void)sendTemporaryAttachmentData:(DataSource *)dataSource
contentType:(NSString *)contentType
inMessage:(TSOutgoingMessage *)outgoingMessage
success:(void (^)())successHandler

View File

@ -486,7 +486,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
failure:failureHandler];
}
- (void)sendTemporaryAttachmentData:(id<DataSource>)dataSource
- (void)sendTemporaryAttachmentData:(DataSource *)dataSource
contentType:(NSString *)contentType
inMessage:(TSOutgoingMessage *)message
success:(void (^)())successHandler
@ -516,7 +516,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
failure:failureWithDeleteHandler];
}
- (void)sendAttachmentData:(id<DataSource>)dataSource
- (void)sendAttachmentData:(DataSource *)dataSource
contentType:(NSString *)contentType
sourceFilename:(nullable NSString *)sourceFilename
inMessage:(TSOutgoingMessage *)message

View File

@ -743,7 +743,7 @@ NS_ASSUME_NONNULL_BEGIN
[[OWSSyncContactsMessage alloc] initWithSignalAccounts:self.contactsManager.signalAccounts
identityManager:self.identityManager
profileManager:self.profileManager];
id<DataSource> dataSource =
DataSource *dataSource =
[DataSourceValue dataSourceWithSyncMessage:[syncContactsMessage buildPlainTextAttachmentData]];
[self.messageSender sendTemporaryAttachmentData:dataSource
contentType:OWSMimeTypeApplicationOctetStream
@ -756,7 +756,7 @@ NS_ASSUME_NONNULL_BEGIN
}];
} else if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeGroups) {
OWSSyncGroupsMessage *syncGroupsMessage = [[OWSSyncGroupsMessage alloc] init];
id<DataSource> dataSource =
DataSource *dataSource =
[DataSourceValue dataSourceWithSyncMessage:[syncGroupsMessage buildPlainTextAttachmentData]];
[self.messageSender sendTemporaryAttachmentData:dataSource
contentType:OWSMimeTypeApplicationOctetStream
@ -882,7 +882,7 @@ NS_ASSUME_NONNULL_BEGIN
if (gThread.groupModel.groupImage) {
NSData *data = UIImagePNGRepresentation(gThread.groupModel.groupImage);
id<DataSource> _Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"];
DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"];
[self.messageSender sendAttachmentData:dataSource
contentType:OWSMimeTypeImagePng
sourceFilename:nil

View File

@ -9,7 +9,9 @@ NS_ASSUME_NONNULL_BEGIN
//
// * Lazy-load if possible.
// * Avoid duplicate reads & writes.
@protocol DataSource
@interface DataSource : NSObject
@property (nonatomic, nullable) NSString *sourceFilename;
// Should not be called unless necessary as it can involve an expensive read.
- (NSData *)data;
@ -21,50 +23,43 @@ NS_ASSUME_NONNULL_BEGIN
// Will only return nil in the error case.
- (nullable NSURL *)dataUrl;
// The file path for the data, if it already exists on disk.
//
// This method is safe to call as it will not do any expensive reads or writes.
//
// May return nil if the data does not (yet) reside on disk.
//
// Use dataUrl instead if you need to access the data; it will
// ensure the data is on disk and return a URL, barring an error.
- (nullable NSString *)dataPathIfOnDisk;
// Will return zero in the error case.
- (NSUInteger)dataLength;
// Returns YES on success.
- (BOOL)writeToPath:(NSString *)dstFilePath;
- (nullable NSString *)sourceFilename;
- (void)setSourceFilename:(NSString *_Nullable)sourceFilename;
// If called, this data source will try to delete its on-disk contents
// when it is deallocated.
- (void)setShouldDeleteOnDeallocation;
- (BOOL)isValidImage;
@end
#pragma mark -
@interface DataSourceValue : NSObject <DataSource>
@interface DataSourceValue : DataSource
+ (nullable id<DataSource>)dataSourceWithData:(NSData *)data fileExtension:(NSString *)fileExtension;
+ (nullable DataSource *)dataSourceWithData:(NSData *)data fileExtension:(NSString *)fileExtension;
+ (nullable id<DataSource>)dataSourceWithData:(NSData *)data utiType:(NSString *)utiType;
+ (nullable DataSource *)dataSourceWithData:(NSData *)data utiType:(NSString *)utiType;
+ (nullable id<DataSource>)dataSourceWithOversizeText:(NSString *_Nullable)text;
+ (nullable DataSource *)dataSourceWithOversizeText:(NSString *_Nullable)text;
+ (id<DataSource>)dataSourceWithSyncMessage:(NSData *)data;
+ (DataSource *)dataSourceWithSyncMessage:(NSData *)data;
+ (id<DataSource>)emptyDataSource;
+ (DataSource *)emptyDataSource;
@end
#pragma mark -
@interface DataSourcePath : NSObject <DataSource>
@interface DataSourcePath : DataSource
+ (nullable id<DataSource>)dataSourceWithURL:(NSURL *)fileUrl;
+ (nullable DataSource *)dataSourceWithURL:(NSURL *)fileUrl;
+ (nullable id<DataSource>)dataSourceWithFilePath:(NSString *)filePath;
+ (nullable DataSource *)dataSourceWithFilePath:(NSString *)filePath;
@end

View File

@ -4,9 +4,94 @@
#import "DataSource.h"
#import "MIMETypeUtil.h"
#import "NSData+Image.h"
NS_ASSUME_NONNULL_BEGIN
@interface DataSource ()
@property (nonatomic) BOOL shouldDeleteOnDeallocation;
// The file path for the data, if it already exists on disk.
//
// This method is safe to call as it will not do any expensive reads or writes.
//
// May return nil if the data does not (yet) reside on disk.
//
// Use dataUrl instead if you need to access the data; it will
// ensure the data is on disk and return a URL, barring an error.
- (nullable NSString *)dataPathIfOnDisk;
@end
#pragma mark -
@implementation DataSource
- (NSData *)data
{
OWSFail(@"%@ Missing required method: data", self.tag);
return nil;
}
- (nullable NSURL *)dataUrl
{
OWSFail(@"%@ Missing required method: dataUrl", self.tag);
return nil;
}
- (nullable NSString *)dataPathIfOnDisk
{
OWSFail(@"%@ Missing required method: dataPathIfOnDisk", self.tag);
return nil;
}
- (NSUInteger)dataLength
{
OWSFail(@"%@ Missing required method: dataLength", self.tag);
return 0;
}
- (BOOL)writeToPath:(NSString *)dstFilePath
{
OWSFail(@"%@ Missing required method: writeToPath:", self.tag);
return NO;
}
- (void)setShouldDeleteOnDeallocation
{
self.shouldDeleteOnDeallocation = YES;
}
- (BOOL)isValidImage
{
NSString *_Nullable dataPath = [self dataPathIfOnDisk];
if (dataPath) {
// if ows_isValidImage is given a file path, it will
// avoid loading most of the data into memory, which
// is considerably more performant, so try to do that.
return [NSData ows_isValidImageAtPath:dataPath];
}
NSData *data = [self data];
return [data ows_isValidImage];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
#pragma mark -
@interface DataSourceValue ()
@property (nonatomic) NSData *dataValue;
@ -16,15 +101,29 @@ NS_ASSUME_NONNULL_BEGIN
// This property is lazy-populated.
@property (nonatomic) NSString *cachedFilePath;
@property (nonatomic, nullable) NSString *sourceFilename;
@end
#pragma mark -
@implementation DataSourceValue
+ (nullable id<DataSource>)dataSourceWithData:(NSData *)data fileExtension:(NSString *)fileExtension
- (void)dealloc
{
if (self.shouldDeleteOnDeallocation) {
NSString *filePath = self.cachedFilePath;
if (filePath) {
dispatch_async(dispatch_get_main_queue(), ^{
NSError *error;
BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
if (!success || error) {
OWSCFail(@"DataSourceValue could not delete file: %@, %@", filePath, error);
}
});
}
}
}
+ (nullable DataSource *)dataSourceWithData:(NSData *)data fileExtension:(NSString *)fileExtension
{
OWSAssert(data);
@ -35,19 +134,19 @@ NS_ASSUME_NONNULL_BEGIN
DataSourceValue *instance = [DataSourceValue new];
instance.dataValue = data;
instance.fileExtension = fileExtension;
// Always try to clean up temp files created by this instance.
[instance setShouldDeleteOnDeallocation];
return instance;
}
+ (nullable id<DataSource>)dataSourceWithData:(NSData *)data utiType:(NSString *)utiType
+ (nullable DataSource *)dataSourceWithData:(NSData *)data utiType:(NSString *)utiType
{
NSString *fileExtension = [MIMETypeUtil fileExtensionForUTIType:utiType];
return [self dataSourceWithData:data fileExtension:fileExtension];
}
+ (nullable id<DataSource>)dataSourceWithOversizeText:(NSString *_Nullable)text
+ (nullable DataSource *)dataSourceWithOversizeText:(NSString *_Nullable)text
{
OWSAssert(text);
if (!text) {
return nil;
}
@ -56,12 +155,12 @@ NS_ASSUME_NONNULL_BEGIN
return [self dataSourceWithData:data fileExtension:kOversizeTextAttachmentFileExtension];
}
+ (id<DataSource>)dataSourceWithSyncMessage:(NSData *)data
+ (DataSource *)dataSourceWithSyncMessage:(NSData *)data
{
return [self dataSourceWithData:data fileExtension:kSyncMessageFileExtension];
}
+ (id<DataSource>)emptyDataSource
+ (DataSource *)emptyDataSource
{
return [self dataSourceWithData:[NSData new] fileExtension:@"bin"];
}
@ -89,7 +188,6 @@ NS_ASSUME_NONNULL_BEGIN
NSString *dirPath = NSTemporaryDirectory();
NSString *fileName = [[[NSUUID UUID] UUIDString] stringByAppendingPathExtension:self.fileExtension];
NSString *filePath = [dirPath stringByAppendingPathComponent:fileName];
DDLogError(@"%@ ---- writing data", self.tag);
if ([self writeToPath:filePath]) {
self.cachedFilePath = filePath;
} else {
@ -155,15 +253,29 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic) NSData *cachedData;
@property (nonatomic) NSNumber *cachedDataLength;
@property (nonatomic, nullable) NSString *sourceFilename;
@end
#pragma mark -
@implementation DataSourcePath
+ (nullable id<DataSource>)dataSourceWithURL:(NSURL *)fileUrl;
- (void)dealloc
{
if (self.shouldDeleteOnDeallocation) {
NSString *filePath = self.filePath;
if (filePath) {
dispatch_async(dispatch_get_main_queue(), ^{
NSError *error;
BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
if (!success || error) {
OWSCFail(@"DataSourcePath could not delete file: %@, %@", filePath, error);
}
});
}
}
}
+ (nullable DataSource *)dataSourceWithURL:(NSURL *)fileUrl;
{
OWSAssert(fileUrl);
@ -175,7 +287,7 @@ NS_ASSUME_NONNULL_BEGIN
return instance;
}
+ (nullable id<DataSource>)dataSourceWithFilePath:(NSString *)filePath;
+ (nullable DataSource *)dataSourceWithFilePath:(NSString *)filePath;
{
OWSAssert(filePath);
@ -238,7 +350,7 @@ NS_ASSUME_NONNULL_BEGIN
NSDictionary<NSFileAttributeKey, id> *_Nullable attributes =
[[NSFileManager defaultManager] attributesOfItemAtPath:self.filePath error:&error];
if (!attributes || error) {
OWSFail(@"%@ Could not read data length from disk: %@", self.tag, self.filePath);
OWSFail(@"%@ Could not read data length from disk: %@, %@", self.tag, self.filePath, error);
self.cachedDataLength = @(0);
} else {
uint64_t fileSize = [attributes fileSize];
@ -256,7 +368,7 @@ NS_ASSUME_NONNULL_BEGIN
NSError *error;
BOOL success = [[NSFileManager defaultManager] copyItemAtPath:self.filePath toPath:dstFilePath error:&error];
if (!success || error) {
OWSFail(@"%@ Could not write data from path: %@, to path: %@", self.tag, self.filePath, dstFilePath);
OWSFail(@"%@ Could not write data from path: %@, to path: %@, %@", self.tag, self.filePath, dstFilePath, error);
return NO;
} else {
return YES;

View File

@ -24,8 +24,8 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) {
OWSErrorCodeMessageSendDisabledDueToPreKeyUpdateFailures = 777405,
OWSErrorCodeMessageSendFailedToBlockList = 777406,
OWSErrorCodeMessageSendNoValidRecipients = 777407,
OWSErrorCodeContactsUpdaterRateLimit = 777407,
OWSErrorCodeCouldNotWriteAttachmentData = 777408,
OWSErrorCodeContactsUpdaterRateLimit = 777408,
OWSErrorCodeCouldNotWriteAttachmentData = 777409,
};
extern NSError *OWSErrorWithCodeDescription(OWSErrorCode code, NSString *description);