Merge branch 'charlesmchen/restoreWithAttachmentPointers'

pull/1/head
Matthew Chen 7 years ago
commit af61418b0e

@ -1 +1 @@
Subproject commit 95badd82b9f1c193b729617d00db0b71ead8eacf
Subproject commit 22f27f0bc4e1ed8a3a0a4c08272783bf6954e022

@ -86,6 +86,12 @@ public class ConversationMediaView: UIView {
configure(forError: .invalid)
return
}
guard attachmentPointer.pointerType == .incoming else {
// TODO: Show "restoring" indicator and possibly progress.
owsFailDebug("Attachment is restoring from backup.")
configure(forError: .missing)
return
}
guard let attachmentId = attachmentPointer.uniqueId else {
owsFailDebug("Attachment missing unique ID.")
configure(forError: .invalid)

@ -8,7 +8,6 @@ NS_ASSUME_NONNULL_BEGIN
@class ConversationViewCell;
@class OWSContactOffersInteraction;
@class OWSContactsManager;
@class TSAttachmentPointer;
@class TSAttachmentStream;
@class TSCall;
@class TSErrorMessage;

@ -835,6 +835,8 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
{
OWSAssertDebug(self.attachmentPointer);
// TODO: We probably want to do something different for attachments
// being restored from backup.
AttachmentPointerView *downloadView =
[[AttachmentPointerView alloc] initWithAttachmentPointer:self.attachmentPointer
isIncoming:self.isIncoming

@ -69,8 +69,7 @@ import SignalMessaging
self.pushRegistrationManager = PushRegistrationManager()
self.pushManager = PushManager()
self.sessionResetJobQueue = SessionResetJobQueue()
assert(SSKEnvironment.shared.primaryStorage != nil)
self.backup = OWSBackup(primaryStorage: SSKEnvironment.shared.primaryStorage)
self.backup = OWSBackup()
super.init()

@ -21,14 +21,12 @@ typedef NS_ENUM(NSUInteger, OWSBackupState) {
};
@class OWSBackupIO;
@class OWSPrimaryStorage;
@class TSAttachmentStream;
@class TSAttachmentPointer;
@class TSThread;
@interface OWSBackup : NSObject
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
+ (instancetype)sharedManager NS_SWIFT_NAME(shared());
@ -79,7 +77,7 @@ typedef NS_ENUM(NSUInteger, OWSBackupState) {
- (NSArray<NSString *> *)attachmentIdsForLazyRestore;
- (void)lazyRestoreAttachment:(TSAttachmentStream *)attachment
- (void)lazyRestoreAttachment:(TSAttachmentPointer *)attachment
backupIO:(OWSBackupIO *)backupIO
completion:(OWSBackupBoolBlock)completion;

@ -51,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN
return AppEnvironment.shared.backup;
}
- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage
- (instancetype)init
{
self = [super init];
@ -59,10 +59,6 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
OWSAssertDebug(primaryStorage);
_dbConnection = primaryStorage.newDatabaseConnection;
_backupExportState = OWSBackupState_Idle;
_backupImportState = OWSBackupState_Idle;
@ -101,6 +97,25 @@ NS_ASSUME_NONNULL_BEGIN
});
}
- (YapDatabaseConnection *)dbConnection
{
@synchronized(self) {
if (!_dbConnection) {
_dbConnection = self.primaryStorage.newDatabaseConnection;
}
return _dbConnection;
}
}
#pragma mark - Dependencies
- (OWSPrimaryStorage *)primaryStorage
{
OWSAssertDebug(SSKEnvironment.shared.primaryStorage);
return SSKEnvironment.shared.primaryStorage;
}
#pragma mark - Backup Export
- (void)tryToExportBackup
@ -121,8 +136,7 @@ NS_ASSUME_NONNULL_BEGIN
_backupExportState = OWSBackupState_InProgress;
self.backupExportJob =
[[OWSBackupExportJob alloc] initWithDelegate:self primaryStorage:[OWSPrimaryStorage sharedManager]];
self.backupExportJob = [[OWSBackupExportJob alloc] initWithDelegate:self primaryStorage:self.primaryStorage];
[self.backupExportJob startAsync];
[self postDidChangeNotification];
@ -254,8 +268,7 @@ NS_ASSUME_NONNULL_BEGIN
[self.backupExportJob cancel];
self.backupExportJob = nil;
} else if (self.shouldHaveBackupExport && !self.backupExportJob) {
self.backupExportJob =
[[OWSBackupExportJob alloc] initWithDelegate:self primaryStorage:[OWSPrimaryStorage sharedManager]];
self.backupExportJob = [[OWSBackupExportJob alloc] initWithDelegate:self primaryStorage:self.primaryStorage];
[self.backupExportJob startAsync];
}
@ -321,8 +334,7 @@ NS_ASSUME_NONNULL_BEGIN
_backupImportState = OWSBackupState_InProgress;
self.backupImportJob =
[[OWSBackupImportJob alloc] initWithDelegate:self primaryStorage:[OWSPrimaryStorage sharedManager]];
self.backupImportJob = [[OWSBackupImportJob alloc] initWithDelegate:self primaryStorage:self.primaryStorage];
[self.backupImportJob startAsync];
[self postDidChangeNotification];
@ -500,18 +512,18 @@ NS_ASSUME_NONNULL_BEGIN
[ext enumerateKeysAndObjectsInGroup:TSLazyRestoreAttachmentsGroup
usingBlock:^(
NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) {
if (![object isKindOfClass:[TSAttachmentStream class]]) {
if (![object isKindOfClass:[TSAttachmentPointer class]]) {
OWSFailDebug(
@"Unexpected object: %@ in collection:%@", [object class], collection);
return;
}
TSAttachmentStream *attachmentStream = object;
if (!attachmentStream.lazyRestoreFragment) {
TSAttachmentPointer *attachmentPointer = object;
if (!attachmentPointer.lazyRestoreFragment) {
OWSFailDebug(
@"Invalid object: %@ in collection:%@", [object class], collection);
return;
}
[recordNames addObject:attachmentStream.lazyRestoreFragment.recordName];
[recordNames addObject:attachmentPointer.lazyRestoreFragment.recordName];
}];
}];
return recordNames;
@ -535,7 +547,7 @@ NS_ASSUME_NONNULL_BEGIN
return attachmentIds;
}
- (void)lazyRestoreAttachment:(TSAttachmentStream *)attachment
- (void)lazyRestoreAttachment:(TSAttachmentPointer *)attachment
backupIO:(OWSBackupIO *)backupIO
completion:(OWSBackupBoolBlock)completion
{
@ -543,16 +555,6 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssertDebug(backupIO);
OWSAssertDebug(completion);
NSString *_Nullable attachmentFilePath = [attachment originalFilePath];
if (attachmentFilePath.length < 1) {
OWSLogError(@"Attachment has invalid file path.");
return completion(NO);
}
if ([NSFileManager.defaultManager fileExistsAtPath:attachmentFilePath]) {
OWSLogError(@"Attachment already has file.");
return completion(NO);
}
OWSBackupFragment *_Nullable lazyRestoreFragment = attachment.lazyRestoreFragment;
if (!lazyRestoreFragment) {
OWSLogWarn(@"Attachment missing lazy restore metadata.");
@ -587,13 +589,13 @@ NS_ASSUME_NONNULL_BEGIN
}];
}
- (void)lazyRestoreAttachment:(TSAttachmentStream *)attachment
- (void)lazyRestoreAttachment:(TSAttachmentPointer *)attachmentPointer
backupIO:(OWSBackupIO *)backupIO
encryptedFilePath:(NSString *)encryptedFilePath
encryptionKey:(NSData *)encryptionKey
completion:(OWSBackupBoolBlock)completion
{
OWSAssertDebug(attachment);
OWSAssertDebug(attachmentPointer);
OWSAssertDebug(backupIO);
OWSAssertDebug(encryptedFilePath.length > 0);
OWSAssertDebug(encryptionKey.length > 0);
@ -614,7 +616,9 @@ NS_ASSUME_NONNULL_BEGIN
}
}
NSString *_Nullable attachmentFilePath = [attachment originalFilePath];
TSAttachmentStream *stream = [[TSAttachmentStream alloc] initWithPointer:attachmentPointer];
NSString *attachmentFilePath = stream.originalFilePath;
if (attachmentFilePath.length < 1) {
OWSLogError(@"Attachment has invalid file path.");
return completion(NO);
@ -626,6 +630,11 @@ NS_ASSUME_NONNULL_BEGIN
return completion(NO);
}
if (![OWSFileSystem deleteFileIfExists:attachmentFilePath]) {
OWSFailDebug(@"Couldn't delete existing file at attachment path.");
return completion(NO);
}
NSError *error;
BOOL success =
[NSFileManager.defaultManager moveItemAtPath:decryptedFilePath toPath:attachmentFilePath error:&error];
@ -634,7 +643,10 @@ NS_ASSUME_NONNULL_BEGIN
return completion(NO);
}
[attachment updateWithLazyRestoreComplete];
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
// This should overwrite the attachment pointer with an attachment stream.
[stream saveWithTransaction:transaction];
}];
completion(YES);
}

