session-ios/Signal/src/ViewControllers/DebugUI/DebugUIBackup.m

259 lines
10 KiB
Objective-C

//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "DebugUIBackup.h"
#import "OWSBackup.h"
#import "OWSTableViewController.h"
#import "Session-Swift.h"
#import <PromiseKit/AnyPromise.h>
#import <SessionCoreKit/Randomness.h>
@import CloudKit;
NS_ASSUME_NONNULL_BEGIN
@implementation DebugUIBackup
#pragma mark - Dependencies
+ (TSAccountManager *)tsAccountManager
{
OWSAssertDebug(SSKEnvironment.shared.tsAccountManager);
return SSKEnvironment.shared.tsAccountManager;
}
+ (OWSBackup *)backup
{
OWSAssertDebug(AppEnvironment.shared.backup);
return AppEnvironment.shared.backup;
}
#pragma mark - Factory Methods
- (NSString *)name
{
return @"Backup";
}
- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread
{
NSMutableArray<OWSTableItem *> *items = [NSMutableArray new];
[items addObject:[OWSTableItem itemWithTitle:@"Backup test file to CloudKit"
actionBlock:^{
[DebugUIBackup backupTestFile];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Check for CloudKit backup"
actionBlock:^{
[DebugUIBackup checkForBackup];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Log CloudKit backup records"
actionBlock:^{
[DebugUIBackup logBackupRecords];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Log CloudKit backup manifests"
actionBlock:^{
[DebugUIBackup logBackupManifests];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Restore CloudKit backup"
actionBlock:^{
[DebugUIBackup tryToImportBackup];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Log Database Size Stats"
actionBlock:^{
[DebugUIBackup logDatabaseSizeStats];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Clear All CloudKit Records"
actionBlock:^{
[DebugUIBackup clearAllCloudKitRecords];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Clear Backup Metadata Cache"
actionBlock:^{
[DebugUIBackup clearBackupMetadataCache];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Log Backup Metadata Cache"
actionBlock:^{
[DebugUIBackup logBackupMetadataCache];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Lazy Restore Attachments"
actionBlock:^{
[AppEnvironment.shared.backupLazyRestore runIfNecessary];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Upload 100 CK records"
actionBlock:^{
[DebugUIBackup uploadCKBatch:100];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Upload 1,000 CK records"
actionBlock:^{
[DebugUIBackup uploadCKBatch:1000];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Upload 10,000 CK records"
actionBlock:^{
[DebugUIBackup uploadCKBatch:10000];
}]];
return [OWSTableSection sectionWithTitle:self.name items:items];
}
+ (void)backupTestFile
{
OWSLogInfo(@"backupTestFile.");
NSData *_Nullable data = [Randomness generateRandomBytes:32];
OWSAssertDebug(data);
NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"pdf"];
BOOL success = [data writeToFile:filePath atomically:YES];
OWSAssertDebug(success);
NSString *recipientId = self.tsAccountManager.localNumber;
NSString *recordName = [OWSBackupAPI recordNameForTestFileWithRecipientId:recipientId];
CKRecord *record = [OWSBackupAPI recordForFileUrl:[NSURL fileURLWithPath:filePath] recordName:recordName];
[[self.backup ensureCloudKitAccess].thenInBackground(^{
return [OWSBackupAPI saveRecordsToCloudObjcWithRecords:@[ record ]];
}) retainUntilComplete];
}
+ (void)checkForBackup
{
OWSLogInfo(@"checkForBackup.");
[OWSBackup.sharedManager
checkCanImportBackup:^(BOOL value) {
OWSLogInfo(@"has backup available for import? %d", value);
}
failure:^(NSError *error){
// Do nothing.
}];
}
+ (void)logBackupRecords
{
OWSLogInfo(@"logBackupRecords.");
[OWSBackup.sharedManager logBackupRecords];
}
+ (void)logBackupManifests
{
OWSLogInfo(@"logBackupManifests.");
[OWSBackup.sharedManager
allRecipientIdsWithManifestsInCloud:^(NSArray<NSString *> *recipientIds) {
OWSLogInfo(@"recipientIds: %@", recipientIds);
}
failure:^(NSError *error) {
OWSLogError(@"error: %@", error);
}];
}
+ (void)tryToImportBackup
{
OWSLogInfo(@"tryToImportBackup.");
UIAlertController *alert =
[UIAlertController alertControllerWithTitle:@"Restore CloudKit Backup"
message:@"This will delete all of your database contents."
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"Restore"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[OWSBackup.sharedManager tryToImportBackup];
}]];
[alert addAction:[OWSAlerts cancelAction]];
UIViewController *fromViewController = [[UIApplication sharedApplication] frontmostViewController];
[fromViewController presentAlert:alert];
}
+ (void)logDatabaseSizeStats
{
OWSLogInfo(@"logDatabaseSizeStats.");
__block unsigned long long interactionCount = 0;
__block unsigned long long interactionSizeTotal = 0;
__block unsigned long long attachmentCount = 0;
__block unsigned long long attachmentSizeTotal = 0;
[[OWSPrimaryStorage.sharedManager newDatabaseConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[transaction enumerateKeysAndObjectsInCollection:[TSInteraction collection]
usingBlock:^(NSString *key, id object, BOOL *stop) {
TSInteraction *interaction = object;
interactionCount++;
NSData *_Nullable data =
[NSKeyedArchiver archivedDataWithRootObject:interaction];
OWSAssertDebug(data);
ows_add_overflow(
interactionSizeTotal, data.length, &interactionSizeTotal);
}];
[transaction enumerateKeysAndObjectsInCollection:[TSAttachment collection]
usingBlock:^(NSString *key, id object, BOOL *stop) {
TSAttachment *attachment = object;
attachmentCount++;
NSData *_Nullable data =
[NSKeyedArchiver archivedDataWithRootObject:attachment];
OWSAssertDebug(data);
ows_add_overflow(
attachmentSizeTotal, data.length, &attachmentSizeTotal);
}];
}];
OWSLogInfo(@"interactionCount: %llu", interactionCount);
OWSLogInfo(@"interactionSizeTotal: %llu", interactionSizeTotal);
if (interactionCount > 0) {
OWSLogInfo(@"interaction average size: %f", interactionSizeTotal / (double)interactionCount);
}
OWSLogInfo(@"attachmentCount: %llu", attachmentCount);
OWSLogInfo(@"attachmentSizeTotal: %llu", attachmentSizeTotal);
if (attachmentCount > 0) {
OWSLogInfo(@"attachment average size: %f", attachmentSizeTotal / (double)attachmentCount);
}
}
+ (void)clearAllCloudKitRecords
{
OWSLogInfo(@"");
[OWSBackup.sharedManager clearAllCloudKitRecords];
}
+ (void)clearBackupMetadataCache
{
OWSLogInfo(@"");
[OWSPrimaryStorage.sharedManager.newDatabaseConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction removeAllObjectsInCollection:[OWSBackupFragment collection]];
}];
}
+ (void)logBackupMetadataCache
{
[self.backup logBackupMetadataCache:OWSPrimaryStorage.sharedManager.newDatabaseConnection];
}
+ (void)uploadCKBatch:(NSUInteger)count
{
NSMutableArray<CKRecord *> *records = [NSMutableArray new];
for (NSUInteger i = 0; i < count; i++) {
NSData *_Nullable data = [Randomness generateRandomBytes:32];
OWSAssertDebug(data);
NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"pdf"];
BOOL success = [data writeToFile:filePath atomically:YES];
OWSAssertDebug(success);
NSString *recipientId = self.tsAccountManager.localNumber;
NSString *recordName = [OWSBackupAPI recordNameForTestFileWithRecipientId:recipientId];
CKRecord *record = [OWSBackupAPI recordForFileUrl:[NSURL fileURLWithPath:filePath] recordName:recordName];
[records addObject:record];
}
[[OWSBackupAPI saveRecordsToCloudObjcWithRecords:records].thenInBackground(^{
OWSLogVerbose(@"success.");
}) retainUntilComplete];
}
@end
NS_ASSUME_NONNULL_END