зеркало из https://github.com/nextcloud/talk-ios.git
272 строки
12 KiB
Objective-C
272 строки
12 KiB
Objective-C
/**
|
|
* @copyright Copyright (c) 2020 Marcel Müller <marcel-mueller@gmx.de>
|
|
*
|
|
* @author Marcel Müller <marcel-mueller@gmx.de>
|
|
*
|
|
* @license GNU GPL version 3 or any later version
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#import "NCChatFileController.h"
|
|
|
|
@import NextcloudKit;
|
|
|
|
#import "NCAPIController.h"
|
|
#import "NCDatabaseManager.h"
|
|
|
|
NSString * const NCChatFileControllerDidChangeIsDownloadingNotification = @"NCChatFileControllerDidChangeIsDownloadingNotification";
|
|
NSString * const NCChatFileControllerDidChangeDownloadProgressNotification = @"NCChatFileControllerDidChangeDownloadProgressNotification";
|
|
|
|
int const kNCChatFileControllerDeleteFilesOlderThanDays = 7;
|
|
|
|
@interface NCChatFileController ()
|
|
|
|
@property (nonatomic, strong) NCChatFileStatus *fileStatus;
|
|
@property (nonatomic, strong) NSString *tempDirectoryPath;
|
|
|
|
@end
|
|
|
|
|
|
@implementation NCChatFileController
|
|
|
|
- (void)initDownloadDirectoryForAccount:(TalkAccount *)account
|
|
{
|
|
NSString *encodedAccountId = [account.accountId stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet];
|
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
_tempDirectoryPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"/download/"];
|
|
_tempDirectoryPath = [_tempDirectoryPath stringByAppendingPathComponent:encodedAccountId];
|
|
|
|
NSLog(@"Directory for downloads: %@", _tempDirectoryPath);
|
|
|
|
if (![fileManager fileExistsAtPath:_tempDirectoryPath]) {
|
|
// Make sure our download directory exists
|
|
[fileManager createDirectoryAtPath:_tempDirectoryPath withIntermediateDirectories:YES attributes:nil error:nil];
|
|
}
|
|
|
|
[self removeOldFilesFromCache:kNCChatFileControllerDeleteFilesOlderThanDays];
|
|
}
|
|
|
|
- (void)removeOldFilesFromCache:(int)thresholdDays
|
|
{
|
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:_tempDirectoryPath];
|
|
|
|
NSDateComponents *dayComponent = [[NSDateComponents alloc] init];
|
|
dayComponent.day = -thresholdDays;
|
|
|
|
NSDate *thresholdDate = [[NSCalendar currentCalendar] dateByAddingComponents:dayComponent toDate:[NSDate date] options:0];
|
|
NSString *file;
|
|
|
|
while (file = [enumerator nextObject])
|
|
{
|
|
NSString *filePath = [_tempDirectoryPath stringByAppendingPathComponent:file];
|
|
NSDate *creationDate = [[fileManager attributesOfItemAtPath:filePath error:nil] fileCreationDate];
|
|
|
|
if ([creationDate compare:thresholdDate] == NSOrderedAscending) {
|
|
NSLog(@"Deleting file from cache: %@", filePath);
|
|
|
|
[fileManager removeItemAtPath:filePath error:nil];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)deleteDownloadDirectoryForAccount:(TalkAccount *)account
|
|
{
|
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
|
|
[self initDownloadDirectoryForAccount:account];
|
|
[fileManager removeItemAtPath:_tempDirectoryPath error:nil];
|
|
|
|
NSLog(@"Deleted download directory: %@", _tempDirectoryPath);
|
|
}
|
|
|
|
- (void)clearDownloadDirectoryForAccount:(TalkAccount *)account
|
|
{
|
|
[self deleteDownloadDirectoryForAccount:account];
|
|
[self initDownloadDirectoryForAccount:account];
|
|
}
|
|
|
|
- (NSInteger)getDiskUsageForAccount:(TalkAccount *)account
|
|
{
|
|
[self initDownloadDirectoryForAccount:account];
|
|
|
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:_tempDirectoryPath];
|
|
|
|
NSString *file;
|
|
NSInteger folderSize = 0;
|
|
|
|
while (file = [enumerator nextObject])
|
|
{
|
|
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[_tempDirectoryPath stringByAppendingPathComponent:file] error:nil];
|
|
folderSize += [[fileAttributes objectForKey:NSFileSize] intValue];
|
|
}
|
|
|
|
return folderSize;
|
|
}
|
|
|
|
- (BOOL)isFileInCache:(NSString *)filePath withModificationDate:(NSDate *)date withSize:(double)size
|
|
{
|
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
|
|
if (![fileManager fileExistsAtPath:filePath]) {
|
|
return NO;
|
|
}
|
|
|
|
NSError *error = nil;
|
|
NSDictionary<NSFileAttributeKey, id> *fileAttributes = [fileManager attributesOfItemAtPath:filePath error:&error];
|
|
|
|
NSDate *modificationDate = [fileAttributes fileModificationDate];
|
|
long long fileSize = [fileAttributes fileSize];
|
|
|
|
if ([date compare:modificationDate] == NSOrderedSame && fileSize == (long long)size) {
|
|
return YES;
|
|
}
|
|
|
|
// At this point there's a file in our cache but there's a different one on the server
|
|
NSLog(@"Deleting file from cache: %@", filePath);
|
|
[fileManager removeItemAtPath:filePath error:nil];
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (void)setCreationDateOnFile:(NSString *)filePath withCreationDate:(NSDate *)date
|
|
{
|
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
|
|
NSDictionary *creationDateAttr = [NSDictionary dictionaryWithObjectsAndKeys:date, NSFileCreationDate, nil];
|
|
[fileManager setAttributes:creationDateAttr ofItemAtPath:filePath error:nil];
|
|
}
|
|
|
|
- (void)setModificationDateOnFile:(NSString *)filePath withModificationDate:(NSDate *)date
|
|
{
|
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
|
|
NSDictionary *modificationDateAttr = [NSDictionary dictionaryWithObjectsAndKeys:date, NSFileModificationDate, nil];
|
|
[fileManager setAttributes:modificationDateAttr ofItemAtPath:filePath error:nil];
|
|
}
|
|
|
|
- (void)downloadFileFromMessage:(NCMessageFileParameter *)fileParameter
|
|
{
|
|
_fileStatus = [NCChatFileStatus initWithFileName:fileParameter.name withFilePath:fileParameter.path withFileId:fileParameter.parameterId];
|
|
fileParameter.fileStatus = _fileStatus;
|
|
|
|
[self startDownload];
|
|
}
|
|
|
|
- (void)downloadFileWithFileId:(NSString *)fileId
|
|
{
|
|
TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
|
|
|
|
[[NCAPIController sharedInstance] getFileByFileId:activeAccount fileId:fileId withCompletionBlock:^(NKFile *file, NSInteger error, NSString *errorDescription) {
|
|
if (file) {
|
|
NSString *remoteDavPrefix = [NSString stringWithFormat:@"/remote.php/dav/files/%@/", activeAccount.userId];
|
|
NSString *directoryPath = [file.path componentsSeparatedByString:remoteDavPrefix].lastObject;
|
|
|
|
NSString *filePath = [NSString stringWithFormat:@"%@%@", directoryPath, file.fileName];
|
|
|
|
self->_fileStatus = [NCChatFileStatus initWithFileName:file.fileName withFilePath:filePath withFileId:file.fileId];
|
|
[self startDownload];
|
|
} else {
|
|
NSLog(@"An error occurred while getting file with fileId %@: %@", fileId, errorDescription);
|
|
[self.delegate fileControllerDidFailLoadingFile:self withErrorDescription:errorDescription];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)startDownload
|
|
{
|
|
TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
|
|
|
|
[[NCAPIController sharedInstance] setupNCCommunicationForAccount:activeAccount];
|
|
[self initDownloadDirectoryForAccount:activeAccount];
|
|
|
|
NSString *serverUrlFileName = [NSString stringWithFormat:@"%@%@/%@", activeAccount.server, [[NCAPIController sharedInstance] filesPathForAccount:activeAccount], _fileStatus.filePath];
|
|
_fileStatus.fileLocalPath = [_tempDirectoryPath stringByAppendingPathComponent:_fileStatus.fileName];
|
|
|
|
// Setting just isDownloading without a concrete progress will show an indeterminate activity indicator
|
|
[self didChangeIsDownloadingNotification:YES];
|
|
|
|
// First read metadata from the file and check if we already downloaded it
|
|
NKRequestOptions *options = [[NKRequestOptions alloc] initWithEndpoint:nil customHeader:nil customUserAgent:nil contentType:nil e2eToken:nil timeout:60 queue:dispatch_get_main_queue()];
|
|
[[NextcloudKit shared] readFileOrFolderWithServerUrlFileName:serverUrlFileName depth:@"0" showHiddenFiles:NO requestBody:nil options:options completion:^(NSString *account, NSArray<NKFile *> *files, NSData *responseDates, NKError *error) {
|
|
if (error.errorCode == 0 && files.count == 1) {
|
|
// File exists on server -> check our cache
|
|
NKFile *file = files.firstObject;
|
|
|
|
if ([self isFileInCache:self->_fileStatus.fileLocalPath withModificationDate:file.date withSize:file.size]) {
|
|
NSLog(@"Found file in cache: %@", self->_fileStatus.fileLocalPath);
|
|
|
|
[self.delegate fileControllerDidLoadFile:self withFileStatus:self->_fileStatus];
|
|
[self didChangeIsDownloadingNotification:NO];
|
|
|
|
return;
|
|
}
|
|
[[NextcloudKit shared] downloadWithServerUrlFileName:serverUrlFileName fileNameLocalPath:self->_fileStatus.fileLocalPath customUserAgent:nil addCustomHeaders:nil queue:dispatch_get_main_queue() taskHandler:^(NSURLSessionTask *task) {
|
|
NSLog(@"Download task");
|
|
} progressHandler:^(NSProgress *progress) {
|
|
[self didChangeDownloadProgressNotification:progress.fractionCompleted];
|
|
} completionHandler:^(NSString *account, NSString *etag, NSDate *date, int64_t length, NSDictionary *allHeaderFields, NKError *error) {
|
|
if (error.errorCode == 0) {
|
|
// Set modification date to invalidate our cache
|
|
[self setModificationDateOnFile:self->_fileStatus.fileLocalPath withModificationDate:file.date];
|
|
|
|
// Set creation date to delete older files from cache
|
|
[self setCreationDateOnFile:self->_fileStatus.fileLocalPath withCreationDate:[NSDate date]];
|
|
|
|
[self.delegate fileControllerDidLoadFile:self withFileStatus:self->_fileStatus];
|
|
} else {
|
|
NSLog(@"Error downloading file: %ld - %@", error.errorCode, error.errorDescription);
|
|
[self.delegate fileControllerDidFailLoadingFile:self withErrorDescription:error.errorDescription];
|
|
}
|
|
|
|
[self didChangeIsDownloadingNotification:NO];
|
|
}];
|
|
} else {
|
|
[self didChangeIsDownloadingNotification:NO];
|
|
|
|
NSLog(@"Error downloading file: %ld - %@", error.errorCode, error.errorDescription);
|
|
[self.delegate fileControllerDidFailLoadingFile:self withErrorDescription:error.errorDescription];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)didChangeIsDownloadingNotification:(BOOL)isDownloading
|
|
{
|
|
_fileStatus.isDownloading = isDownloading;
|
|
|
|
NSMutableDictionary *userInfo = [NSMutableDictionary new];
|
|
[userInfo setObject:_fileStatus forKey:@"fileStatus"];
|
|
[userInfo setObject:@(isDownloading) forKey:@"isDownloading"];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatFileControllerDidChangeIsDownloadingNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
}
|
|
|
|
- (void)didChangeDownloadProgressNotification:(double)progress
|
|
{
|
|
_fileStatus.downloadProgress = progress;
|
|
|
|
NSMutableDictionary *userInfo = [NSMutableDictionary new];
|
|
[userInfo setObject:_fileStatus forKey:@"fileStatus"];
|
|
[userInfo setObject:@(progress) forKey:@"progress"];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatFileControllerDidChangeDownloadProgressNotification
|
|
object:self
|
|
userInfo:userInfo];
|
|
}
|
|
|
|
@end
|