// // CWUploadTask.m // uploadFileDemo // // Created by hyjet on 2018/3/9. // Copyright © 2018年 uploadFileDemo. All rights reserved. // #import "CWUploadTask.h" #import "CWFileUploadManager.h" #import "CWFileStreamSeparation.h" #import "CWFileManager.h" #import "CWUploadTask+CheckInfo.h" //分隔符 #define Boundary @"1a2b3c" //一般换行 #define Wrap1 @"\r\n" //key-value换行 #define Wrap2 @"\r\n\r\n" //开始分割 #define StartBoundary [NSString stringWithFormat:@"--%@%@",Boundary,Wrap1] //文件分割完成 #define EndBody [NSString stringWithFormat:@"--%@--",Boundary] //一个片段上传失败默认重试3次 #define REPEAT_MAX 3 //#define plistPath [[CWFileManager cachesDir] stringByAppendingPathComponent:uploadPlist] #define GETPOSTFLOWCHUNKAPI @"/nextcloud/index.php/apps/rcapi/ajax/upload.php"/*断点续传*/ NSString *const CWUploadTaskExeing = @"TaskExeing"; NSString *const CWUploadTaskExeError = @"TaskExeError"; NSString *const CWUploadTaskExeEnd = @"TaskExeEnd"; NSString *const CWUploadTaskExeSuspend = @"TaskExeSuspend"; @interface CWUploadTask () //@property (nonatomic,strong)NSURLSessionUploadTask *uploadTask; //@property (nonatomic,strong)NSMutableURLRequest *request; //@property (nonatomic,readwrite)NSURLSessionTaskState taskState; @property (nonatomic,readwrite)NSURL * url; @property (nonatomic,readwrite)NSString *ID; @property (nonatomic,readwrite)NSMutableDictionary *param;//上传时参数 @property (nonatomic,readwrite)CWFileStreamSeparation *fileStream; @property (nonatomic,copy)finishHandler finishBlock;//片段上传成功上传的回调block @property (nonatomic,copy)success successBlock;//整体上传成功上传的回调block @property (nonatomic,copy)NSString *chunkNumName;//片段编号这一参数的参数名 @property (nonatomic,copy)NSDictionary *lastParam;//片段完成上传后的参数 @property (nonatomic,assign)NSInteger chunkNo;//片段完成上传后的编号 @property (nonatomic,assign)NSInteger taskRepeatNum;//重试次数 @property (nonatomic,assign)BOOL isSuspendedState;//记录状态更改 @property (nonatomic,strong)CWFileUploadManager *uploadManager; @end @implementation CWUploadTask -(CWFileUploadManager *)uploadManager { if (!_uploadManager) { _uploadManager = [CWFileUploadManager shardUploadManager]; } return _uploadManager; } - (void)setFileStream:(CWFileStreamSeparation *)fileStream { _fileStream.fileStatus = CWUploadStatusWaiting; _taskRepeatNum = 0; _ID = fileStream.md5String; for (NSInteger idx=0; idx *)uploadTasksWithDict:(NSDictionary *)dict{ NSMutableDictionary *taskDict = [NSMutableDictionary dictionary]; for (NSString *key in dict.allKeys) { CWFileStreamSeparation *fs = [dict objectForKey:key]; CWUploadTask *task = [CWUploadTask initWithStreamModel:fs]; [taskDict setValue:task forKey:key]; } return taskDict; } + (instancetype)initWithStreamModel:(CWFileStreamSeparation *)fileStream { CWUploadTask *task = [CWUploadTask new]; task.fileStream = fileStream; task.timeStamp = [iTools getNowTimeStamp]; task.isSuspendedState = NO; task.url = [CWFileUploadManager shardUploadManager].url; return task; } - (void)listenTaskExeCallback:(finishHandler _Nonnull)block success:(success)successBlock { self.finishBlock = block; self.successBlock = successBlock; if (_finishBlock) _finishBlock(_fileStream,nil); } - (instancetype _Nonnull)initWithStreamModel:(CWFileStreamSeparation *)fileStream finish:(finishHandler _Nonnull)block success:(success)successBlock { if (self = [super init]) { self.fileStream = fileStream; _finishBlock = block; _successBlock = successBlock; } return self; } //-(NSMutableURLRequest*)uploadRequest //{ // if ([CWFileUploadManager shardUploadManager].request) { // _request = [CWFileUploadManager shardUploadManager].request; // }else{ // HLog(@"请配置上传任务的request"); // } // return _request; // //} -(NSData*)taskRequestBodyWithParam:(NSDictionary *)param uploadData:(NSData *)data { NSMutableData* totlData=[NSMutableData new]; NSArray* allKeys=[param allKeys]; for (int i=0; i_param setObject:[NSString stringWithFormat:@"%zd",(i+1)] forKey:@"flowChunkNumber"]; [self->_param setObject:@(fragment.fragmentSize) forKey:@"flowCurrentChunkSize"]; dispatch_group_async(group, queue, ^{ @autoreleasepool { NSData *data = [self->_fileStream readDateOfFragment:fragment]; self.lastParam = self->_param; // if ([CWFileUploadManager shardUploadManager].leftStore < data.length) { // 云盘空间不足 // // // 分片上传失败 // self->_fileStream.fileStatus = CWUploadStatusFailed; // self->_fileStream.timeStamp = [iTools getNowTimeStamp]; // [self archTaskFileStream]; // // 分片上传失败通知 刷新列表 // dispatch_async(dispatch_get_main_queue(), ^{ // NSString *error = @"云盘剩余空间不足"; // [self sendNotionWithKey:CWUploadTaskExeError userInfo:@{@"fileStream":self->_fileStream,@"error":error}]; // [self sendNotionWithKey:CloudStoreIsFullNotification userInfo:@{}]; // }); // [self deallocSession]; // return; // } HLog(@"POST之前——--文件名:%@ 已上传完进度:%.2f 上传状态:%ld", self->_fileStream.fileName, self->_fileStream.progressRate, self->_fileStream.fileStatus); [[UseAccountManage shareInstance] doUploadInfoWithParams:self->_param md5string:self->_fileStream.md5String data:data success:^(id _Nonnull responseObject) { self->_taskRepeatNum = 0; fragment.fragmentStatus = YES; [self archTaskFileStream]; self->_chunkNo = i+1; dispatch_async(dispatch_get_main_queue(), ^{ if (self->_fileStream.streamFragments.count == self->_chunkNo) { // 分片上传成功 是最后一片 上传完 self->_fileStream.fileStatus = CWUploadStatusFinished; self->_fileStream.progressRate = 1.00; self->_fileStream.uploadDateSize = self->_fileStream.fileSize; self->_fileStream.timeStamp = [iTools getNowTimeStamp]; [self archTaskFileStream]; HLog(@"POST之后——--文件名:%@ 已上传完进度:%.2f 上传状态:%ld", self->_fileStream.fileName, self->_fileStream.progressRate, self->_fileStream.fileStatus); // 上传完成通知 刷新完成列表 dispatch_async(dispatch_get_main_queue(), ^{ if (self->_finishBlock) self->_finishBlock(self->_fileStream,nil); [self sendNotionWithKey:CWUploadTaskExeEnd userInfo:@{@"fileStream":self->_fileStream}]; }); }else { // 分片上传成功 不是最后一片 上传中 if (self->_fileStream.uploadDateSize > self->_chunkNo * CWStreamFragmentMaxSize) { // 上传进度异常 HLog(@"上传进度异常"); }else { // self->_fileStream.fileStatus = CWUploadStatusUpdownloading; self->_fileStream.progressRate = self->_chunkNo * 1.00 / self->_fileStream.streamFragments.count; self->_fileStream.uploadDateSize = self->_chunkNo * CWStreamFragmentMaxSize; self->_fileStream.timeStamp = [iTools getNowTimeStamp]; [self archTaskFileStream]; HLog(@"POST之后——--文件名:%@ 已上传完进度:%.2f 上传状态:%ld", self->_fileStream.fileName, self->_fileStream.progressRate, self->_fileStream.fileStatus); // 上传中通知 刷新上传进度 dispatch_async(dispatch_get_main_queue(), ^{ if (self->_finishBlock) self->_finishBlock(self->_fileStream,nil); [self sendNotionWithKey:CWUploadTaskExeing userInfo:@{@"fileStream":self->_fileStream,@"lastParam":self->_lastParam,@"indexNo":@(self->_chunkNo)}]; }); } /// 继续GET [self getFileInfo]; } [self deallocSession]; }); dispatch_semaphore_signal(semaphore); } faild:^(NSError * _Nonnull error) { if (self->_taskRepeatNum_taskRepeatNum++; [self startExe]; }else{ // 分片上传失败 self->_fileStream.fileStatus = CWUploadStatusFailed; // self->_fileStream.progressRate = (self->_chunkNo-1) / self->_fileStream.streamFragments.count; // self->_fileStream.uploadDateSize = (self->_chunkNo-1) * CWStreamFragmentMaxSize; self->_fileStream.timeStamp = [iTools getNowTimeStamp]; [self archTaskFileStream]; HLog(@"POST之后——--文件名:%@ 已上传完进度:%.2f 上传状态:%ld", self->_fileStream.fileName, self->_fileStream.progressRate, self->_fileStream.fileStatus); // 分片上传失败通知 刷新列表 dispatch_async(dispatch_get_main_queue(), ^{ if (self->_finishBlock) self->_finishBlock(self->_fileStream,error); [self sendNotionWithKey:CWUploadTaskExeError userInfo:@{@"fileStream":self->_fileStream,@"error":error}]; }); [self deallocSession]; return; } }]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); } }); break; } } dispatch_group_notify(group, queue, ^{ if (self->_fileStream.progressRate != 1) { HLog(@"dispatch_group_notify: %.2f", self->_fileStream.progressRate); return; } self->_fileStream.fileStatus = CWUploadStatusFinished; self->_fileStream.timeStamp = [iTools getNowTimeStamp]; [self archTaskFileStream]; dispatch_async(dispatch_get_main_queue(), ^{ if (self->_finishBlock) self->_finishBlock(self->_fileStream,nil); [self sendNotionWithKey:CWUploadTaskExeEnd userInfo:@{@"fileStream":self->_fileStream}]; }); [self deallocSession]; }); */ } - (void)taskResume{ _isSuspendedState = NO; if (self.uploadManager.uploadingTasks.allValues.count >= self.uploadManager.uploadMaxNum) { // 超过最大限制数量3个 self.fileStream.fileStatus = CWUploadStatusWaiting; [self archTaskFileStream]; HLog(@"状态修改——--文件名:%@ 已上传完进度:%.2f 上传状态:%ld", self.fileStream.fileName, self.fileStream.progressRate, self.fileStream.fileStatus); dispatch_async(dispatch_get_main_queue(), ^{ if (self->_successBlock) self->_successBlock(self->_fileStream); [self sendNotionWithKey:CWUploadTaskExeSuspend userInfo:@{@"fileStream":self->_fileStream}]; }); return; }else { self.fileStream.fileStatus = CWUploadStatusUpdownloading; [self archTaskFileStream]; HLog(@"状态修改——--文件名:%@ 已上传完进度:%.2f 上传状态:%ld", self.fileStream.fileName, self.fileStream.progressRate, self.fileStream.fileStatus); dispatch_async(dispatch_get_main_queue(), ^{ if (self->_successBlock) self->_successBlock(self->_fileStream); [self sendNotionWithKey:CWUploadTaskExeing userInfo:@{@"fileStream":self->_fileStream}]; }); [self getFileInfo]; // 启动上传任务 先get 后post } } - (void)taskCancel{ _fileStream.fileStatus = CWUploadStatusPaused; [self archTaskFileStream]; _isSuspendedState = YES; dispatch_async(dispatch_get_main_queue(), ^{ if (self->_finishBlock) self->_finishBlock(self->_fileStream,nil); [self sendNotionWithKey:CWUploadTaskExeSuspend userInfo:@{@"fileStream":self->_fileStream}]; }); } - (void)deallocSession{ _taskRepeatNum = 0; } #pragma mark -- tools - (void)archTaskFileStream{ NSArray *fileArray = [self->_fileStream.filePath pathComponents]; NSString *filePathAccount = @"0"; if (fileArray.count > 3) { filePathAccount = fileArray[fileArray.count - 3]; } NSArray *plistArray = [[CWFileUploadManager shardUploadManager].plistPath pathComponents]; NSString *plistPathAccount = @"1"; if (plistArray.count > 3) { plistPathAccount = plistArray[plistArray.count - 3]; } // HLog(@"文件缓存账号:%@ 与 plist文件账号:%@", filePathAccount, plistPathAccount); if (![filePathAccount isEqualToString:plistPathAccount]) { // HLog(@"切换账号 文件缓存账号%@ 与 plist文件账号:%@ 不一致", filePathAccount, plistPathAccount); return; } NSMutableDictionary *fsDic = [CWUploadTask unArcherThePlist:[CWFileUploadManager shardUploadManager].plistPath]; if (!fsDic) { fsDic = [NSMutableDictionary dictionary]; } [fsDic setObject:_fileStream forKey:_fileStream.fileName]; [CWUploadTask archerTheDictionary:fsDic file:[CWFileUploadManager shardUploadManager].plistPath]; } //归档 + (void)archerTheDictionary:(NSDictionary *)dict file:(NSString *)path{ NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dict]; BOOL finish = [data writeToFile:path atomically:YES]; if (finish) {}; } //解档 + (NSMutableDictionary *)unArcherThePlist:(NSString *)path{ NSMutableDictionary *dic = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; return dic; } - (void)sendNotionWithKey:(NSString *)key userInfo:(NSDictionary *)dict{ //创建通知 NSNotification *notification =[NSNotification notificationWithName:key object:nil userInfo:dict]; //通过通知中心发送通知 [[NSNotificationCenter defaultCenter] postNotification:notification]; } @end