// // nasUploadFileManager.m // 双子星云手机 // // Created by xd h on 2024/8/7. // #import "nasUploadFileManager.h" #import "nasUploadManager.h" @implementation nasUploadFileManager + (instancetype)shareInstance { static nasUploadFileManager *_instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } - (id)init { self = [super init]; if (self) { [self initManager]; } return self; } - (void)initManager { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(uploadTaskFinishedNoti:) name:nasUploadTaskExeEnd object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(uploadTaskErrorNoti:) name:nasUploadTaskExeError object:nil]; } #pragma mark 读取数据库数据 - (void)getDataInDatabaseFun:(BOOL)isReGet complete:(custom_complete_Arr)complete { if(_databaseArr && _databaseArr.count == 3 && !isReGet){ complete(_databaseArr); return; } if(!_databaseArr) { _databaseArr = [NSMutableArray new]; } //KWeakSelf dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{ HLog(@"begin bg_findAsync"); [uploadFileDataModel bg_findAsync:nasUpLoadFile_tableName limit:0 orderBy:nil desc:YES complete:^(NSArray * _Nullable array) { HLog(@"end bg_findAsync"); NSMutableArray *failArr = [NSMutableArray new]; NSMutableArray *doneArr = [NSMutableArray new]; NSMutableArray *otherArr = [NSMutableArray new]; for (uploadFileDataModel * curModel in array) { //图片 和视频 还原 if(curModel.curUploadFileType == uploadFileTypeImage){ } else if(curModel.curUploadFileType == uploadFileTypeVideo){ if(curModel.curUploadStateType != uploadStateDone){ } } if(curModel.curUploadStateType == uploadStateFail){ [failArr addObject:curModel]; } else if(curModel.curUploadStateType == uploadStateDone){ [doneArr addObject:curModel]; } else{ [otherArr addObject:curModel]; } } NSMutableArray *newArr = [NSMutableArray new]; [newArr addObject:otherArr]; [newArr addObject:doneArr]; [newArr addObject:failArr]; self->_databaseArr = newArr; complete(self->_databaseArr); }]; }); } //把TZAssetModel 转成 我们需要上传的model - (void)handlTZAssetModelToUploadFileDataFunBy:(NSMutableArray*)indexPathsForSelectedItems complete:(custom_complete_Arr)complete { if(!indexPathsForSelectedItems && indexPathsForSelectedItems.count == 0){ complete(_databaseArr); 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]; } complete(_databaseArr); return; } _isNewAddTaskType = YES; //self.curUploadModelNumbers = indexPathsForSelectedItems.count; NSMutableArray *newUploadTaskArr = [NSMutableArray new]; for (TZAssetModel * model in indexPathsForSelectedItems) { uploadFileDataModel * curModel = [uploadFileDataModel new]; curModel.asset = model.asset; curModel.localIdentifier = model.asset.localIdentifier; BOOL isRepeatingTasksType = NO; //查询上传任务是否存在 if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *uploadingArr = [[NSMutableArray alloc] initWithArray:_databaseArr[0]]; for (uploadFileDataModel *preModel in uploadingArr) { if([preModel.localIdentifier isEqualToString:curModel.localIdentifier]){ isRepeatingTasksType = YES; break; } } } if(isRepeatingTasksType){ continue; } NSString * uploadDefaultPath = [HWDataManager getStringWithKey:stringKeyAddSn(Const_photo_upload_default_path)]; if(!uploadDefaultPath || uploadDefaultPath.length == 0){ [HWDataManager setStringWithKey:stringKeyAddSn(Const_photo_upload_default_path) value:Const_default_upload_path]; uploadDefaultPath = Const_default_upload_path; } //判断最后一个是否是/ NSString *lastStr= [uploadDefaultPath substringFromIndex:uploadDefaultPath.length-1]; if(![lastStr isEqualToString:@"/"]){ uploadDefaultPath = [[NSString alloc] initWithFormat:@"%@/",uploadDefaultPath]; } //NSString*savePath = [[NSString alloc] initWithFormat:@"%@%@",uploadDefaultPath,filePath]; curModel.savePath = uploadDefaultPath; // curModel.imageData = model.imageData; // curModel.videoData = model.videoData; curModel.filename = [model.asset valueForKey:@"filename"]; //curModel.curUploadStateType = uploadStateWait; curModel.curUploadStateType = uploadStateUploading; if(model.type == TZAssetModelMediaTypeVideo){ curModel.curUploadFileType = uploadFileTypeVideo; [cachesFileManager getFileNameWithContent:curModel.videoData fileName:curModel.filename type:uploadFileTypeVideo]; //curModel.totalBytes = [model.videoData length]; curModel.totalBytes = model.totalBytes; curModel.videoData = [NSData new];//视频文件存储到文件后内存清空 NSString *imgName1 = [curModel.filename stringByReplacingOccurrencesOfString:@"." withString:@"_"]; curModel.videoFirstImageName = [[NSString alloc] initWithFormat:@"%@.png",imgName1]; //第一帧图片 [[PHImageManager defaultManager] requestImageDataForAsset:curModel.asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { // 直接得到最终的 NSData 数据 if (imageData) { curModel.imageData = imageData; [cachesFileManager getFileNameWithContent:curModel.imageData fileName:curModel.videoFirstImageName type:uploadFileTypeImage]; } }]; } else{ curModel.curUploadFileType = uploadFileTypeImage; curModel.totalBytes = model.totalBytes; if(curModel.imageData) { [cachesFileManager getFileNameWithContent:curModel.imageData fileName:curModel.filename type:uploadFileTypeImage]; curModel.imageData = nil; } else{ } } //保存到数据库 curModel.bg_tableName = nasUpLoadFile_tableName; [newUploadTaskArr addObject:curModel]; } KWeakSelf if(newUploadTaskArr.count == 0){ [self getDataInDatabaseFun:YES complete:^(NSMutableArray * _Nonnull Arr) { complete(Arr); [weakSelf handleUploadFileModelBg_idFun:Arr]; }]; } else{ [uploadFileDataModel bg_saveOrUpdateArrayAsync:newUploadTaskArr complete:^(BOOL isSuccess) { [weakSelf getDataInDatabaseFun:YES complete:^(NSMutableArray * _Nonnull Arr) { complete(Arr); [weakSelf handleUploadFileModelBg_idFun:Arr]; }]; }]; } } #pragma mark 处理当前的model 加上bg_id - (void)handleUploadFileModelBg_idFun:(NSMutableArray*)totalArr { if(!totalArr || totalArr.count != 3){ return; } NSMutableArray* uploadTaskArr = [NSMutableArray arrayWithArray:totalArr[0]]; //多任务同时进行模式 if(uploadTaskArr.count >0){ [[nasMixUploadManager shareManager] addUploadWithModels:uploadTaskArr]; } } #pragma mark 上传完成 - (void)uploadTaskFinishedNoti:(NSNotification *)notification { uploadFileDataModel *model = notification.object; if(!model)return; model.curUploadStateType = uploadStateDone; [self nasUploadFileChangeingOneFileFunBy:model]; [self deleteCacheDataBy:model]; } #pragma mark 上传失败 - (void)uploadTaskErrorNoti:(NSNotification *)notification { uploadFileDataModel *model = notification.object; if(!model)return; model.curUploadStateType = uploadStateFail; [self nasUploadFileChangeingOneFileFunBy:model]; [self deleteCacheDataBy:model]; } #pragma mark 上传完成 清理缓存 - (void)deleteCacheDataBy:(uploadFileDataModel*)uploadFileDataMod { HLog(@"上传--清理缓存") uploadFileDataMod.imageData = nil; uploadFileDataMod.videoData = nil; if(uploadFileDataMod.curUploadFileType == uploadFileTypeVideo){ [cachesFileManager removeItemAtPath:uploadFileDataMod.filename type:uploadFileTypeVideo error:nil]; } uploadFileDataMod = nil; } #pragma mark 更新数据状态 - (void)nasUploadFileChangeingOneFileFunBy:(uploadFileDataModel*)dataModel { //test code //return; HLog(@"更新数据状态") if(dataModel.curUploadStateType == uploadStateDone){ [self handleDatabaseArrDeleteObjectInUploading:dataModel]; [self handleDatabaseArrAddObjectInDone:dataModel]; } else if(dataModel.curUploadStateType == uploadStateFail){ if (!_databaseArr || _databaseArr.count != 3) { return; } //删除操作导致的失败 NSMutableArray *ingArr = _databaseArr[0]; NSInteger count = ingArr.count; if(count == 0){ return; } [self handleDatabaseArrDeleteObjectInUploading:dataModel]; [self handleDatabaseArrAddObjectInFail:dataModel]; } else{ //[cachesFileManager writeLogsWithMsg:@"nasUploadFileChangeingOneFileFunBy else"]; } dataModel.bg_tableName = nasUpLoadFile_tableName; [dataModel bg_saveOrUpdateAsync:^(BOOL isSuccess) { HLog(@"%@ 写入 %@", dataModel.filename, isSuccess ? @"成功":@"失败"); }]; // if(_databaseArr.count == 3) // { // NSMutableArray *ingArr = _databaseArr[0]; // NSMutableArray* doneArr = _databaseArr[1]; // NSMutableArray* failArr = _databaseArr[2]; // // NSString *logstr = [[NSString alloc] initWithFormat:@"nasUploadFileChangeingOneFileFunBy ing:%ld,done:%ld,fail:%ld---total:%ld",ingArr.count,doneArr.count,failArr.count,ingArr.count + doneArr.count +failArr.count]; // [cachesFileManager writeLogsWithMsg:logstr]; // } if(!_isSuspendType || dataModel.curUploadStateType != uploadStateSuspend){ HLog(@"nasUploadFileChangeingOneFileFunBy uploadFileRefreshNotification") [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileRefreshNotification object:dataModel]; } } #pragma mark 删除上传中的任务 - (void)handleDatabaseArrDeleteObjectInUploading:(uploadFileDataModel*)model { HLog(@"删除上传中的任务") @synchronized (self) { if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *ingArr = _databaseArr[0]; NSInteger count = ingArr.count; [ingArr removeObject:model]; NSInteger atferDelCount = ingArr.count; if(count == atferDelCount){ // NSString* logStr = [[NSString alloc] initWithFormat:@"DeleteObjectInUploading error begin %ld--model:%@--%@",ingArr.count,model,model.filename]; // HLog(@"%@",logStr) // [cachesFileManager writeLogsWithMsg:logStr]; for (uploadFileDataModel*preModel in ingArr) { if(preModel.bg_id.integerValue == model.bg_id.integerValue){ if (//[preModel.filename isEqualToString:model.filename]&& [preModel.localIdentifier isEqualToString:model.localIdentifier]) { [ingArr removeObject:preModel]; }else{ // NSString* logStr22 = [[NSString alloc] initWithFormat:@"filename error %@",preModel.filename]; // [cachesFileManager writeLogsWithMsg:logStr22]; } break; } } NSString* logStr2 = [[NSString alloc] initWithFormat:@"DeleteObjectInUploading error end %ld",ingArr.count]; HLog(@"%@",logStr2) //[cachesFileManager writeLogsWithMsg:logStr2]; } } } } #pragma mark 添加任务到上传完成 - (void)handleDatabaseArrAddObjectInDone:(uploadFileDataModel*)model { HLog(@"添加任务到上传完成") @synchronized (self) { if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *doneArr = _databaseArr[1]; if(model){ [doneArr insertObject:model atIndex:0]; } } } } #pragma mark 添加任务到上传失败 - (void)handleDatabaseArrAddObjectInFail:(uploadFileDataModel*)model { HLog(@"添加任务到上传失败") @synchronized(self){ if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *failArr = _databaseArr[2]; if(model){ [failArr insertObject:model atIndex:0]; } } } } #pragma mark 上传完成所有任务 - (void)didUploadAllTaskDoneFun { //self->_isUploadIngType = NO; [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileAllTaskDoneNotification object:nil]; } #pragma mark 删除内存数据记录 - (void)handleDatabaseArrByDelete:(uploadFileDataModel*)delModel { if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *uploadingArr = nil; if(delModel.curUploadStateType == uploadStateUploading ||delModel.curUploadStateType == uploadStateSuspend ||delModel.curUploadStateType == uploadStateWait){ uploadingArr = _databaseArr[0]; } else if(delModel.curUploadStateType == uploadStateDone) { uploadingArr = _databaseArr[1]; } else{ uploadingArr = _databaseArr[2]; } [uploadingArr removeObject:delModel]; } } #pragma mark 删除本地数据库记录 - (void)deleteUploadFileRecordBy:(NSMutableArray *)delArr withDelCache:(BOOL)isDelCache complete:(custom_complete_B)complete { // BOOL isDelUploadingModel = NO; NSMutableArray *curDelArr = [NSMutableArray arrayWithArray:delArr]; for (uploadFileDataModel *uploadFileDataMod in curDelArr) { //1.删除数据库 NSMutableString* where = [[NSMutableString alloc] initWithString:@"where "]; NSString *curStr = [NSString stringWithFormat:@"%@=%@ ",bg_sqlKey(@"bg_id"),bg_sqlValue(uploadFileDataMod.bg_id)]; [where appendString:curStr]; //isSuc = [uploadFileDataModel bg_delete:nasUpLoadFile_tableName where:where]; [uploadFileDataModel bg_deleteAsync:nasUpLoadFile_tableName where:where complete:^(BOOL isSuccess) { if(isSuccess){ } }]; // 2.删除内存数据 [self handleDatabaseArrByDelete:uploadFileDataMod]; //3.删除缓存的本地数据 if(isDelCache){ //判断是否可以删除本地缓存 if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *uploadingArr = _databaseArr[0]; NSMutableArray *uploadDoneArr = _databaseArr[1]; NSMutableArray *uploadFailArr = _databaseArr[2]; BOOL isNeedDel = YES; for (uploadFileDataModel *baseUploadFileDataMod in uploadingArr) { if([uploadFileDataMod.filename isEqualToString:baseUploadFileDataMod.filename] ){ isNeedDel = NO; break; } } if(isNeedDel){ for (uploadFileDataModel *baseUploadFileDataMod in uploadDoneArr) { if([uploadFileDataMod.filename isEqualToString:baseUploadFileDataMod.filename] ){ isNeedDel = NO; break; } } } if(isNeedDel){ for (uploadFileDataModel *baseUploadFileDataMod in uploadFailArr) { if([uploadFileDataMod.filename isEqualToString:baseUploadFileDataMod.filename] ){ isNeedDel = NO; break; } } } if(isNeedDel){ if(uploadFileDataMod.curUploadFileType == uploadFileTypeVideo){ [cachesFileManager removeItemAtPath:uploadFileDataMod.videoFirstImageName type:uploadFileTypeImage error:nil]; [cachesFileManager removeItemAtPath:uploadFileDataMod.filename type:uploadFileTypeVideo error:nil]; } else{ [cachesFileManager removeItemAtPath:uploadFileDataMod.filename type:uploadFileTypeImage error:nil]; } } } } if(!isDelCache){//上传报云机已经存在文件了 查询本地是否有任务记录 [self handleRetryUploadAndDelRecordFun:uploadFileDataMod]; } //是否在删除上传中的任务 if(uploadFileDataMod.curUploadStateType == uploadStateUploading){ [[nasMixUploadManager shareManager] cancelUploadTaskFunWith:uploadFileDataMod]; } } uploadFileDataModel *RefreshUploadFileDataMod = nil; if(delArr.count >= 1){ RefreshUploadFileDataMod = delArr.firstObject; } [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileRefreshNotification object:RefreshUploadFileDataMod]; complete(YES); } #pragma mark 处理重复上传文件的问题 - (void)handleRetryUploadAndDelRecordFun:(uploadFileDataModel *)uploadFileDataMod { @synchronized (self) { if (!_databaseArr || _databaseArr.count != 3) { return; } NSMutableArray * doneArr = _databaseArr[1]; NSMutableArray * failArr = _databaseArr[2]; BOOL isNeedDelType = YES; for (uploadFileDataModel *doneModel in doneArr) { if([doneModel.localIdentifier isEqualToString:uploadFileDataMod.localIdentifier]){ isNeedDelType = NO; break; } } if(isNeedDelType){ for (uploadFileDataModel *failModel in failArr) { if([failModel.localIdentifier isEqualToString:uploadFileDataMod.localIdentifier]){ isNeedDelType = NO; break; } } } if(isNeedDelType){ if(uploadFileDataMod.curUploadFileType == uploadFileTypeVideo){ [cachesFileManager removeItemAtPath:uploadFileDataMod.videoFirstImageName type:uploadFileTypeImage error:nil]; [cachesFileManager removeItemAtPath:uploadFileDataMod.filename type:uploadFileTypeVideo error:nil]; } else{ [cachesFileManager removeItemAtPath:uploadFileDataMod.filename type:uploadFileTypeImage error:nil]; } } else{//视频文件是要删除的 if(uploadFileDataMod.curUploadFileType == uploadFileTypeVideo){ [cachesFileManager removeItemAtPath:uploadFileDataMod.filename type:uploadFileTypeVideo error:nil]; } } } } - (void)checkHadUploadTaskWithComplete:(custom_complete_B)complete { [self getDataInDatabaseFun:NO complete:^(NSMutableArray * _Nonnull Arr) { mainBlock(^{ if(!Arr || Arr.count != 3){ complete(NO); } else{ NSArray *firstArr = Arr[0]; if(firstArr.count >0){ complete(YES); } else{ complete(NO); } } }); }]; } //文件重新上传 - (void)reUploadFileFunBy:(NSMutableArray*)Arr withAll:(BOOL)isAllType { if(!Arr || Arr.count == 0){ return; } //1.修改状态从失败改为上传中 for (uploadFileDataModel * model in Arr) { model.curUploadStateType = uploadStateUploading; //修改已经读取的内存数据 NSMutableArray * failArr = _databaseArr[2]; for (uploadFileDataModel * failModel in failArr) { if(model.bg_id.integerValue == failModel.bg_id.integerValue){ [failArr removeObject:failModel]; break; } } } //2、保存到数控库 [uploadFileDataModel bg_saveOrUpdateArrayAsync:Arr complete:^(BOOL isSuccess) { }]; //重新开始上传 [[nasMixUploadManager shareManager] addUploadWithModels:Arr]; } //暂停上传 当 isSuspendAll为NO时候 传指定暂停哪一个 - (void)suspendUploadFileFun:(BOOL)isSuspendAll withModel:(uploadFileDataModel*)model { //[[nasUploadManager shareInstance] cancelUploadTaskFun]; if (isSuspendAll) { [[nasMixUploadManager shareManager] cancelUploadAllTaskFun]; } else{ [[nasMixUploadManager shareManager] cancelUploadTaskFunWith:model]; } [self suspendUploadingTaskBy:isSuspendAll withModel:model]; } #pragma mark 暂停任务 - (void)suspendUploadingTaskBy:(BOOL)isDeleteAll withModel:(uploadFileDataModel*)model { NSMutableArray *uploadingArr = [NSMutableArray new]; if(!isDeleteAll){ if(model){ model.curUploadStateType = uploadStateSuspend; [uploadingArr addObject:model]; } } else { if (!_databaseArr || _databaseArr.count != 3) { return; } uploadingArr = _databaseArr[0]; for (uploadFileDataModel*preModel in uploadingArr) { preModel.curUploadStateType = uploadStateSuspend; } } if(uploadingArr.count > 0){ //更新数据库 [uploadFileDataModel bg_saveOrUpdateArrayAsync:uploadingArr complete:^(BOOL isSuccess) { }]; } } - (NSMutableArray*)uploadingArr { if(_databaseArr && _databaseArr.count == 3){ NSMutableArray *uploadingArr = _databaseArr[0]; return uploadingArr; } return [NSMutableArray new]; } //网络失败后任务暂时保存 - (void)saveUploadingTaskByNetWorkErrorFun { HLog(@"hxd saveUploadingTaskByNetWorkErrorFun") if(self.uploadingArr.count > 0){ [[nasMixUploadManager shareManager] cancelUploadAllTaskFun]; _needToReUploadTaskType = YES; } } //重新上传网络失败的任务 - (void)reUploadFileFunByNetWork { [nasUploadFileManager shareInstance].needToReUploadTaskType = NO; HLog(@"reUploadFileFunByNetWork") //[cachesFileManager writeLogsWithMsg:@"reUploadFileFunByNetWork"]; if(self.uploadingArr.count >0 && _databaseArr.count == 3){ // NSMutableArray* doneArr = _databaseArr[1]; // NSMutableArray* failArr = _databaseArr[2]; // // NSString *logstr = [[NSString alloc] initWithFormat:@"ing:%ld,done:%ld,fail:%ld",self.uploadingArr.count,doneArr.count,failArr.count]; // // [cachesFileManager writeLogsWithMsg:logstr]; //1.修改状态从失败改为上传中 // for (uploadFileDataModel * model in _netWorkFailSaveArr) { // model.curUploadStateType = uploadStateUploading; //// for (uploadFileDataModel * uploadingModel in self.uploadingArr){ //// if (model.bg_id.integerValue == uploadingModel.bg_id.integerValue) { //// uploadingModel.curUploadStateType = uploadStateUploading; //// continue; //// } //// } // } //2、保存到数控库 // [uploadFileDataModel bg_saveOrUpdateArrayAsync:_netWorkFailSaveArr complete:^(BOOL isSuccess) { // // }]; //3.判断是否可以上传 BOOL isCanUseCellular = [HWDataManager getBoolWithKey:stringKeyAddSn(Const_file_Transfe_canUse_Cellular_all)]; if(!isCanUseCellular){//不允许流量上传 // if([AFNetworkReachabilityManager sharedManager].networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN){ return; } } //4.重新开始上传 [[nasMixUploadManager shareManager] addUploadWithModels:self.uploadingArr]; } } @end