diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 66dd750b27..6855f3cc2a 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -369,7 +369,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; return NO; } - id _Nullable dataSource = [DataSourcePath dataSourceWithURL:url]; + DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithURL:url]; if (!dataSource) { DDLogError(@"Application opened with URL with unloadable content: %@", url); [OWSAlerts showAlertWithTitle: diff --git a/Signal/src/Models/SignalAttachment.swift b/Signal/src/Models/SignalAttachment.swift index 7d6417ce75..2905ada67a 100644 --- a/Signal/src/Models/SignalAttachment.swift +++ b/Signal/src/Models/SignalAttachment.swift @@ -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) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index eff4e93ae5..c3c18607b0 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -1681,7 +1681,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) { BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; TSOutgoingMessage *message; if ([text lengthOfBytesUsingEncoding:NSUTF8StringEncoding] >= kOversizeTextMessageSizeThreshold) { - id _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 _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 _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 _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 _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 _Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"]; + DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"]; [self.messageSender sendAttachmentData:dataSource contentType:OWSMimeTypeImagePng sourceFilename:nil diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index 5adf6d2365..9141355ebb 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -325,7 +325,7 @@ NS_ASSUME_NONNULL_BEGIN OWSMessageSender *messageSender = [Environment getCurrent].messageSender; NSString *filename = [filePath lastPathComponent]; NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:filename.pathExtension]; - id _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 _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 _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]; diff --git a/Signal/src/ViewControllers/NewGroupViewController.m b/Signal/src/ViewControllers/NewGroupViewController.m index 96e951ddf9..a33520e369 100644 --- a/Signal/src/ViewControllers/NewGroupViewController.m +++ b/Signal/src/ViewControllers/NewGroupViewController.m @@ -497,7 +497,7 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68; if (model.groupImage) { NSData *data = UIImagePNGRepresentation(model.groupImage); - id _Nullable dataSource = + DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"]; [self.messageSender sendAttachmentData:dataSource contentType:OWSMimeTypeImagePng diff --git a/Signal/src/util/OWSContactsSyncing.m b/Signal/src/util/OWSContactsSyncing.m index 4d12b0b8d5..83c7e619b2 100644 --- a/Signal/src/util/OWSContactsSyncing.m +++ b/Signal/src/util/OWSContactsSyncing.m @@ -113,7 +113,7 @@ NSString *const kTSStorageManagerOWSContactsSyncingLastMessageKey = self.isRequestInFlight = YES; - id dataSource = + DataSource *dataSource = [DataSourceValue dataSourceWithSyncMessage:[syncContactsMessage buildPlainTextAttachmentData]]; [self.messageSender sendTemporaryAttachmentData:dataSource contentType:OWSMimeTypeApplicationOctetStream diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h index 21e41ee02b..1905f338a9 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h @@ -44,7 +44,7 @@ NS_ASSUME_NONNULL_BEGIN - (nullable NSData *)readDataFromFileWithError:(NSError **)error; - (BOOL)writeData:(NSData *)data error:(NSError **)error; -- (BOOL)writeDataSource:(id)dataSource; +- (BOOL)writeDataSource:(DataSource *)dataSource; + (void)deleteAttachments; + (NSString *)attachmentsFolder; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m index 5948715157..536812c0ed 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m @@ -158,7 +158,7 @@ NS_ASSUME_NONNULL_BEGIN return [data writeToFile:filePath options:0 error:error]; } -- (BOOL)writeDataSource:(id)dataSource +- (BOOL)writeDataSource:(DataSource *)dataSource { OWSAssert(dataSource); diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.h b/SignalServiceKit/src/Messages/OWSMessageSender.h index ae41baa9ab..0739cf2091 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.h +++ b/SignalServiceKit/src/Messages/OWSMessageSender.h @@ -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 +- (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 +- (void)sendTemporaryAttachmentData:(DataSource *)dataSource contentType:(NSString *)contentType inMessage:(TSOutgoingMessage *)outgoingMessage success:(void (^)())successHandler diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index f0547cf037..5175683baa 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -486,7 +486,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; failure:failureHandler]; } -- (void)sendTemporaryAttachmentData:(id)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 +- (void)sendAttachmentData:(DataSource *)dataSource contentType:(NSString *)contentType sourceFilename:(nullable NSString *)sourceFilename inMessage:(TSOutgoingMessage *)message diff --git a/SignalServiceKit/src/Messages/TSMessagesManager.m b/SignalServiceKit/src/Messages/TSMessagesManager.m index f5f264e16c..4be17b91a0 100644 --- a/SignalServiceKit/src/Messages/TSMessagesManager.m +++ b/SignalServiceKit/src/Messages/TSMessagesManager.m @@ -743,7 +743,7 @@ NS_ASSUME_NONNULL_BEGIN [[OWSSyncContactsMessage alloc] initWithSignalAccounts:self.contactsManager.signalAccounts identityManager:self.identityManager profileManager:self.profileManager]; - id 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 = [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 _Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"]; + DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithData:data fileExtension:@"png"]; [self.messageSender sendAttachmentData:dataSource contentType:OWSMimeTypeImagePng sourceFilename:nil diff --git a/SignalServiceKit/src/Util/DataSource.h b/SignalServiceKit/src/Util/DataSource.h index 0d467231f2..ee5702d149 100755 --- a/SignalServiceKit/src/Util/DataSource.h +++ b/SignalServiceKit/src/Util/DataSource.h @@ -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 +@interface DataSourceValue : DataSource -+ (nullable id)dataSourceWithData:(NSData *)data fileExtension:(NSString *)fileExtension; ++ (nullable DataSource *)dataSourceWithData:(NSData *)data fileExtension:(NSString *)fileExtension; -+ (nullable id)dataSourceWithData:(NSData *)data utiType:(NSString *)utiType; ++ (nullable DataSource *)dataSourceWithData:(NSData *)data utiType:(NSString *)utiType; -+ (nullable id)dataSourceWithOversizeText:(NSString *_Nullable)text; ++ (nullable DataSource *)dataSourceWithOversizeText:(NSString *_Nullable)text; -+ (id)dataSourceWithSyncMessage:(NSData *)data; ++ (DataSource *)dataSourceWithSyncMessage:(NSData *)data; -+ (id)emptyDataSource; ++ (DataSource *)emptyDataSource; @end #pragma mark - -@interface DataSourcePath : NSObject +@interface DataSourcePath : DataSource -+ (nullable id)dataSourceWithURL:(NSURL *)fileUrl; ++ (nullable DataSource *)dataSourceWithURL:(NSURL *)fileUrl; -+ (nullable id)dataSourceWithFilePath:(NSString *)filePath; ++ (nullable DataSource *)dataSourceWithFilePath:(NSString *)filePath; @end diff --git a/SignalServiceKit/src/Util/DataSource.m b/SignalServiceKit/src/Util/DataSource.m index 9ae66528a1..6649e8461f 100755 --- a/SignalServiceKit/src/Util/DataSource.m +++ b/SignalServiceKit/src/Util/DataSource.m @@ -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)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)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)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)dataSourceWithSyncMessage:(NSData *)data ++ (DataSource *)dataSourceWithSyncMessage:(NSData *)data { return [self dataSourceWithData:data fileExtension:kSyncMessageFileExtension]; } -+ (id)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)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)dataSourceWithFilePath:(NSString *)filePath; ++ (nullable DataSource *)dataSourceWithFilePath:(NSString *)filePath; { OWSAssert(filePath); @@ -238,7 +350,7 @@ NS_ASSUME_NONNULL_BEGIN NSDictionary *_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; diff --git a/SignalServiceKit/src/Util/OWSError.h b/SignalServiceKit/src/Util/OWSError.h index 14d515cd71..3d70ba7b9d 100644 --- a/SignalServiceKit/src/Util/OWSError.h +++ b/SignalServiceKit/src/Util/OWSError.h @@ -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);