@ -507,6 +507,17 @@ NS_ASSUME_NONNULL_BEGIN
TSYapDatabaseObject *entity = object;
count++;
if ([entity isKindOfClass:[TSAttachmentStream class]]) {
// Convert attachment streams to pointers,
// since we'll need to restore them.
TSAttachmentStream *attachmentStream
= (TSAttachmentStream *)entity;
TSAttachmentPointer *attachmentPointer =
[[TSAttachmentPointer alloc]
initForRestoreWithAttachmentStream:attachmentStream];
entity = attachmentPointer;
}
if (![exportStream writeObject:entity entityType:entityType]) {
*stop = YES;
aborted = YES;
@ -536,7 +547,10 @@ NS_ASSUME_NONNULL_BEGIN
[TSAttachment class],
^(id object) {
if (![object isKindOfClass:[TSAttachmentStream class]]) {
return NO;
// No need to backup the contents (e.g. the file on disk)
// of attachment pointers.
// After a restore, users will be able "tap to retry".
return YES;
}
TSAttachmentStream *attachmentStream = object;
NSString *_Nullable filePath = attachmentStream.originalFilePath;

@ -281,13 +281,18 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe
// Attachment-related errors are recoverable and can be ignored.
continue;
}
TSAttachmentStream *_Nullable attachment =
[TSAttachmentStream fetchObjectWithUniqueID:item.attachmentId transaction:transaction];
TSAttachmentPointer *_Nullable attachment =
[TSAttachmentPointer fetchObjectWithUniqueID:item.attachmentId transaction:transaction];
if (!attachment) {
OWSLogError(@"attachment to restore could not be found.");
// Attachment-related errors are recoverable and can be ignored.
continue;
}
if (![attachment isKindOfClass:[TSAttachmentPointer class]]) {
OWSFailDebug(@"attachment has unexpected type: %@.", attachment.class);
// Attachment-related errors are recoverable and can be ignored.
continue;
}
[attachment markForLazyRestoreWithFragment:item transaction:transaction];
count++;
[self updateProgressWithDescription:NSLocalizedString(@"BACKUP_IMPORT_PHASE_RESTORING_FILES",

@ -68,7 +68,7 @@ public class OWSBackupLazyRestoreJob: NSObject {
return
}
attachmentIdsCopy.removeLast()
guard let attachment = TSAttachmentStream.fetch(uniqueId: attachmentId) else {
guard let attachmentPointer = TSAttachment.fetch(uniqueId: attachmentId) as? TSAttachmentPointer else {
Logger.warn("could not load attachment.")
// Not necessarily an error.
// The attachment might have been deleted since the job began.
@ -76,7 +76,7 @@ public class OWSBackupLazyRestoreJob: NSObject {
tryToRestoreNextAttachment(attachmentIds: attachmentIds, backupIO: backupIO)
return
}
OWSBackup.shared().lazyRestoreAttachment(attachment,
OWSBackup.shared().lazyRestoreAttachment(attachmentPointer,
backupIO: backupIO,
completion: { (success) in
if success {

@ -147,6 +147,10 @@ typedef void (^AttachmentDownloadFailure)(NSError *error);
[attachmentStreams addObject:attachmentStream];
} else if ([attachment isKindOfClass:[TSAttachmentPointer class]]) {
TSAttachmentPointer *attachmentPointer = (TSAttachmentPointer *)attachment;
if (attachmentPointer.pointerType != TSAttachmentPointerTypeIncoming) {
OWSLogInfo(@"Ignoring restoring attachment.");
continue;
}
[attachmentPointers addObject:attachmentPointer];
} else {
OWSFailDebug(@"Unexpected attachment type: %@", attachment.class);

@ -1,42 +0,0 @@
//
// 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 OWSPrimaryStorage;
@class SSKProtoAttachmentPointer;
@class TSAttachmentPointer;
@class TSAttachmentStream;
@class TSMessage;
@class TSNetworkManager;
@class TSThread;
@class YapDatabaseReadWriteTransaction;
/**
* Given incoming attachment protos, determines which we support.
* It can download those that we support and notifies threads when it receives unsupported attachments.
*/
@interface OWSAttachmentsProcessor : NSObject
@property (nonatomic, readonly) NSArray<TSAttachmentPointer *> *attachmentPointers;
- (instancetype)init NS_UNAVAILABLE;
/*
* Retry fetching failed attachment download
*/
- (instancetype)initWithAttachmentPointers:(NSArray<TSAttachmentPointer *> *)attachmentPointers
NS_DESIGNATED_INITIALIZER;
- (void)fetchAttachmentsForMessage:(nullable TSMessage *)message
transaction:(YapDatabaseReadWriteTransaction *)transaction
success:(void (^)(NSArray<TSAttachmentStream *> *attachmentStreams))successHandler
failure:(void (^)(NSError *error))failureHandler;
@end
NS_ASSUME_NONNULL_END

@ -6,6 +6,7 @@
NS_ASSUME_NONNULL_BEGIN
@class TSAttachmentPointer;
@class TSMessage;
typedef NS_ENUM(NSUInteger, TSAttachmentType) {
@ -27,7 +28,7 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) {
// TSAttachmentPointer, which can be distinguished by the isDownloaded
// property.
@property (atomic, readwrite) UInt64 serverId;
@property (atomic, readwrite) NSData *encryptionKey;
@property (atomic, readwrite, nullable) NSData *encryptionKey;
@property (nonatomic, readonly) NSString *contentType;
@property (atomic, readwrite) BOOL isDownloaded;
@property (nonatomic) TSAttachmentType attachmentType;
@ -62,6 +63,14 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) {
caption:(nullable NSString *)caption
albumMessageId:(nullable NSString *)albumMessageId;
// This constructor is used for new instances of TSAttachmentPointer,
// i.e. undownloaded restoring attachments.
- (instancetype)initForRestoreWithUniqueId:(NSString *)uniqueId
contentType:(NSString *)contentType
sourceFilename:(nullable NSString *)sourceFilename
caption:(nullable NSString *)caption
albumMessageId:(nullable NSString *)albumMessageId;
// This constructor is used for new instances of TSAttachmentStream
// that represent new, un-uploaded outgoing attachments.
- (instancetype)initWithContentType:(NSString *)contentType
@ -72,7 +81,7 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) {
// This constructor is used for new instances of TSAttachmentStream
// that represent downloaded incoming attachments.
- (instancetype)initWithPointer:(TSAttachment *)pointer;
- (instancetype)initWithPointer:(TSAttachmentPointer *)pointer;
- (nullable instancetype)initWithCoder:(NSCoder *)coder;

@ -4,6 +4,7 @@
#import "TSAttachment.h"
#import "MIMETypeUtil.h"
#import "TSAttachmentPointer.h"
#import "TSMessage.h"
#import <SignalCoreKit/NSString+SSK.h>
#import <SignalCoreKit/iOSVersions.h>
@ -65,6 +66,40 @@ NSUInteger const TSAttachmentSchemaVersion = 4;
return self;
}
// This constructor is used for new instances of TSAttachmentPointer,
// i.e. undownloaded restoring attachments.
- (instancetype)initForRestoreWithUniqueId:(NSString *)uniqueId
contentType:(NSString *)contentType
sourceFilename:(nullable NSString *)sourceFilename
caption:(nullable NSString *)caption
albumMessageId:(nullable NSString *)albumMessageId
{
OWSAssertDebug(uniqueId.length > 0);
if (contentType.length < 1) {
OWSLogWarn(@"incoming attachment has invalid content type");
contentType = OWSMimeTypeApplicationOctetStream;
}
OWSAssertDebug(contentType.length > 0);
// If saved, this AttachmentPointer would replace the AttachmentStream in the attachments collection.
// However we only use this AttachmentPointer should only be used during the export process so it
// won't be saved until we restore the backup (when there will be no AttachmentStream to replace).
self = [super initWithUniqueId:uniqueId];
if (!self) {
return self;
}
_contentType = contentType;
_sourceFilename = sourceFilename;
_caption = caption;
_albumMessageId = albumMessageId;
_attachmentSchemaVersion = TSAttachmentSchemaVersion;
return self;
}
// This constructor is used for new instances of TSAttachmentStream
// that represent new, un-uploaded outgoing attachments.
- (instancetype)initWithContentType:(NSString *)contentType
@ -99,14 +134,16 @@ NSUInteger const TSAttachmentSchemaVersion = 4;
// This constructor is used for new instances of TSAttachmentStream
// that represent downloaded incoming attachments.
- (instancetype)initWithPointer:(TSAttachment *)pointer
- (instancetype)initWithPointer:(TSAttachmentPointer *)pointer
{
if (!pointer.lazyRestoreFragment) {
OWSAssertDebug(pointer.serverId > 0);
OWSAssertDebug(pointer.encryptionKey.length > 0);
if (pointer.byteCount <= 0) {
// This will fail with legacy iOS clients which don't upload attachment size.
OWSLogWarn(@"Missing pointer.byteCount for attachment with serverId: %lld", pointer.serverId);
}
}
OWSAssertDebug(pointer.contentType.length > 0);
// Once saved, this AttachmentStream will replace the AttachmentPointer in the attachments collection.

@ -6,9 +6,17 @@
NS_ASSUME_NONNULL_BEGIN
@class OWSBackupFragment;
@class SSKProtoAttachmentPointer;
@class TSAttachmentStream;
@class TSMessage;
typedef NS_ENUM(NSUInteger, TSAttachmentPointerType) {
TSAttachmentPointerTypeUnknown = 0,
TSAttachmentPointerTypeIncoming = 1,
TSAttachmentPointerTypeRestoring = 2,
};
typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) {
TSAttachmentPointerStateEnqueued = 0,
TSAttachmentPointerStateDownloading = 1,
@ -20,6 +28,17 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) {
*/
@interface TSAttachmentPointer : TSAttachment
@property (nonatomic) TSAttachmentPointerType pointerType;
@property (atomic) TSAttachmentPointerState state;
@property (nullable, atomic) NSString *mostRecentFailureLocalizedText;
// Though now required, `digest` may be null for pre-existing records or from
// messages received from other clients
@property (nullable, nonatomic, readonly) NSData *digest;
// Non-nil for attachments which need "lazy backup restore."
- (nullable OWSBackupFragment *)lazyRestoreFragment;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithServerId:(UInt64)serverId
@ -32,6 +51,8 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) {
albumMessageId:(nullable NSString *)albumMessageId
attachmentType:(TSAttachmentType)attachmentType NS_DESIGNATED_INITIALIZER;
- (instancetype)initForRestoreWithAttachmentStream:(TSAttachmentStream *)attachmentStream NS_DESIGNATED_INITIALIZER;
+ (nullable TSAttachmentPointer *)attachmentPointerFromProto:(SSKProtoAttachmentPointer *)attachmentProto
albumMessage:(nullable TSMessage *)message;
@ -39,12 +60,11 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) {
(NSArray<SSKProtoAttachmentPointer *> *)attachmentProtos
albumMessage:(TSMessage *)message;
@property (atomic) TSAttachmentPointerState state;
@property (nullable, atomic) NSString *mostRecentFailureLocalizedText;
#pragma mark - Update With... Methods
// Though now required, `digest` may be null for pre-existing records or from
// messages received from other clients
@property (nullable, nonatomic, readonly) NSData *digest;
// Marks attachment as needing "lazy backup restore."
- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment
transaction:(YapDatabaseReadWriteTransaction *)transaction;
@end

@ -3,11 +3,23 @@
//
#import "TSAttachmentPointer.h"
#import "OWSBackupFragment.h"
#import "TSAttachmentStream.h"
#import <SignalServiceKit/MimeTypeUtil.h>
#import <SignalServiceKit/SignalServiceKit-Swift.h>
#import <YapDatabase/YapDatabase.h>
NS_ASSUME_NONNULL_BEGIN
@interface TSAttachmentPointer ()
// Optional property. Only set for attachments which need "lazy backup restore."
@property (nonatomic, nullable) NSString *lazyRestoreFragmentId;
@end
#pragma mark -
@implementation TSAttachmentPointer
- (nullable instancetype)initWithCoder:(NSCoder *)coder
@ -24,6 +36,10 @@ NS_ASSUME_NONNULL_BEGIN
_state = TSAttachmentPointerStateFailed;
}
if (_pointerType == TSAttachmentPointerTypeUnknown) {
_pointerType = TSAttachmentPointerTypeIncoming;
}
return self;
}
@ -51,6 +67,27 @@ NS_ASSUME_NONNULL_BEGIN
_digest = digest;
_state = TSAttachmentPointerStateEnqueued;
self.attachmentType = attachmentType;
_pointerType = TSAttachmentPointerTypeIncoming;
return self;
}
- (instancetype)initForRestoreWithAttachmentStream:(TSAttachmentStream *)attachmentStream
{
OWSAssertDebug(attachmentStream);
self = [super initForRestoreWithUniqueId:attachmentStream.uniqueId
contentType:attachmentStream.contentType
sourceFilename:attachmentStream.sourceFilename
caption:attachmentStream.caption
albumMessageId:attachmentStream.albumMessageId];
if (!self) {
return self;
}
_state = TSAttachmentPointerStateEnqueued;
self.attachmentType = attachmentStream.attachmentType;
_pointerType = TSAttachmentPointerTypeRestoring;
return self;
}
@ -141,6 +178,34 @@ NS_ASSUME_NONNULL_BEGIN
}
}
- (nullable OWSBackupFragment *)lazyRestoreFragment
{
if (!self.lazyRestoreFragmentId) {
return nil;
}
return [OWSBackupFragment fetchObjectWithUniqueID:self.lazyRestoreFragmentId];
}
#pragma mark - Update With... Methods
- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssertDebug(lazyRestoreFragment);
OWSAssertDebug(transaction);
if (!lazyRestoreFragment.uniqueId) {
// If metadata hasn't been saved yet, save now.
[lazyRestoreFragment saveWithTransaction:transaction];
OWSAssertDebug(lazyRestoreFragment.uniqueId);
}
[self applyChangeToSelfAndLatestCopy:transaction
changeBlock:^(TSAttachmentPointer *attachment) {
[attachment setLazyRestoreFragmentId:lazyRestoreFragment.uniqueId];
}];
}
@end
NS_ASSUME_NONNULL_END

@ -3,7 +3,6 @@
//
#import "DataSource.h"
#import "OWSBackupFragment.h"
#import "TSAttachment.h"
#if TARGET_OS_IPHONE
@ -70,9 +69,6 @@ typedef void (^OWSThumbnailFailure)(void);
+ (nullable NSError *)migrateToSharedData;
// Non-nil for attachments which need "lazy backup restore."
- (nullable OWSBackupFragment *)lazyRestoreFragment;
#pragma mark - Thumbnails
// On cache hit, the thumbnail will be returned synchronously and completion will never be invoked.
@ -99,12 +95,6 @@ typedef void (^OWSThumbnailFailure)(void);
#pragma mark - Update With... Methods
// Marks attachment as needing "lazy backup restore."
- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment
transaction:(YapDatabaseReadWriteTransaction *)transaction;
// Marks attachment as having completed "lazy backup restore."
- (void)updateWithLazyRestoreComplete;
- (nullable TSAttachmentStream *)cloneAsThumbnail;
#pragma mark - Protobuf

@ -39,9 +39,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail);
// This property should only be accessed on the main thread.
@property (nullable, nonatomic) NSNumber *cachedAudioDurationSeconds;
// Optional property. Only set for attachments which need "lazy backup restore."
@property (nonatomic, nullable) NSString *lazyRestoreFragmentId;
@property (atomic, nullable) NSNumber *isValidImageCached;
@property (atomic, nullable) NSNumber *isValidVideoCached;
@ -358,10 +355,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail);
{
OWSAssertDebug(self.isImage || self.isAnimated);
if (self.lazyRestoreFragment) {
return NO;
}
@synchronized(self) {
if (!self.isValidImageCached) {
self.isValidImageCached =
@ -375,10 +368,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail);
{
OWSAssertDebug(self.isVideo);
if (self.lazyRestoreFragment) {
return NO;
}
@synchronized(self) {
if (!self.isValidVideoCached) {
self.isValidVideoCached = @([OWSMediaUtils isValidVideoWithPath:self.originalFilePath]);
@ -629,14 +618,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail);
return audioDurationSeconds;
}
- (nullable OWSBackupFragment *)lazyRestoreFragment
{
if (!self.lazyRestoreFragmentId) {
return nil;
}
return [OWSBackupFragment fetchObjectWithUniqueID:self.lazyRestoreFragmentId];
}
#pragma mark - Thumbnails
- (nullable UIImage *)thumbnailImageWithSizeHint:(CGSize)sizeHint
@ -819,34 +800,6 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail);
#pragma mark - Update With... Methods
- (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssertDebug(lazyRestoreFragment);
OWSAssertDebug(transaction);
if (!lazyRestoreFragment.uniqueId) {
// If metadata hasn't been saved yet, save now.
[lazyRestoreFragment saveWithTransaction:transaction];
OWSAssertDebug(lazyRestoreFragment.uniqueId);
}
[self applyChangeToSelfAndLatestCopy:transaction
changeBlock:^(TSAttachmentStream *attachment) {
[attachment setLazyRestoreFragmentId:lazyRestoreFragment.uniqueId];
}];
}
- (void)updateWithLazyRestoreComplete
{
[self.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[self applyChangeToSelfAndLatestCopy:transaction
changeBlock:^(TSAttachmentStream *attachment) {
[attachment setLazyRestoreFragmentId:nil];
}];
}];
}
- (nullable TSAttachmentStream *)cloneAsThumbnail
{
NSData *_Nullable thumbnailData = self.thumbnailDataSmallSync;

@ -6,7 +6,7 @@
#import "OWSDevice.h"
#import "OWSReadTracking.h"
#import "TSAttachment.h"
#import "TSAttachmentStream.h"
#import "TSAttachmentPointer.h"
#import "TSIncomingMessage.h"
#import "TSInvalidIdentityKeyErrorMessage.h"
#import "TSOutgoingMessage.h"
@ -369,19 +369,19 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object class], collection);
return nil;
}
if (![object isKindOfClass:[TSAttachmentStream class]]) {
if (![object isKindOfClass:[TSAttachmentPointer class]]) {
return nil;
}
TSAttachmentStream *attachmentStream = (TSAttachmentStream *)object;
if (attachmentStream.lazyRestoreFragment) {
TSAttachmentPointer *attachmentPointer = (TSAttachmentPointer *)object;
if (attachmentPointer.lazyRestoreFragment) {
return TSLazyRestoreAttachmentsGroup;
} else {
return nil;
}
}];
YapDatabaseViewSorting *viewSorting = [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(
YapDatabaseReadTransaction *transaction,
YapDatabaseViewSorting *viewSorting =
[YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction,
NSString *group,
NSString *collection1,
NSString *key1,
@ -389,19 +389,19 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
NSString *collection2,
NSString *key2,
id object2) {
if (![object1 isKindOfClass:[TSAttachmentStream class]]) {
if (![object1 isKindOfClass:[TSAttachmentPointer class]]) {
OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object1 class], collection1);
return NSOrderedSame;
}
if (![object2 isKindOfClass:[TSAttachmentStream class]]) {
if (![object2 isKindOfClass:[TSAttachmentPointer class]]) {
OWSFailDebug(@"Unexpected entity %@ in collection: %@", [object2 class], collection2);
return NSOrderedSame;
}
// Specific ordering doesn't matter; we just need a stable ordering.
TSAttachmentStream *attachmentStream1 = (TSAttachmentStream *)object1;
TSAttachmentStream *attachmentStream2 = (TSAttachmentStream *)object2;
return [attachmentStream2.creationTimestamp compare:attachmentStream1.creationTimestamp];
TSAttachmentPointer *attachmentPointer1 = (TSAttachmentPointer *)object1;
TSAttachmentPointer *attachmentPointer2 = (TSAttachmentPointer *)object2;
return [attachmentPointer1.uniqueId compare:attachmentPointer2.uniqueId];
}];
YapDatabaseViewOptions *options = [YapDatabaseViewOptions new];
@ -409,7 +409,7 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
options.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSAttachment collection]]];
YapDatabaseView *view =
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"3" options:options];
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"4" options:options];
[storage asyncRegisterExtension:view withName:TSLazyRestoreAttachmentsDatabaseViewExtensionName];
}

Loading…
Cancel
Save