// // downloadManager.m // 隐私保护 // // Created by xd h on 2024/1/9. // #import "downloadManager.h" #import "cachesFileManager.h" #import "AFNetworkReachabilityManager.h" @interface downloadManager () /**检测任务10s后 无反馈重新开始 */ @property (nonatomic, assign) NSInteger taskRenewTime; // @end @implementation downloadManager static downloadManager * cur_downloadManager = nil; +(downloadManager *)shareInstance; { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ cur_downloadManager = [[downloadManager alloc] init]; }); return cur_downloadManager; } - (id)init { self = [super init]; if (self) { //[self initManager]; } return self; } #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), ^{ // NSLock *lock = [NSLock new]; // [lock lock]; [couldPhoneFileModel bg_findAsync:download_tableName limit:0 orderBy:nil desc:YES complete:^(NSArray * _Nullable array) { NSMutableArray *failArr = [NSMutableArray new]; NSMutableArray *doneArr = [NSMutableArray new]; NSMutableArray *otherArr = [NSMutableArray new]; if(array && array.count >0){ for (couldPhoneFileModel * curModel in array) { if(curModel.curDownloadStateType == downloadStateFail){ [failArr addObject:curModel]; } else if(curModel.curDownloadStateType == downloadStateDone){ [doneArr addObject:curModel]; } else{ [otherArr addObject:curModel]; } } } NSLock *lock = [NSLock new]; [lock lock]; NSMutableArray *newArr = [NSMutableArray new]; [newArr addObject:otherArr]; [newArr addObject:doneArr]; [newArr addObject:failArr]; self->_databaseArr = newArr; [lock unlock]; complete(self->_databaseArr); }]; // [lock unlock]; //}); } -(void)handleCouldPhoneFileModelToDownloadFileDataFunBy:(NSMutableArray*)indexPathsForSelectedItems complete:(custom_complete_Arr)complete { if(!indexPathsForSelectedItems && indexPathsForSelectedItems.count == 0){ complete(nil); 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; } for (couldPhoneFileModel*model in indexPathsForSelectedItems) { model.bg_tableName = download_tableName; } _isNewAddTaskType = YES; KWeakSelf //查 [self getDataInDatabaseFun:YES complete:^(NSMutableArray * _Nonnull Arr) { //排重 NSMutableArray *newDownArr = [weakSelf checkDownloadTaskRepeatFun:indexPathsForSelectedItems]; if(newDownArr.count>0){ //存 [couldPhoneFileModel bg_saveOrUpdateArrayAsync:newDownArr complete:^(BOOL isSuccess) { //再查 [weakSelf getDataInDatabaseFun:YES complete:^(NSMutableArray * _Nonnull Arr) { complete(Arr); [weakSelf planToDownloadFileFun]; }]; }]; } else{ complete(Arr); [weakSelf planToDownloadFileFun]; } }]; } #pragma mark 检测是否有下载任务重复 - (NSMutableArray*)checkDownloadTaskRepeatFun:(NSMutableArray*)indexPathsForSelectedItems { if(!_databaseArr || _databaseArr.count != 3){ return indexPathsForSelectedItems; } NSMutableArray *downloadArr = _databaseArr[0]; NSMutableArray *newTaskArr = [NSMutableArray new]; for (couldPhoneFileModel*model in indexPathsForSelectedItems) { NSString *fileName = [model getFileNameFun]; BOOL isNeedAddType = YES; for (couldPhoneFileModel* hadModel in downloadArr) { NSString *hadFileName = [hadModel getFileNameFun]; if([fileName isEqualToString:hadFileName]){ isNeedAddType = NO; break; } } if(isNeedAddType){ [newTaskArr addObject:model]; } } return newTaskArr; } - (void)planToDownloadFileFun { if(!_databaseArr || _databaseArr.count != 3){ return; } _downLoadFileModelDataArr = [NSMutableArray arrayWithArray:_databaseArr[0]]; [self beginDownloadFileFun]; } - (void)beginDownloadFileFun { if(_downLoadFileModelDataArr.count == 0) { [self didDownloadAllTaskDoneFun]; return; } BOOL isCanUseCellular = [HWDataManager getBoolWithKey:stringKeyAddSn(Const_file_Transfe_canUse_Cellular_all)]; if(!isCanUseCellular){//不允许流量上传 // if([AFNetworkReachabilityManager sharedManager].networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN){ mainBlock(^{ [[NSNotificationCenter defaultCenter] postNotificationName:downloadFileSuspendAllNotification 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; } self.taskRenewTime = [iTools getNowTimeStamp]; _isSuspendType = NO; _isDownloadIngType = YES; if(_reDownloadIngSelectIndex > 0 && _reDownloadIngSelectIndex < _downLoadFileModelDataArr.count){ _curDownloadFileModel = _downLoadFileModelDataArr[_reDownloadIngSelectIndex]; } else { _curDownloadFileModel = _downLoadFileModelDataArr.firstObject; } if(!_curDownloadFileModel){ return; } // //做个异常处理 // if(_databaseArr.count == 3 && _isNewAddTaskType){ // NSMutableArray *downloadIngArr = _databaseArr[0]; // if(_downLoadFileModelDataArr.count != downloadIngArr.count){ // _databaseArr[0] = [NSMutableArray arrayWithArray:_downLoadFileModelDataArr]; // } // } if(![iTools checkFreeDiskSpaceInBytesIsOK:_curDownloadFileModel.length]){ mainBlock(^{ [[iToast makeText:NSLocalizedString(@"phone_space_Insufficient",nil)] show]; }); return; } _curDownloadFileModel.curDownloadStateType = downloadStateUploading; [[webSocketManager shareInstance] begindownloadFileFunBy:_curDownloadFileModel]; } - (void)DownloadFileDoneOneFileFun { self.taskRenewTime = [iTools getNowTimeStamp]; _curDownloadFileModel.curDownloadStateType = downloadStateDone; // NSString *fileName = [_curDownloadFileModel getFileNameFun]; // [cachesFileManager removeItemAtPath:fileName type:DownLoadFileType error:nil]; //1.先做数据保存 NSDictionary *dataDict = [_curDownloadFileModel downLoadInfoWithFinished:YES]; [self saveFileInfoWithDict:dataDict with:_curDownloadFileModel.path]; [self DownloadFileChangeingOneFileFun]; if(_isSuspendType){ return; } [self beginDownloadFileFun]; } - (void)DownloadFileFailOneFileFun { self.taskRenewTime = [iTools getNowTimeStamp]; _curDownloadFileModel.curDownloadStateType = downloadStateFail; [self DownloadFileChangeingOneFileFun]; if(_isSuspendType){ return; } [self beginDownloadFileFun]; } - (void)DownloadFileChangeingOneFileFun { self.taskRenewTime = [iTools getNowTimeStamp]; if(_curDownloadFileModel.curDownloadStateType == downloadStateDone){ [_downLoadFileModelDataArr removeObject:_curDownloadFileModel]; [self handleDatabaseArrDeleteObjectInDownloading:_curDownloadFileModel]; [self handleDatabaseArrAddObjectInDone:_curDownloadFileModel]; } else if(_curDownloadFileModel.curDownloadStateType == uploadStateFail){ [_downLoadFileModelDataArr removeObject:_curDownloadFileModel]; [self handleDatabaseArrDeleteObjectInDownloading:_curDownloadFileModel]; [self handleDatabaseArrAddObjectInFail:_curDownloadFileModel]; } [_curDownloadFileModel bg_saveOrUpdateAsync:^(BOOL isSuccess) { //HLog(@"%@ 写入 %@", model.filename, isSuccess ? @"成功":@"失败"); }]; if(!_isSuspendType || _curDownloadFileModel.curDownloadStateType != uploadStateSuspend){ [[NSNotificationCenter defaultCenter] postNotificationName:downloadFileRefreshNotification object:_curDownloadFileModel]; } } - (void)handleDatabaseArrDeleteObjectInDownloading:(couldPhoneFileModel*)model { NSLock *lock = [NSLock new]; [lock lock]; if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *ingArr = _databaseArr[0]; NSInteger count = ingArr.count; [ingArr removeObject:model]; NSInteger atferDelCount = ingArr.count; if(count == atferDelCount){ for (couldPhoneFileModel*preModel in ingArr) { if(preModel.bg_id.integerValue == model.bg_id.integerValue){ [ingArr removeObject:preModel]; break; } } } NSInteger atferDelCount2 = ingArr.count; if(count == atferDelCount2){ // HLog(@"\n\n\nerror:下载中的任务没有删除掉database bgid:%@\n\n\n\n",model.bg_id); } } [lock unlock]; } - (void)handleDatabaseArrAddObjectInDone:(couldPhoneFileModel*)model { NSLock *lock = [NSLock new]; [lock lock]; if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *doneArr = _databaseArr[1]; if(model){ [doneArr insertObject:model atIndex:0]; } } [lock unlock]; } - (void)handleDatabaseArrAddObjectInFail:(couldPhoneFileModel*)model { NSLock *lock = [NSLock new]; [lock lock]; if(_databaseArr && _databaseArr.count == 3 ){ NSMutableArray *failArr = _databaseArr[2]; if(model){ [failArr insertObject:model atIndex:0]; } } [lock unlock]; } - (void)suspendDownloadFileFun:(BOOL)isSuspendAll withModel:(couldPhoneFileModel*)model { if(isSuspendAll){ _isSuspendType = YES; [[NSNotificationCenter defaultCenter] postNotificationName:downloadFileSuspendAllNotification object:nil]; // for (couldPhoneFileModel *couldPhoneFileMod in _downLoadFileModelDataArr) { // couldPhoneFileMod.curDownloadStateType = downloadStateSuspend; // } [self changeDownloadState:downloadStateSuspend withModelArr:_downLoadFileModelDataArr complete:^(BOOL isSuccess) { [self->_downLoadFileModelDataArr removeAllObjects]; }]; } else{ couldPhoneFileModel *curModel = _curDownloadFileModel; if(model){ curModel = model; } else{ _isSuspendType = YES; } [self changeDownloadState:downloadStateSuspend withModelArr:@[curModel] complete:^(BOOL isSuccess) { [self->_downLoadFileModelDataArr removeObject:model]; if(curModel.bg_id.integerValue == self->_curDownloadFileModel.bg_id.integerValue){ //开启下一个任务 _reDownloadIngSelectIndex = -1; [self beginDownloadFileFun]; } }]; } } - (void)reDownloadFileFunBy:(NSMutableArray*)Arr withAll:(BOOL)isAllType { if(!_downLoadFileModelDataArr){ _downLoadFileModelDataArr = [NSMutableArray new]; } if(isAllType) { _isNewAddTaskType = YES; _downLoadFileModelDataArr = [NSMutableArray arrayWithArray:Arr]; _reDownloadIngSelectIndex = -1; } else{ _isNewAddTaskType = NO; _reDownloadIngSelectIndex = 0; NSMutableArray *curArr = [NSMutableArray arrayWithArray:Arr]; for (uploadFileDataModel*addModel in curArr){ [_downLoadFileModelDataArr insertObject:addModel atIndex:0]; } } [self changeDownloadState:downloadStateUploading withModelArr:_downLoadFileModelDataArr complete:^(BOOL isSuccess) { }]; [self beginDownloadFileFun]; } - (void)handleDatabaseArrByDelete:(couldPhoneFileModel*)delModel { if(_databaseArr && _databaseArr.count == 3 ){ if(delModel.curDownloadStateType == downloadStateDone) { NSMutableArray *arr = _databaseArr[1]; [arr removeObject:delModel]; } else if(delModel.curDownloadStateType == downloadStateFail){ NSMutableArray *arr = _databaseArr[2]; [arr removeObject:delModel]; } else{ NSMutableArray *arr = _databaseArr[0]; [arr removeObject:delModel]; } } } - (void)deleteDownloadFileRecordBy:(NSMutableArray *)delArr withDelCache:(BOOL)isDelCache { //逻辑待优化 BOOL isSuc = false; BOOL isDelUploadingModel = false; NSMutableArray *curDelArr = [NSMutableArray arrayWithArray:delArr]; for (couldPhoneFileModel *couldPhoneFileMod in curDelArr) { NSMutableString* where = [[NSMutableString alloc] initWithString:@"where "]; NSString *curStr = [NSString stringWithFormat:@"%@=%@ ",bg_sqlKey(@"bg_id"),bg_sqlValue(couldPhoneFileMod.bg_id)]; [where appendString:curStr]; [couldPhoneFileModel bg_deleteAsync:download_tableName where:where complete:^(BOOL isSuccess) { }]; //isSuc = [couldPhoneFileModel bg_delete:download_tableName where:where]; [self handleDatabaseArrByDelete:couldPhoneFileMod]; if(couldPhoneFileMod.bg_id.integerValue == _curDownloadFileModel.bg_id.integerValue){ isDelUploadingModel = YES; [self suspendDownloadFileFun:NO withModel:_curDownloadFileModel]; } } if(isDelUploadingModel){ _isDownloadIngType = NO; if(_downLoadFileModelDataArr > 0){ [self beginDownloadFileFun]; } } [[NSNotificationCenter defaultCenter] postNotificationName:downloadFileRefreshNotification object:_curDownloadFileModel]; } //修改文件上传的状态 - (void)changeDownloadState:(downloadStateType)curDownloadStateType withModelArr:(NSArray*)modelArr complete:(custom_complete_B)complete { for (couldPhoneFileModel * model in modelArr) { model.curDownloadStateType = curDownloadStateType; } if(modelArr.count == 0){ return; } [couldPhoneFileModel bg_saveOrUpdateArrayAsync:modelArr complete:^(BOOL isSuccess) { complete(YES); }]; } //检查是否需要重新下载 - (void)checkReDownloadFileFun { if(!_curDownloadFileModel){ return; } if(_isSuspendType){ return; } NSInteger curTime = [iTools getNowTimeStamp]; if(self.taskRenewTime == 0){ return; } if(curTime - self.taskRenewTime < 10){ return; } if(![iTools checkFreeDiskSpaceInBytesIsOK:_curDownloadFileModel.length]){ mainBlock(^{ [[iToast makeText:NSLocalizedString(@"phone_space_Insufficient",nil)] show]; }); _curDownloadFileModel = nil; return; } [[webSocketManager shareInstance] begindownloadFileFunBy:_curDownloadFileModel]; } - (BOOL)checkDownloadingFun { if(!_curDownloadFileModel){ return NO; } // if(_curDownloadFileModel.curDownloadStateType == downloadStateDone // ||_curDownloadFileModel.curDownloadStateType == downloadStateFail // ||_curDownloadFileModel.curDownloadStateType == downloadStateSuspend){ // return NO; // } if(_isSuspendType){ return NO; } return YES; } - (void)didDownloadAllTaskDoneFun { _curDownloadFileModel = nil; [[NSNotificationCenter defaultCenter] postNotificationName:downloadFileAllTaskDoneNotification object:nil]; } - (void)checkHadDownloadTaskWithComplete:(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); } } }); }]; } #pragma mark- ws download done plist Path - (NSString *)getDownloadDonePlistPath { NSString *fileFolder = [NSString stringWithFormat:@"%@/DownLoadFlie",CachesPatch];; return [fileFolder stringByAppendingPathComponent:@"webSocketDownloadDoneInfo.plist"];; } #pragma mark- download done plist - (NSMutableDictionary *)getDownloadDownList { if (!_downloadDoneList) { // 内存没有 _downloadDoneList = [[NSDictionary dictionaryWithContentsOfFile:[self getDownloadDonePlistPath]] mutableCopy]; // 本地加载 if (!_downloadDoneList) { // 本地没有,分配内存 _downloadDoneList = [NSMutableDictionary dictionary]; } } return _downloadDoneList; } /** 增加配置信息 */ - (BOOL)saveFileInfoWithDict:(NSDictionary *)dict with:(NSString*)url { HLog(@"saveFileInfoWithDict:%@",url) if(!dict || !url){ return NO; } BOOL flag = NO; @synchronized (self) { NSString *key = url; NSMutableDictionary *dictM = [self getDownloadDownList]; [dictM setObject:dict forKey:key]; flag = [dictM writeToFile:[self getDownloadDonePlistPath] atomically:YES]; } return flag; } /** 删除配置信息 */ - (BOOL)deleteFileInfoWithUrl:(NSString *)url { if(!url){ return NO; } BOOL flag = NO; @synchronized (self) { NSMutableDictionary *dictM = [self getDownloadDownList]; [dictM removeObjectForKey:url]; flag = [dictM writeToFile:[self getDownloadDonePlistPath] atomically:YES]; } return flag; } #pragma mark-保存完成后 删除此次信息 download done plist - (void)deleteDownloadDonePlistInfoBy:(NSString*)fullPath { HLog(@"deleteDownloadDonePlistInfoBy:%@",fullPath) NSMutableDictionary *dictM = [self getDownloadDownList]; for (NSString*key in dictM) { NSDictionary*dict = dictM[key]; if ([[dict allKeys] containsObject:@"fullPath"]) { NSString * infofullPath = dict[@"fullPath"]; if([fullPath isEqualToString:infofullPath]){ [self deleteFileInfoWithUrl:key]; break; } } } } #pragma mark-查询还有没有没处理的任务 - (void)checkDownloadDonePlistInfoFun { NSMutableDictionary *dictM = [[self getDownloadDownList] mutableCopy]; if(dictM.count > 0){ for (NSString*key in dictM) { NSDictionary*dict = dictM[key]; couldPhoneFileModel *model = [couldPhoneFileModel mj_objectWithKeyValues:dict]; NSString *fileName = [model getFileNameFun]; NSString*fullPath = [cachesFileManager getFilePathWithName:fileName type:DownLoadFileType]; //判断文件是否还存在 if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath]) { //不存在 删除信息 HLog(@"deleteFileInfoWithUrl:%@",key) [self deleteFileInfoWithUrl:key]; } else{//存在 通知保存流程 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [[webSocketManager shareInstance] saveDownDoneFileToPhoneFunBy:fullPath withKey:model.path]; }); break; } } } } @end