|
@@ -0,0 +1,838 @@
|
|
|
+//
|
|
|
+// nasMixBackupsManager.m
|
|
|
+// 双子星云手机
|
|
|
+//
|
|
|
+// Created by xd h on 2024/8/30.
|
|
|
+//
|
|
|
+
|
|
|
+#import "nasMixBackupsManager.h"
|
|
|
+#import "customUploadOperation.h"
|
|
|
+#import "nasUploadFileManager.h"
|
|
|
+#import "frpFileExistModel.h"
|
|
|
+#import "frpUploadModel.h"
|
|
|
+
|
|
|
+#define Kboundary3 @"Boundaryhxd"
|
|
|
+
|
|
|
+@interface nasMixBackupsManager ()<NSURLSessionDataDelegate>
|
|
|
+//排队等候下载的上传地址数组
|
|
|
+@property(nonatomic,strong) NSMutableArray *uploadWaitingUrlArr;
|
|
|
+//正在下载的上传地址数组
|
|
|
+@property(nonatomic,strong) NSMutableArray *uploadingOperationArr;
|
|
|
+
|
|
|
+@property(nonatomic,assign) NSInteger speedShowCount;//内网的情况 多少次才刷新一次
|
|
|
+@end
|
|
|
+
|
|
|
+@implementation nasMixBackupsManager
|
|
|
++ (instancetype)shareManager {
|
|
|
+ static nasMixUploadManager *_instance;
|
|
|
+ static dispatch_once_t onceToken;
|
|
|
+ dispatch_once(&onceToken, ^{
|
|
|
+ _instance = [[self alloc] init];
|
|
|
+ });
|
|
|
+ return _instance;
|
|
|
+}
|
|
|
+
|
|
|
+- (instancetype)init {
|
|
|
+
|
|
|
+ if (self = [super init]) {
|
|
|
+ _maxUploadLoadCount = 1;
|
|
|
+
|
|
|
+ if ([connectDeviceManager shareInstance].isPingOk)
|
|
|
+ {
|
|
|
+ _speedShowCount = 3;
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ _speedShowCount = 0;
|
|
|
+ }
|
|
|
+ //[self registeNotification];
|
|
|
+ }
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+/** 添加要上传的 模型 */
|
|
|
+- (void)addBackupsWithModels:(NSArray *)fileModels{
|
|
|
+
|
|
|
+ HLog(@"添加备份任务-- %ld",fileModels.count)
|
|
|
+
|
|
|
+ for (uploadFileDataModel *model in fileModels) {
|
|
|
+ BOOL needAddType = YES;
|
|
|
+
|
|
|
+ //1. 排查上传中
|
|
|
+ for (customUploadOperation *operationDoing in self.uploadingOperationArr) {
|
|
|
+ if([operationDoing.fileModel.filename isEqualToString:model.filename]){
|
|
|
+ needAddType = NO;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //1. 排查等待下载
|
|
|
+ for (uploadFileDataModel *waitModel in self.uploadWaitingUrlArr) {
|
|
|
+ if([waitModel.filename isEqualToString:model.filename]){
|
|
|
+ needAddType = NO;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(needAddType){
|
|
|
+ [self.uploadWaitingUrlArr addObject:model];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //启动上传
|
|
|
+ [self beginUpload];
|
|
|
+}
|
|
|
+
|
|
|
+//在添加XX后 启动下载
|
|
|
+- (void)beginUpload
|
|
|
+{
|
|
|
+ BOOL isCanUseCellular = [HWDataManager getBoolWithKey:stringKeyAddSn(Const_file_Transfe_canUse_Cellular_all)];
|
|
|
+ if(!isCanUseCellular){//不允许流量上传
|
|
|
+ //
|
|
|
+ if([AFNetworkReachabilityManager sharedManager].networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN){
|
|
|
+ mainBlock(^{
|
|
|
+ [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileSuspendAllNotification object:nil];
|
|
|
+ [[iToast makeText:NSLocalizedString(@"File_Transfer_By_Cellular_tip",nil)] show];
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if(ksharedAppDelegate.DisabledFileTransferType){
|
|
|
+ if(ksharedAppDelegate.isImageNewFor130){
|
|
|
+ [[iToast makeText:NSLocalizedString(@"File_Transfer_Disable_tip",nil)] show];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ [[iToast makeText:NSLocalizedString(@"File_Transfer_Disable_tip2",nil)] show];
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ @synchronized (self) {
|
|
|
+ if(self.uploadingOperationArr.count == _maxUploadLoadCount){
|
|
|
+ HLog(@"正在上传的数量达到了最大值 %ld",_maxUploadLoadCount)
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(self.uploadWaitingUrlArr.count == 0){
|
|
|
+ HLog(@"没有等待中的上传任务")
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ NSInteger canAddTaskNumber = _maxUploadLoadCount - self.uploadingOperationArr.count;
|
|
|
+
|
|
|
+ for (int i=0; i<canAddTaskNumber; i++) {
|
|
|
+
|
|
|
+ if(self.uploadWaitingUrlArr.count >= 1){
|
|
|
+ //创建上传任务
|
|
|
+ uploadFileDataModel *WaitingModel = self.uploadWaitingUrlArr.firstObject;
|
|
|
+
|
|
|
+ __block customUploadOperation * operation = [customUploadOperation new];
|
|
|
+ operation.fileModel = WaitingModel;
|
|
|
+
|
|
|
+ //等待下载中的任务
|
|
|
+ [self.uploadWaitingUrlArr removeObjectAtIndex:0];
|
|
|
+ //添加到下载中数组
|
|
|
+ [self.uploadingOperationArr addObject:operation];
|
|
|
+
|
|
|
+ [self checkFileUploadStateWithOperation:operation];
|
|
|
+
|
|
|
+ //[weakSelf handleTaskDidUploadWith:operation withState:state];
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 检测文件是否上传过了
|
|
|
+- (void)checkFileUploadStateWithOperation:(customUploadOperation*)operation
|
|
|
+{
|
|
|
+ NSMutableDictionary*paraDict = [NSMutableDictionary new];
|
|
|
+
|
|
|
+ if(operation.fileModel.savePath){
|
|
|
+ NSString *absPath = [[NSString alloc] initWithFormat:@"%@%@",operation.fileModel.savePath,operation.fileModel.filename];
|
|
|
+ [paraDict setValue:absPath forKey:@"absPath"];
|
|
|
+
|
|
|
+ NSNumber *totalBytesNumber = [NSNumber numberWithLong:operation.fileModel.totalBytes];
|
|
|
+ [paraDict setValue:totalBytesNumber forKey:@"fileSize"];
|
|
|
+ }
|
|
|
+
|
|
|
+ KWeakSelf
|
|
|
+ [[netWorkManager shareInstance] cloudPhoneGETCallBackCode:@"isFileExist" Parameters:paraDict success:^(id _Nonnull responseObject) {
|
|
|
+
|
|
|
+ frpFileExistModel *model = [[frpFileExistModel alloc] initWithDictionary:responseObject error:nil];
|
|
|
+ if(model && model.status == 0){
|
|
|
+ [weakSelf checkFileUploadStateFunAfterNetWith:model WithOperation:operation];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ [weakSelf handleUploadFailOneFileBy:operation];
|
|
|
+ //FileExistRet(-1);
|
|
|
+ }
|
|
|
+ } failure:^(NSError * _Nonnull error) {
|
|
|
+ HLog(@"%@",error)
|
|
|
+ //FileExistRet(-1);
|
|
|
+ [weakSelf handleUploadFailOneFileBy:operation];
|
|
|
+ }];
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 检测分家是否存在后处理 是否要上传
|
|
|
+- (void)checkFileUploadStateFunAfterNetWith:(frpFileExistModel*)model WithOperation:(customUploadOperation*)operation
|
|
|
+{
|
|
|
+ if(!model){
|
|
|
+ [self handleUploadFailOneFileBy:operation];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ operation.fileModel.didUploadBytes = 0;
|
|
|
+ operation.fileModel.taskId = model.data.fileTaskId;
|
|
|
+
|
|
|
+ if(!model.data.exist){//未上传过
|
|
|
+ [self prepareToUploadFileWithOperation:operation];
|
|
|
+
|
|
|
+ }
|
|
|
+ else if(model.data.isComplete){//上传过了 并且文件上传完了
|
|
|
+ //判断下文件创建长度是否一致 一致则是上传完了 不一致 重新上传一个 可能是同名的文件而已
|
|
|
+ if(model.data.size >= operation.fileModel.totalBytes){//上传完了
|
|
|
+// mainBlock(^{
|
|
|
+// [[iToast makeText:NSLocalizedString(@"File_upload_file_already_exists",nil)] show];
|
|
|
+// });
|
|
|
+
|
|
|
+ [self handleUploadDoneOneFileBy:operation];
|
|
|
+ }
|
|
|
+ else{//未上传完 isComplete 这个字段有问题
|
|
|
+ operation.fileModel.didUploadBytes = model.data.size;
|
|
|
+ [self prepareToUploadFileWithOperation:operation];
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ else{//上传过了 未上传完成
|
|
|
+ operation.fileModel.didUploadBytes = model.data.size;
|
|
|
+ [self prepareToUploadFileWithOperation:operation];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark 处理任务失败
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark 准备上传文件
|
|
|
+- (void)prepareToUploadFileWithOperation:(customUploadOperation*)operation
|
|
|
+{
|
|
|
+ NSMutableDictionary *paraDict = [NSMutableDictionary new];
|
|
|
+
|
|
|
+ NSString* taskUid = operation.fileModel.taskId;
|
|
|
+ if(!taskUid || taskUid.length == 0){
|
|
|
+ taskUid = [iTools getTaskUidStr];
|
|
|
+ operation.fileModel.taskId = taskUid;
|
|
|
+ }
|
|
|
+
|
|
|
+ [paraDict setObject:taskUid forKey:@"taskId"];
|
|
|
+ [paraDict setObject:@0 forKey:@"position"];
|
|
|
+ [paraDict setObject:@"true" forKey:@"isLast"];
|
|
|
+ if(operation.fileModel.savePath){
|
|
|
+ [paraDict setObject:operation.fileModel.savePath forKey:@"savePath"];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ HLog(@"获取保存路径失败")
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(operation.fileModel.filename){
|
|
|
+ [paraDict setObject:operation.fileModel.filename forKey:@"filename"];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ HLog(@"获取用户名失败")
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ KWeakSelf
|
|
|
+ if(operation.fileModel.curUploadFileType == uploadFileTypeImage){
|
|
|
+ [paraDict setObject:@1 forKey:@"imageType"];
|
|
|
+
|
|
|
+ if(!operation.fileModel.imageData){
|
|
|
+
|
|
|
+ NSString*pathStr = [cachesFileManager getFilePathWithName:operation.fileModel.filename type:operation.fileModel.curUploadFileType];
|
|
|
+ NSData *imageData = [NSData dataWithContentsOfFile:pathStr];
|
|
|
+
|
|
|
+ if (!imageData) {
|
|
|
+
|
|
|
+ if(!operation.fileModel.asset){
|
|
|
+ NSString *curLocalIdentifier = operation.fileModel.localIdentifier;
|
|
|
+ PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[curLocalIdentifier] options:nil];
|
|
|
+ PHAsset *asset = fetchResult.firstObject;
|
|
|
+ operation.fileModel.asset = asset;
|
|
|
+ }
|
|
|
+
|
|
|
+ [[PHImageManager defaultManager] requestImageDataForAsset:operation.fileModel.asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
|
|
|
+ // 直接得到最终的 NSData 数据
|
|
|
+ if (imageData) {
|
|
|
+ operation.fileModel.imageData = imageData;
|
|
|
+ [weakSelf afterGetImageDataFunWithOperation:operation];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ [weakSelf handleUploadFailOneFileBy:operation];
|
|
|
+ }
|
|
|
+ }];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ operation.fileModel.imageData = imageData;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ NSData *curData = operation.fileModel.imageData;
|
|
|
+ operation.onceDataLengt = [curData length];
|
|
|
+
|
|
|
+ [self startUpload:paraDict operation:operation data:curData success:^(id _Nonnull responseObject) {
|
|
|
+ frpUploadModel *model = [[frpUploadModel alloc] initWithDictionary:responseObject error:nil];
|
|
|
+ if(model && model.position == operation.fileModel.totalBytes){
|
|
|
+ HLog(@"%@上传完成 000",operation.fileModel.filename)
|
|
|
+ [weakSelf handleUploadDoneOneFileBy:operation];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ HLog(@"%@上传完成一片 %ld",operation.fileModel.filename,model.position)
|
|
|
+ }
|
|
|
+ } faild:^(NSError * _Nonnull error) {
|
|
|
+ HLog(@"%@上传失败",operation.fileModel.filename)
|
|
|
+ [weakSelf handleUploadFailOneFileBy:operation];
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ [paraDict setObject:@1 forKey:@"videoType"];
|
|
|
+ [paraDict setObject:@"false" forKey:@"isLast"];
|
|
|
+
|
|
|
+ if(![cachesFileManager checkFileIsSaveState:operation.fileModel.filename withType:uploadFileTypeVideo]){
|
|
|
+
|
|
|
+ if(!operation.fileModel.asset){
|
|
|
+ NSString *curLocalIdentifier = operation.fileModel.localIdentifier;
|
|
|
+ PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[curLocalIdentifier] options:nil];
|
|
|
+ PHAsset *asset = fetchResult.firstObject;
|
|
|
+ operation.fileModel.asset = asset;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //真正的视频数据
|
|
|
+ PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
|
|
|
+ options.version = PHVideoRequestOptionsVersionOriginal;
|
|
|
+ [[PHImageManager defaultManager] requestAVAssetForVideo:operation.fileModel.asset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
|
|
|
+ if ([asset isKindOfClass:[AVURLAsset class]]) {
|
|
|
+
|
|
|
+ AVURLAsset* urlAsset = (AVURLAsset*)asset;
|
|
|
+
|
|
|
+ BOOL isSuc = [cachesFileManager copyVideoItemAtPath:[urlAsset.URL path] fileName:operation.fileModel.filename error:nil];
|
|
|
+
|
|
|
+ if (isSuc) {
|
|
|
+ [weakSelf afterGetVideoDataFunWithOperation:operation];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ [weakSelf handleUploadFailOneFileBy:operation];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ [weakSelf handleUploadFailOneFileBy:operation];
|
|
|
+ }
|
|
|
+ }];
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ long curPosition = operation.fileModel.didUploadBytes;
|
|
|
+ [self beginUploadVideoDataFunBy:operation with:curPosition withPara:paraDict success:^(id _Nonnull responseObject) {
|
|
|
+
|
|
|
+ } faild:^(NSError * _Nonnull error) {
|
|
|
+
|
|
|
+ }];
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 视频上传
|
|
|
+- (void)beginUploadVideoDataFunBy:(customUploadOperation*)operation with:(NSInteger)position withPara:(NSMutableDictionary*)paraDict success:(netWork_Success)success faild:(netWork_Faild)faildStr
|
|
|
+{
|
|
|
+ if(operation.isCancelType){
|
|
|
+ HLog(@"防止取消不了任务生效")
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ BOOL isLastPicece = NO;
|
|
|
+ if((operation.fileModel.totalBytes - position) <= MaxNasUploadPieceSzie){
|
|
|
+ [paraDict setObject:@"true" forKey:@"isLast"];
|
|
|
+ isLastPicece = YES;
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ [paraDict setObject:@"false" forKey:@"isLast"];
|
|
|
+ }
|
|
|
+
|
|
|
+ [paraDict setObject:[NSNumber numberWithLong:position] forKey:@"position"];
|
|
|
+
|
|
|
+ //视频数据切片
|
|
|
+ __block NSData *videoData = [self cutVideoFileFunAtIndex:position withMaxLenght:MaxNasUploadPieceSzie withModel:operation.fileModel];
|
|
|
+
|
|
|
+ if(!videoData ||videoData.length ==0){
|
|
|
+ HLog(@"视频没获取到")
|
|
|
+ [self handleUploadFailOneFileBy:operation];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ operation.onceDataLengt = [videoData length];
|
|
|
+ KWeakSelf
|
|
|
+ [self startUpload:paraDict operation:operation data:videoData success:^(id _Nonnull responseObject) {
|
|
|
+ frpUploadModel *model = [[frpUploadModel alloc] initWithDictionary:responseObject error:nil];
|
|
|
+ if(model && model.position >= operation.fileModel.totalBytes){
|
|
|
+ HLog(@"%@上传完成 000",operation.fileModel.filename)
|
|
|
+ [weakSelf handleUploadDoneOneFileBy:operation];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ HLog(@"%@上传完成一片 %ld",operation.fileModel.filename,model.position)
|
|
|
+
|
|
|
+ [weakSelf beginUploadVideoDataFunBy:operation with:model.position withPara:paraDict success:^(id _Nonnull responseObject) {
|
|
|
+ success(responseObject);
|
|
|
+ } faild:^(NSError * _Nonnull error) {
|
|
|
+ NSError *err = error;
|
|
|
+ if(error.code != -999){
|
|
|
+ faildStr(err);
|
|
|
+ }
|
|
|
+
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ } faild:^(NSError * _Nonnull error) {
|
|
|
+ HLog(@"%@上传失败",operation.fileModel.filename)
|
|
|
+ [weakSelf handleUploadFailOneFileBy:operation];
|
|
|
+ }];
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 分段读视频文件
|
|
|
+-(NSData*)cutVideoFileFunAtIndex:(NSUInteger)dataIndex withMaxLenght:(NSInteger)maxLengt withModel:(uploadFileDataModel*)dataModel{
|
|
|
+ NSString *filePath = [cachesFileManager getFilePathWithName:dataModel.filename type:uploadFileTypeVideo]; // 文件路径
|
|
|
+
|
|
|
+ NSFileManager *manager0 = [NSFileManager defaultManager];
|
|
|
+ if(![manager0 fileExistsAtPath:filePath]) {
|
|
|
+
|
|
|
+ return [NSData new];
|
|
|
+ }
|
|
|
+
|
|
|
+ NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath]; // 创建文件句柄
|
|
|
+
|
|
|
+ // 设置分段读取的大小,这里以每次读取1KB为例
|
|
|
+ const NSUInteger chunkSize = maxLengt;//cutVideoPieceSzie;//5 * 1024 *1024;
|
|
|
+ NSMutableData *data = [NSMutableData data];
|
|
|
+
|
|
|
+ if (fileHandle) {
|
|
|
+
|
|
|
+ long long endOfFile = [fileHandle seekToEndOfFile];
|
|
|
+
|
|
|
+ if(dataModel.totalBytes == 0
|
|
|
+ || dataModel.totalBytes < endOfFile){//异常处理
|
|
|
+ dataModel.totalBytes = endOfFile;
|
|
|
+ }
|
|
|
+
|
|
|
+ //异常处理
|
|
|
+ if(endOfFile == dataIndex){
|
|
|
+ dataModel.totalBytes = endOfFile;
|
|
|
+ dataModel.didUploadBytes = endOfFile;
|
|
|
+ dataModel.curUploadStateType = uploadStateDone;
|
|
|
+ [fileHandle closeFile];
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (endOfFile >= chunkSize) {
|
|
|
+
|
|
|
+ // 读取文件的分段数据到某个位置
|
|
|
+ [fileHandle seekToFileOffset:dataIndex];
|
|
|
+
|
|
|
+ // 读取文件的分段数据
|
|
|
+ NSData* chunk = [fileHandle readDataOfLength:chunkSize];
|
|
|
+ if (chunk) {
|
|
|
+ [data appendData:chunk];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ // 读取文件的分段数据到某个位置
|
|
|
+ [fileHandle seekToFileOffset:dataIndex];
|
|
|
+
|
|
|
+ [data appendData:[fileHandle readDataToEndOfFile]];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在这里可以对文件内容进行处理
|
|
|
+ // ...
|
|
|
+
|
|
|
+ // 关闭文件句柄
|
|
|
+ [fileHandle closeFile];
|
|
|
+ }
|
|
|
+
|
|
|
+ HLog(@"视频切片完成 dataIndex:%ld --长度:%ld",dataIndex,[data length])
|
|
|
+ return data;
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 处理上传完成
|
|
|
+- (void)handleUploadDoneOneFileBy:(customUploadOperation*)operation
|
|
|
+{
|
|
|
+ [[NSNotificationCenter defaultCenter] postNotificationName:nasBackupsTaskExeEnd object:operation.fileModel];
|
|
|
+ [_uploadingOperationArr removeObject:operation];
|
|
|
+ //[self beginUpload];
|
|
|
+ [[nasBackupsManager shareInstance] backupsFileDoneFun];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 处理删除失败
|
|
|
+- (void)handleUploadFailOneFileBy:(customUploadOperation*)operation
|
|
|
+{
|
|
|
+ operation.fileModel.curUploadStateType = uploadStateFail;
|
|
|
+ [[NSNotificationCenter defaultCenter] postNotificationName:nasBackupsTaskExeError object:operation.fileModel];
|
|
|
+ [_uploadingOperationArr removeObject:operation];
|
|
|
+ //[self beginUpload];
|
|
|
+ [[backupsFileManager shareInstance] changeBackupsFileStateToFailWith:@"back fail"];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 根据 asset 获取到图片数据
|
|
|
+- (void)afterGetImageDataFunWithOperation:(customUploadOperation*)operation
|
|
|
+{
|
|
|
+ [cachesFileManager getFileNameWithContent:operation.fileModel.imageData fileName:operation.fileModel.filename type:uploadFileTypeImage];
|
|
|
+
|
|
|
+ [self prepareToUploadFileWithOperation:operation];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 根据 asset 获取到视频数据
|
|
|
+- (void)afterGetVideoDataFunWithOperation:(customUploadOperation*)operation
|
|
|
+{
|
|
|
+
|
|
|
+ [self prepareToUploadFileWithOperation:operation];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 开始上传
|
|
|
+- (void)startUpload:(NSMutableDictionary *)params operation:(customUploadOperation*)operation data:(NSData *)data success:(netWork_Success)success faild:(netWork_Faild)faildStr {
|
|
|
+
|
|
|
+ NSString *urlString = ksharedAppDelegate.NASFileByBoxService;
|
|
|
+ urlString = [[NSString alloc] initWithFormat:@"%@uploadFile",urlString];
|
|
|
+ NSURL *URL = [NSURL URLWithString:urlString];
|
|
|
+ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
|
|
|
+ [request setHTTPMethod:@"POST"];
|
|
|
+
|
|
|
+ //请求体
|
|
|
+ NSMutableData *bodyData = [self getBodyDataWithRequest:request withModel:operation.fileModel withData:data withPara:params];
|
|
|
+
|
|
|
+ //设置请求体
|
|
|
+ [request setHTTPMethod:@"POST"];
|
|
|
+ [request setHTTPBody:bodyData];
|
|
|
+
|
|
|
+ //设置请求体长度
|
|
|
+ NSInteger length = [bodyData length];
|
|
|
+ [request setValue:[NSString stringWithFormat:@"%ld",length] forHTTPHeaderField:@"Content-Length"];
|
|
|
+ //设置 POST请求文件上传
|
|
|
+ [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary3] forHTTPHeaderField:@"Content-Type"];
|
|
|
+
|
|
|
+ KWeakSelf
|
|
|
+ //回话对象
|
|
|
+ NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
|
|
|
+ operation.session = session;
|
|
|
+
|
|
|
+ //请求task
|
|
|
+ /*
|
|
|
+ 第一个参数:请求对象
|
|
|
+ 第二个参数:传递是要上传的数据(请求体)
|
|
|
+ 第三个参数:
|
|
|
+ */
|
|
|
+ NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:nil completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
|
|
+ //解析
|
|
|
+ [weakSelf handleCustomUploadResultBy:data withResponse:response withError:error success:success faild:faildStr];
|
|
|
+ }];
|
|
|
+
|
|
|
+// NSString *filePath = [cachesFileManager getFilePathWithName:dataModel.filename type:uploadFileTypeVideo]; // 文件路径
|
|
|
+// NSURL *filePathUrl = [NSURL URLWithString:filePath];
|
|
|
+//
|
|
|
+// NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:filePathUrl completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
|
|
+// HLog(@"data string:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
|
|
|
+ //[weakSelf handleCustomUploadResultBy:data withResponse:response withError:error];
|
|
|
+// }];
|
|
|
+
|
|
|
+// NSURLSessionDataTask *uploadTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
|
|
+//
|
|
|
+// HLog(@"data string:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
|
|
|
+ //[weakSelf handleCustomUploadResultBy:data withResponse:response withError:error];
|
|
|
+//
|
|
|
+//// NSJSONSerialization *object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
|
|
|
+//// NSDictionary *dict = (NSDictionary *)object;
|
|
|
+//// NSLog(@"=====%@",[dict objectForKey:@"success"]);
|
|
|
+// }];
|
|
|
+
|
|
|
+
|
|
|
+ //执行Task
|
|
|
+ [uploadTask resume];
|
|
|
+ operation.dataTask = uploadTask;
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 用系统方法写的上传处理
|
|
|
+- (void)handleCustomUploadResultBy:(NSData*)data withResponse:(NSURLResponse*)response withError:(NSError*)error success:(netWork_Success)success faild:(netWork_Faild)faildStr{
|
|
|
+ if(error){
|
|
|
+ HLog(@"上传错误:%@",error)
|
|
|
+ if(error.code != -999){
|
|
|
+ faildStr(error);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ NSJSONSerialization *object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
|
|
|
+ NSDictionary *dict = (NSDictionary *)object;
|
|
|
+
|
|
|
+ frpUploadModel *model = [[frpUploadModel alloc] initWithDictionary:dict error:nil];
|
|
|
+ if(model && [model.msg isEqualToString:@"success"]){
|
|
|
+ success(dict);
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ NSError *err = [NSError new];
|
|
|
+ faildStr(err);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (NSMutableData *)getBodyDataWithRequest:(NSMutableURLRequest *)request withModel:(uploadFileDataModel*)dataModel withData:(NSData*)data withPara:(NSMutableDictionary*)params{
|
|
|
+
|
|
|
+ //1 边界符号要配置请求头里面去
|
|
|
+ /*
|
|
|
+ multipart/form-data 是表单格式
|
|
|
+ charset=utf-8 是utf-8编码
|
|
|
+ bounary 是表单开头
|
|
|
+ */
|
|
|
+ [request setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", Kboundary3] forHTTPHeaderField:@"Content-Type"];
|
|
|
+
|
|
|
+ /// body
|
|
|
+ NSMutableData *boydData = [NSMutableData data];
|
|
|
+ // 2.1 边界符号(开始边界)
|
|
|
+
|
|
|
+ //2.1.1 其它参数
|
|
|
+ NSMutableString *paraString = [NSMutableString new];
|
|
|
+ //[paraString appendFormat:@"--%@\r\n",Kboundary];//\n:换行 \n:切换到行首
|
|
|
+ for (NSString *key in params) {
|
|
|
+ NSString *value = params[key];
|
|
|
+ [paraString appendFormat:@"--%@\r\n",Kboundary3];//\n:换行 \n:切换到行首
|
|
|
+ [paraString appendFormat:@"Content-Disposition: form-data; name=\"%@\"",key];
|
|
|
+ [paraString appendFormat:@"\r\n"];
|
|
|
+ [paraString appendFormat:@"\r\n"];
|
|
|
+ [paraString appendFormat:@"%@\r\n",value];
|
|
|
+ }
|
|
|
+
|
|
|
+ //[boydData appendData:[paraString dataUsingEncoding:NSUTF8StringEncoding]];
|
|
|
+
|
|
|
+
|
|
|
+ // body每一个段内容以换行符作为结束标示
|
|
|
+ NSString *fileBeginBoundary = [NSString stringWithFormat:@"--%@\r\n", Kboundary3];
|
|
|
+ //[boydData appendData:[fileBeginBoundary dataUsingEncoding:NSUTF8StringEncoding]];
|
|
|
+
|
|
|
+ [paraString appendString:fileBeginBoundary];
|
|
|
+
|
|
|
+ // 2.2 属性配置 名字;key;类型
|
|
|
+
|
|
|
+ NSString *serverFileKey = @"image"; //key
|
|
|
+ //NSString *serverFileKey = @"file";
|
|
|
+ NSString *serverContentTypes = @"image/png"; //类型
|
|
|
+
|
|
|
+ if (dataModel.curUploadFileType == uploadFileTypeVideo) {
|
|
|
+ serverFileKey = @"video";
|
|
|
+ serverContentTypes = @"video/mp4";
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ NSString *serverFileName = dataModel.filename; //name
|
|
|
+
|
|
|
+
|
|
|
+ // filename已命名文件; name相当于一个key, 这个名字和服务器保持一致
|
|
|
+ /*
|
|
|
+ 理解key,表单发送给服务端,服务端拿到数据之后,可以将任务解析成一个字典了imageDict;图片数据会通过这个字典里面的name来获取图片(伪代码 image = imageDict[serverFileKey])
|
|
|
+ */
|
|
|
+ //2.3 拼接数据(创建一个字符串来拼装)
|
|
|
+ NSMutableString *string = [NSMutableString new];
|
|
|
+ [string appendFormat:@"Content-Disposition:form-data; name=\"%@\"; filename=\"%@\" ", @"file", serverFileName];
|
|
|
+ //[string appendFormat:@"%@", KNewLine];
|
|
|
+ [string appendFormat:@"\r\n"];
|
|
|
+ [string appendFormat:@"Content-Type:%@", serverContentTypes];
|
|
|
+// [string appendFormat:@"%@", KNewLine];
|
|
|
+// [string appendFormat:@"%@", KNewLine];
|
|
|
+ [string appendFormat:@"\r\n"];
|
|
|
+ [string appendFormat:@"\r\n"];
|
|
|
+ // [boydData appendData:[string dataUsingEncoding:NSUTF8StringEncoding]];
|
|
|
+
|
|
|
+ [paraString appendString:string];
|
|
|
+ [boydData appendData:[paraString dataUsingEncoding:NSUTF8StringEncoding]];
|
|
|
+
|
|
|
+ // 2.3 拼接数据(拼接文件数据)
|
|
|
+ [boydData appendData:data];
|
|
|
+
|
|
|
+ // 2.4 边界符号 (结束边界)
|
|
|
+ NSString *fileEndBoundary = [NSString stringWithFormat:@"\r\n--%@--", Kboundary3];
|
|
|
+ [boydData appendData:[fileEndBoundary dataUsingEncoding:NSUTF8StringEncoding]];
|
|
|
+
|
|
|
+ return boydData;
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 上传的文件已存在
|
|
|
+- (void)handleTaskDidUploadWith:(customUploadOperation*)operation withState:(NSInteger)state
|
|
|
+{
|
|
|
+// if(state == 1){
|
|
|
+// [[iToast makeText:NSLocalizedString(@"File_upload_file_already_exists",nil)] show];
|
|
|
+// }
|
|
|
+
|
|
|
+
|
|
|
+ [self.uploadingOperationArr removeObject:operation];
|
|
|
+
|
|
|
+ NSMutableArray *delArr = [NSMutableArray new];
|
|
|
+ [delArr addObject:operation.fileModel];
|
|
|
+
|
|
|
+ [[nasUploadFileManager shareInstance] deleteUploadFileRecordBy:delArr withDelCache:NO complete:^(BOOL isSuccess) {
|
|
|
+ if (isSuccess) {
|
|
|
+
|
|
|
+ }
|
|
|
+ }];
|
|
|
+
|
|
|
+ [self beginUpload];
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark - <NSURLSessionDataDelegate>
|
|
|
+
|
|
|
+// ssl 服务 证书信任
|
|
|
+- (void)URLSession:(NSURLSession *)session
|
|
|
+didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
|
|
|
+ completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{
|
|
|
+ if(![challenge.protectionSpace.authenticationMethod isEqualToString:@"NSURLAuthenticationMethodServerTrust"]) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 信任该插件
|
|
|
+ NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
|
|
|
+ // 第一个参数 告诉系统如何处置
|
|
|
+ completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
|
|
|
+}
|
|
|
+
|
|
|
+//当请求协议是https的时候回调用该方法
|
|
|
+//Challenge 挑战 质询(受保护空间)
|
|
|
+//NSURLAuthenticationMethodServerTrust 服务器信任证书
|
|
|
+- (void)URLSession:(NSURLSession *)session
|
|
|
+ task:(NSURLSessionTask *)task
|
|
|
+didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
|
|
|
+ completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler {
|
|
|
+
|
|
|
+ if(![challenge.protectionSpace.authenticationMethod isEqualToString:@"NSURLAuthenticationMethodServerTrust"]) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 信任该插件
|
|
|
+ NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
|
|
|
+ // 第一个参数 告诉系统如何处置
|
|
|
+ completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// 接受到响应调用
|
|
|
+- (void)URLSession:(NSURLSession *)session
|
|
|
+ dataTask:(NSURLSessionDataTask *)dataTask
|
|
|
+didReceiveResponse:(NSURLResponse *)response
|
|
|
+ completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
|
|
|
+
|
|
|
+ completionHandler(NSURLSessionResponseAllow);
|
|
|
+}
|
|
|
+
|
|
|
+// 上传进度
|
|
|
+- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
|
|
|
+
|
|
|
+ //每包发送的大小bytesSent,totalBytesSent已经上传了多少;totalBytesExpectedToSend总共要发送多少
|
|
|
+ // 32768 = 32KB
|
|
|
+ HLog(@"didSendBodyData: %lld--%lld-%lld", bytesSent, totalBytesSent, totalBytesExpectedToSend);
|
|
|
+
|
|
|
+ for (customUploadOperation*operation in _uploadingOperationArr) {
|
|
|
+ if(operation.dataTask == task){
|
|
|
+ operation.fileModel.didUploadBytes += bytesSent;
|
|
|
+
|
|
|
+ //调整下大小 因为上传的数据 除了data 长度 还包含了 参数大小
|
|
|
+ if(totalBytesSent == totalBytesExpectedToSend){
|
|
|
+ operation.fileModel.didUploadBytes -= (totalBytesExpectedToSend - operation.onceDataLengt);
|
|
|
+ }
|
|
|
+
|
|
|
+ operation.i ++;
|
|
|
+ if(operation.i >= _speedShowCount){
|
|
|
+
|
|
|
+ [nasBackupsManager shareInstance].curPhotosBackupsTaskMod.didUploadBytes = operation.fileModel.didUploadBytes;
|
|
|
+
|
|
|
+ [[nasBackupsManager shareInstance] changeBackupsFileStateFun];
|
|
|
+
|
|
|
+// [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileRefreshNotification object:operation.fileModel];
|
|
|
+ operation.i = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 取消单个任务
|
|
|
+- (void)cancelUploadTaskFunWith:(uploadFileDataModel*)fileModel
|
|
|
+{
|
|
|
+ HLog(@"取消任务-- %@--%@",fileModel.filename,fileModel.taskId)
|
|
|
+ @synchronized (self) {
|
|
|
+ for (uploadFileDataModel*waitModel in _uploadWaitingUrlArr) {
|
|
|
+ if([waitModel.filename isEqualToString:fileModel.filename]){
|
|
|
+ [_uploadWaitingUrlArr removeObject:waitModel];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (customUploadOperation*operation in _uploadingOperationArr) {
|
|
|
+ if([operation.fileModel.filename isEqualToString:fileModel.filename]){
|
|
|
+ operation.isCancelType = YES;
|
|
|
+ [operation.dataTask cancel];
|
|
|
+ [_uploadingOperationArr removeObject:operation];
|
|
|
+ [self beginUpload];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark 取消所有任务
|
|
|
+- (void)cancelUploadAllTaskFun
|
|
|
+{
|
|
|
+ HLog(@"取消所有任务")
|
|
|
+ @synchronized (self) {
|
|
|
+ [_uploadWaitingUrlArr removeAllObjects];
|
|
|
+
|
|
|
+ for (customUploadOperation*operation in _uploadingOperationArr) {
|
|
|
+ operation.isCancelType = YES;
|
|
|
+ [operation.dataTask cancel];
|
|
|
+ }
|
|
|
+
|
|
|
+ [_uploadingOperationArr removeAllObjects];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark 判断是否在上传中
|
|
|
+- (BOOL)checkUploadTaskDoingFun
|
|
|
+{
|
|
|
+ if(_uploadWaitingUrlArr.count >0 || _uploadingOperationArr.count>0){
|
|
|
+ return YES;
|
|
|
+ }
|
|
|
+
|
|
|
+ return NO;
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark - lazy load
|
|
|
+- (NSMutableArray *)uploadWaitingUrlArr {
|
|
|
+
|
|
|
+ if (!_uploadWaitingUrlArr) {
|
|
|
+ _uploadWaitingUrlArr = [NSMutableArray array];
|
|
|
+ }
|
|
|
+ return _uploadWaitingUrlArr;
|
|
|
+}
|
|
|
+
|
|
|
+- (NSMutableArray *)uploadingOperationArr {
|
|
|
+
|
|
|
+ if (!_uploadingOperationArr) {
|
|
|
+ _uploadingOperationArr = [NSMutableArray array];
|
|
|
+ }
|
|
|
+ return _uploadingOperationArr;
|
|
|
+}
|
|
|
+@end
|