nasMixBackupsManager.m 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. //
  2. // nasMixBackupsManager.m
  3. // 双子星云手机
  4. //
  5. // Created by xd h on 2024/8/30.
  6. //
  7. #import "nasMixBackupsManager.h"
  8. #import "customUploadOperation.h"
  9. #import "nasUploadFileManager.h"
  10. #import "frpFileExistModel.h"
  11. #import "frpUploadModel.h"
  12. #define Kboundary3 @"Boundaryhxd"
  13. @interface nasMixBackupsManager ()<NSURLSessionDataDelegate>
  14. //排队等候下载的上传地址数组
  15. @property(nonatomic,strong) NSMutableArray *uploadWaitingUrlArr;
  16. //正在下载的上传地址数组
  17. @property(nonatomic,strong) NSMutableArray *uploadingOperationArr;
  18. @property(nonatomic,assign) NSInteger speedShowCount;//内网的情况 多少次才刷新一次
  19. @end
  20. @implementation nasMixBackupsManager
  21. + (instancetype)shareManager {
  22. static nasMixBackupsManager *_instance;
  23. static dispatch_once_t onceToken;
  24. dispatch_once(&onceToken, ^{
  25. _instance = [[self alloc] init];
  26. });
  27. return _instance;
  28. }
  29. - (instancetype)init {
  30. if (self = [super init]) {
  31. _maxUploadLoadCount = 1;
  32. if ([pingManager shareManager].isPingOk)
  33. {
  34. _speedShowCount = 3;
  35. }
  36. else{
  37. _speedShowCount = 0;
  38. }
  39. //[self registeNotification];
  40. }
  41. return self;
  42. }
  43. /** 添加要上传的 模型 */
  44. - (void)addBackupsWithModels:(NSArray *)fileModels{
  45. HLog(@"添加备份任务-- %ld",fileModels.count)
  46. for (uploadFileDataModel *model in fileModels) {
  47. BOOL needAddType = YES;
  48. //1. 排查上传中
  49. for (customUploadOperation *operationDoing in self.uploadingOperationArr) {
  50. if([operationDoing.fileModel.localIdentifier isEqualToString:model.localIdentifier]){
  51. needAddType = NO;
  52. break;
  53. }
  54. }
  55. //1. 排查等待下载
  56. for (uploadFileDataModel *waitModel in self.uploadWaitingUrlArr) {
  57. if([waitModel.localIdentifier isEqualToString:model.localIdentifier]){
  58. needAddType = NO;
  59. break;
  60. }
  61. }
  62. if(needAddType){
  63. [self.uploadWaitingUrlArr addObject:model];
  64. }
  65. }
  66. //启动上传
  67. [self beginUpload];
  68. }
  69. //在添加XX后 启动下载
  70. - (void)beginUpload
  71. {
  72. BOOL isCanUseCellular = [HWDataManager getBoolWithKey:stringKeyAddSn(Const_file_Transfe_canUse_Cellular_all)];
  73. if(!isCanUseCellular){//不允许流量上传
  74. //
  75. if([AFNetworkReachabilityManager sharedManager].networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN){
  76. mainBlock(^{
  77. [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileSuspendAllNotification object:nil];
  78. [[iToast makeText:NSLocalizedString(@"File_Transfer_By_Cellular_tip",nil)] show];
  79. });
  80. return;
  81. }
  82. }
  83. if(ksharedAppDelegate.DisabledFileTransferType){
  84. if(ksharedAppDelegate.isImageNewFor130){
  85. [[iToast makeText:NSLocalizedString(@"File_Transfer_Disable_tip",nil)] show];
  86. }
  87. else{
  88. [[iToast makeText:NSLocalizedString(@"File_Transfer_Disable_tip2",nil)] show];
  89. }
  90. return;
  91. }
  92. @synchronized (self) {
  93. if(self.uploadingOperationArr.count == _maxUploadLoadCount){
  94. HLog(@"正在上传的数量达到了最大值 %ld",_maxUploadLoadCount)
  95. return;
  96. }
  97. if(self.uploadWaitingUrlArr.count == 0){
  98. HLog(@"没有等待中的上传任务")
  99. return;
  100. }
  101. NSInteger canAddTaskNumber = _maxUploadLoadCount - self.uploadingOperationArr.count;
  102. for (int i=0; i<canAddTaskNumber; i++) {
  103. if(self.uploadWaitingUrlArr.count >= 1){
  104. //创建上传任务
  105. uploadFileDataModel *WaitingModel = self.uploadWaitingUrlArr.firstObject;
  106. __block customUploadOperation * operation = [customUploadOperation new];
  107. operation.fileModel = WaitingModel;
  108. //等待下载中的任务
  109. [self.uploadWaitingUrlArr removeObjectAtIndex:0];
  110. //添加到下载中数组
  111. [self.uploadingOperationArr addObject:operation];
  112. [self checkFileUploadStateWithOperation:operation];
  113. //[weakSelf handleTaskDidUploadWith:operation withState:state];
  114. }
  115. }
  116. }
  117. }
  118. #pragma mark 检测文件是否上传过了
  119. - (void)checkFileUploadStateWithOperation:(customUploadOperation*)operation
  120. {
  121. NSMutableDictionary*paraDict = [NSMutableDictionary new];
  122. if(operation.fileModel.savePath){
  123. NSString *absPath = [[NSString alloc] initWithFormat:@"%@%@",operation.fileModel.savePath,operation.fileModel.filename];
  124. [paraDict setValue:absPath forKey:@"absPath"];
  125. NSNumber *totalBytesNumber = [NSNumber numberWithLong:operation.fileModel.totalBytes];
  126. [paraDict setValue:totalBytesNumber forKey:@"fileSize"];
  127. }
  128. KWeakSelf
  129. [[netWorkManager shareInstance] cloudPhoneGETCallBackCode:@"isFileExist" Parameters:paraDict success:^(id _Nonnull responseObject) {
  130. frpFileExistModel *model = [[frpFileExistModel alloc] initWithDictionary:responseObject error:nil];
  131. if(model && model.status == 0){
  132. [weakSelf checkFileUploadStateFunAfterNetWith:model WithOperation:operation];
  133. }
  134. else if(model && model.status == 5){
  135. //备份路径
  136. NSString * backupsDefaultPath = [HWDataManager getStringWithKey:stringKeyAddSn(Const_photo_backups_default_path)];
  137. NSArray * stringArr = [backupsDefaultPath componentsSeparatedByString:@"/"];
  138. NSString *lastStr = stringArr.lastObject;
  139. NSString *repStr = [[NSString alloc] initWithFormat:@"/%@",lastStr];
  140. NSString *name = [backupsDefaultPath stringByReplacingOccurrencesOfString:repStr withString:@""];
  141. name = [iTools changePathToShowPathBy:name];
  142. NSString* showTip = [[NSString alloc] initWithFormat:@"【%@】%@",name,NSLocalizedString(@"disk_space_not_tip_for_95",nil)];
  143. [[iToast makeText:showTip] show];
  144. [weakSelf handleUploadFailOneFileBy:operation];
  145. NSString* failTip = [[NSString alloc] initWithFormat:@"【%@】%@",name,NSLocalizedString(@"disk_space_not_tip_for_95_fail_tip",nil)];
  146. [[nasBackupsManager shareInstance] changeBackupsFileStateToFailWith:failTip];
  147. }
  148. else{
  149. [weakSelf handleUploadFailOneFileBy:operation];
  150. //FileExistRet(-1);
  151. }
  152. } failure:^(NSError * _Nonnull error) {
  153. HLog(@"%@",error)
  154. //FileExistRet(-1);
  155. [weakSelf handleUploadFailOneFileBy:operation];
  156. }];
  157. }
  158. #pragma mark 检测分家是否存在后处理 是否要上传
  159. - (void)checkFileUploadStateFunAfterNetWith:(frpFileExistModel*)model WithOperation:(customUploadOperation*)operation
  160. {
  161. if(!model){
  162. [self handleUploadFailOneFileBy:operation];
  163. return;
  164. }
  165. operation.fileModel.didUploadBytes = 0;
  166. operation.fileModel.taskId = model.data.fileTaskId;
  167. if(!model.data.exist){//未上传过
  168. [self prepareToUploadFileWithOperation:operation];
  169. }
  170. else if(model.data.isComplete){//上传过了 并且文件上传完了
  171. //判断下文件创建长度是否一致 一致则是上传完了 不一致 重新上传一个 可能是同名的文件而已
  172. if(model.data.size >= operation.fileModel.totalBytes){//上传完了
  173. // mainBlock(^{
  174. // [[iToast makeText:NSLocalizedString(@"File_upload_file_already_exists",nil)] show];
  175. // });
  176. [self handleUploadDoneOneFileBy:operation];
  177. }
  178. else{//未上传完 isComplete 这个字段有问题
  179. operation.fileModel.didUploadBytes = model.data.size;
  180. [self prepareToUploadFileWithOperation:operation];
  181. }
  182. }
  183. else{//上传过了 未上传完成
  184. operation.fileModel.didUploadBytes = model.data.size;
  185. [self prepareToUploadFileWithOperation:operation];
  186. }
  187. }
  188. #pragma mark 处理任务失败
  189. #pragma mark 准备上传文件
  190. - (void)prepareToUploadFileWithOperation:(customUploadOperation*)operation
  191. {
  192. NSMutableDictionary *paraDict = [NSMutableDictionary new];
  193. NSString* taskUid = operation.fileModel.taskId;
  194. if(!taskUid || taskUid.length == 0){
  195. taskUid = [iTools getTaskUidStr];
  196. operation.fileModel.taskId = taskUid;
  197. }
  198. [paraDict setObject:taskUid forKey:@"taskId"];
  199. [paraDict setObject:@0 forKey:@"position"];
  200. [paraDict setObject:@"true" forKey:@"isLast"];
  201. if(operation.fileModel.savePath){
  202. [paraDict setObject:operation.fileModel.savePath forKey:@"savePath"];
  203. }
  204. else{
  205. HLog(@"获取保存路径失败")
  206. return;
  207. }
  208. if(operation.fileModel.filename){
  209. [paraDict setObject:operation.fileModel.filename forKey:@"filename"];
  210. }
  211. else{
  212. HLog(@"获取用户名失败")
  213. return;
  214. }
  215. KWeakSelf
  216. if(operation.fileModel.curUploadFileType == uploadFileTypeImage){
  217. [paraDict setObject:@1 forKey:@"imageType"];
  218. if(!operation.fileModel.imageData){
  219. NSString*pathStr = [cachesFileManager getFilePathWithName:operation.fileModel.filename type:operation.fileModel.curUploadFileType];
  220. NSData *imageData = [NSData dataWithContentsOfFile:pathStr];
  221. if (!imageData) {
  222. if(!operation.fileModel.asset){
  223. NSString *curLocalIdentifier = operation.fileModel.localIdentifier;
  224. PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[curLocalIdentifier] options:nil];
  225. PHAsset *asset = fetchResult.firstObject;
  226. operation.fileModel.asset = asset;
  227. }
  228. PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
  229. options.networkAccessAllowed = YES; // Allow downloading from iCloud
  230. options.version = PHImageRequestOptionsVersionCurrent;
  231. options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
  232. [[PHImageManager defaultManager] requestImageDataForAsset:operation.fileModel.asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
  233. // 直接得到最终的 NSData 数据
  234. if (imageData) {
  235. operation.fileModel.imageData = imageData;
  236. [weakSelf afterGetImageDataFunWithOperation:operation];
  237. }
  238. else{
  239. [weakSelf handleUploadFailOneFileBy:operation];
  240. }
  241. }];
  242. return;
  243. }
  244. operation.fileModel.imageData = imageData;
  245. }
  246. NSData *curData = operation.fileModel.imageData;
  247. operation.onceDataLengt = [curData length];
  248. [self startUpload:paraDict operation:operation data:curData success:^(id _Nonnull responseObject) {
  249. frpUploadModel *model = [[frpUploadModel alloc] initWithDictionary:responseObject error:nil];
  250. if(model && model.position == operation.fileModel.totalBytes){
  251. HLog(@"%@备份完成 数据正常",operation.fileModel.filename)
  252. [weakSelf handleUploadDoneOneFileBy:operation];
  253. }
  254. else if(model && model.position > operation.fileModel.totalBytes){
  255. HLog(@"%@备份完成 数据异常 -- position:%ld -- totalBytes:%ld",operation.fileModel.filename,model.position,operation.fileModel.totalBytes)
  256. [weakSelf handleUploadDoneOneFileBy:operation];
  257. }
  258. else{
  259. HLog(@"%@备份完成一片 %ld",operation.fileModel.filename,model.position)
  260. }
  261. } faild:^(NSError * _Nonnull error) {
  262. HLog(@"%@备份失败",operation.fileModel.filename)
  263. [weakSelf handleUploadFailOneFileBy:operation];
  264. }];
  265. }
  266. else{
  267. [paraDict setObject:@1 forKey:@"videoType"];
  268. [paraDict setObject:@"false" forKey:@"isLast"];
  269. if(![cachesFileManager checkFileIsSaveState:operation.fileModel.filename withType:uploadFileTypeVideo]){
  270. if(!operation.fileModel.asset){
  271. NSString *curLocalIdentifier = operation.fileModel.localIdentifier;
  272. PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[curLocalIdentifier] options:nil];
  273. PHAsset *asset = fetchResult.firstObject;
  274. operation.fileModel.asset = asset;
  275. }
  276. //真正的视频数据
  277. PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
  278. options.version = PHVideoRequestOptionsVersionOriginal;
  279. options.networkAccessAllowed = YES; // Allow downloading from iCloud
  280. [[PHImageManager defaultManager] requestAVAssetForVideo:operation.fileModel.asset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
  281. if ([asset isKindOfClass:[AVURLAsset class]]) {
  282. AVURLAsset* urlAsset = (AVURLAsset*)asset;
  283. BOOL isSuc = [cachesFileManager copyVideoItemAtPath:[urlAsset.URL path] fileName:operation.fileModel.filename error:nil];
  284. if (isSuc) {
  285. [weakSelf afterGetVideoDataFunWithOperation:operation];
  286. }
  287. else{
  288. [weakSelf handleUploadFailOneFileBy:operation];
  289. }
  290. }
  291. else{
  292. [weakSelf handleUploadFailOneFileBy:operation];
  293. }
  294. }];
  295. return;
  296. }
  297. long curPosition = operation.fileModel.didUploadBytes;
  298. [self beginUploadVideoDataFunBy:operation with:curPosition withPara:paraDict success:^(id _Nonnull responseObject) {
  299. } faild:^(NSError * _Nonnull error) {
  300. }];
  301. }
  302. }
  303. #pragma mark 视频上传
  304. - (void)beginUploadVideoDataFunBy:(customUploadOperation*)operation with:(NSInteger)position withPara:(NSMutableDictionary*)paraDict success:(netWork_Success)success faild:(netWork_Faild)faildStr
  305. {
  306. if(operation.isCancelType){
  307. HLog(@"防止取消不了任务生效")
  308. return;
  309. }
  310. BOOL isLastPicece = NO;
  311. if((operation.fileModel.totalBytes - position) <= MaxNasUploadPieceSzie){
  312. [paraDict setObject:@"true" forKey:@"isLast"];
  313. isLastPicece = YES;
  314. }
  315. else{
  316. [paraDict setObject:@"false" forKey:@"isLast"];
  317. }
  318. [paraDict setObject:[NSNumber numberWithLong:position] forKey:@"position"];
  319. //视频数据切片
  320. __block NSData *videoData = [self cutVideoFileFunAtIndex:position withMaxLenght:MaxNasUploadPieceSzie withModel:operation.fileModel];
  321. if(!videoData ||videoData.length ==0){
  322. HLog(@"视频没获取到")
  323. [self handleUploadFailOneFileBy:operation];
  324. return;
  325. }
  326. operation.onceDataLengt = [videoData length];
  327. KWeakSelf
  328. [self startUpload:paraDict operation:operation data:videoData success:^(id _Nonnull responseObject) {
  329. frpUploadModel *model = [[frpUploadModel alloc] initWithDictionary:responseObject error:nil];
  330. if(model && model.position >= operation.fileModel.totalBytes){
  331. HLog(@"%@上传完成 000",operation.fileModel.filename)
  332. [weakSelf handleUploadDoneOneFileBy:operation];
  333. }
  334. else{
  335. HLog(@"%@上传完成一片 %ld",operation.fileModel.filename,model.position)
  336. [weakSelf beginUploadVideoDataFunBy:operation with:model.position withPara:paraDict success:^(id _Nonnull responseObject) {
  337. success(responseObject);
  338. } faild:^(NSError * _Nonnull error) {
  339. NSError *err = error;
  340. if(error.code != -999){
  341. faildStr(err);
  342. }
  343. }];
  344. }
  345. } faild:^(NSError * _Nonnull error) {
  346. HLog(@"%@上传失败",operation.fileModel.filename)
  347. [weakSelf handleUploadFailOneFileBy:operation];
  348. }];
  349. }
  350. #pragma mark 分段读视频文件
  351. -(NSData*)cutVideoFileFunAtIndex:(NSUInteger)dataIndex withMaxLenght:(NSInteger)maxLengt withModel:(uploadFileDataModel*)dataModel{
  352. NSString *filePath = [cachesFileManager getFilePathWithName:dataModel.filename type:uploadFileTypeVideo]; // 文件路径
  353. NSFileManager *manager0 = [NSFileManager defaultManager];
  354. if(![manager0 fileExistsAtPath:filePath]) {
  355. return [NSData new];
  356. }
  357. NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath]; // 创建文件句柄
  358. // 设置分段读取的大小,这里以每次读取1KB为例
  359. const NSUInteger chunkSize = maxLengt;//cutVideoPieceSzie;//5 * 1024 *1024;
  360. NSMutableData *data = [NSMutableData data];
  361. if (fileHandle) {
  362. long long endOfFile = [fileHandle seekToEndOfFile];
  363. if(dataModel.totalBytes == 0
  364. || dataModel.totalBytes < endOfFile){//异常处理
  365. dataModel.totalBytes = endOfFile;
  366. }
  367. //异常处理
  368. if(endOfFile == dataIndex){
  369. dataModel.totalBytes = endOfFile;
  370. dataModel.didUploadBytes = endOfFile;
  371. dataModel.curUploadStateType = uploadStateDone;
  372. [fileHandle closeFile];
  373. return data;
  374. }
  375. if (endOfFile >= chunkSize) {
  376. // 读取文件的分段数据到某个位置
  377. [fileHandle seekToFileOffset:dataIndex];
  378. // 读取文件的分段数据
  379. NSData* chunk = [fileHandle readDataOfLength:chunkSize];
  380. if (chunk) {
  381. [data appendData:chunk];
  382. }
  383. }
  384. else{
  385. // 读取文件的分段数据到某个位置
  386. [fileHandle seekToFileOffset:dataIndex];
  387. [data appendData:[fileHandle readDataToEndOfFile]];
  388. }
  389. // 在这里可以对文件内容进行处理
  390. // ...
  391. // 关闭文件句柄
  392. [fileHandle closeFile];
  393. }
  394. HLog(@"视频切片完成 dataIndex:%ld --长度:%ld",dataIndex,[data length])
  395. return data;
  396. }
  397. #pragma mark 处理上传完成
  398. - (void)handleUploadDoneOneFileBy:(customUploadOperation*)operation
  399. {
  400. [[NSNotificationCenter defaultCenter] postNotificationName:nasBackupsTaskExeEnd object:operation.fileModel];
  401. [_uploadingOperationArr removeObject:operation];
  402. //[self beginUpload];
  403. [[nasBackupsManager shareInstance] backupsFileDoneFun];
  404. }
  405. #pragma mark 处理删除失败
  406. - (void)handleUploadFailOneFileBy:(customUploadOperation*)operation
  407. {
  408. operation.fileModel.curUploadStateType = uploadStateFail;
  409. [[NSNotificationCenter defaultCenter] postNotificationName:nasBackupsTaskExeError object:operation.fileModel];
  410. [_uploadingOperationArr removeObject:operation];
  411. //[self beginUpload];
  412. //[[nasBackupsManager shareInstance] changeBackupsFileStateToFailWith:@""];
  413. }
  414. #pragma mark 根据 asset 获取到图片数据
  415. - (void)afterGetImageDataFunWithOperation:(customUploadOperation*)operation
  416. {
  417. [cachesFileManager getFileNameWithContent:operation.fileModel.imageData fileName:operation.fileModel.filename type:uploadFileTypeImage];
  418. [self prepareToUploadFileWithOperation:operation];
  419. }
  420. #pragma mark 根据 asset 获取到视频数据
  421. - (void)afterGetVideoDataFunWithOperation:(customUploadOperation*)operation
  422. {
  423. [self prepareToUploadFileWithOperation:operation];
  424. }
  425. #pragma mark 开始上传
  426. - (void)startUpload:(NSMutableDictionary *)params operation:(customUploadOperation*)operation data:(NSData *)data success:(netWork_Success)success faild:(netWork_Faild)faildStr {
  427. NSString *urlString = ksharedAppDelegate.NASFileByBoxService;
  428. urlString = [[NSString alloc] initWithFormat:@"%@uploadFile",urlString];
  429. NSURL *URL = [NSURL URLWithString:urlString];
  430. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  431. [request setHTTPMethod:@"POST"];
  432. //请求体
  433. NSMutableData *bodyData = [self getBodyDataWithRequest:request withModel:operation.fileModel withData:data withPara:params];
  434. //设置请求体
  435. [request setHTTPMethod:@"POST"];
  436. [request setHTTPBody:bodyData];
  437. //设置请求体长度
  438. NSInteger length = [bodyData length];
  439. [request setValue:[NSString stringWithFormat:@"%ld",length] forHTTPHeaderField:@"Content-Length"];
  440. //设置 POST请求文件上传
  441. [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary3] forHTTPHeaderField:@"Content-Type"];
  442. KWeakSelf
  443. //回话对象
  444. NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
  445. operation.session = session;
  446. //请求task
  447. /*
  448. 第一个参数:请求对象
  449. 第二个参数:传递是要上传的数据(请求体)
  450. 第三个参数:
  451. */
  452. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:nil completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  453. //解析
  454. [weakSelf handleCustomUploadResultBy:data withResponse:response withError:error success:success faild:faildStr];
  455. }];
  456. // NSString *filePath = [cachesFileManager getFilePathWithName:dataModel.filename type:uploadFileTypeVideo]; // 文件路径
  457. // NSURL *filePathUrl = [NSURL URLWithString:filePath];
  458. //
  459. // NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:filePathUrl completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  460. // HLog(@"data string:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
  461. //[weakSelf handleCustomUploadResultBy:data withResponse:response withError:error];
  462. // }];
  463. // NSURLSessionDataTask *uploadTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  464. //
  465. // HLog(@"data string:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
  466. //[weakSelf handleCustomUploadResultBy:data withResponse:response withError:error];
  467. //
  468. //// NSJSONSerialization *object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
  469. //// NSDictionary *dict = (NSDictionary *)object;
  470. //// NSLog(@"=====%@",[dict objectForKey:@"success"]);
  471. // }];
  472. //执行Task
  473. [uploadTask resume];
  474. operation.dataTask = uploadTask;
  475. }
  476. #pragma mark 用系统方法写的上传处理
  477. - (void)handleCustomUploadResultBy:(NSData*)data withResponse:(NSURLResponse*)response withError:(NSError*)error success:(netWork_Success)success faild:(netWork_Faild)faildStr{
  478. if(error){
  479. HLog(@"上传错误:%@",error)
  480. if(error.code != -999){
  481. faildStr(error);
  482. }
  483. return;
  484. }
  485. NSJSONSerialization *object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
  486. NSDictionary *dict = (NSDictionary *)object;
  487. frpUploadModel *model = [[frpUploadModel alloc] initWithDictionary:dict error:nil];
  488. if(model && [model.msg isEqualToString:@"success"]){
  489. success(dict);
  490. }
  491. else{
  492. NSError *err = [NSError new];
  493. faildStr(err);
  494. }
  495. }
  496. - (NSMutableData *)getBodyDataWithRequest:(NSMutableURLRequest *)request withModel:(uploadFileDataModel*)dataModel withData:(NSData*)data withPara:(NSMutableDictionary*)params{
  497. //1 边界符号要配置请求头里面去
  498. /*
  499. multipart/form-data 是表单格式
  500. charset=utf-8 是utf-8编码
  501. bounary 是表单开头
  502. */
  503. [request setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", Kboundary3] forHTTPHeaderField:@"Content-Type"];
  504. /// body
  505. NSMutableData *boydData = [NSMutableData data];
  506. // 2.1 边界符号(开始边界)
  507. //2.1.1 其它参数
  508. NSMutableString *paraString = [NSMutableString new];
  509. //[paraString appendFormat:@"--%@\r\n",Kboundary];//\n:换行 \n:切换到行首
  510. for (NSString *key in params) {
  511. NSString *value = params[key];
  512. [paraString appendFormat:@"--%@\r\n",Kboundary3];//\n:换行 \n:切换到行首
  513. [paraString appendFormat:@"Content-Disposition: form-data; name=\"%@\"",key];
  514. [paraString appendFormat:@"\r\n"];
  515. [paraString appendFormat:@"\r\n"];
  516. [paraString appendFormat:@"%@\r\n",value];
  517. }
  518. //[boydData appendData:[paraString dataUsingEncoding:NSUTF8StringEncoding]];
  519. // body每一个段内容以换行符作为结束标示
  520. NSString *fileBeginBoundary = [NSString stringWithFormat:@"--%@\r\n", Kboundary3];
  521. //[boydData appendData:[fileBeginBoundary dataUsingEncoding:NSUTF8StringEncoding]];
  522. [paraString appendString:fileBeginBoundary];
  523. // 2.2 属性配置 名字;key;类型
  524. NSString *serverFileKey = @"image"; //key
  525. //NSString *serverFileKey = @"file";
  526. NSString *serverContentTypes = @"image/png"; //类型
  527. if (dataModel.curUploadFileType == uploadFileTypeVideo) {
  528. serverFileKey = @"video";
  529. serverContentTypes = @"video/mp4";
  530. }
  531. NSString *serverFileName = dataModel.filename; //name
  532. // filename已命名文件; name相当于一个key, 这个名字和服务器保持一致
  533. /*
  534. 理解key,表单发送给服务端,服务端拿到数据之后,可以将任务解析成一个字典了imageDict;图片数据会通过这个字典里面的name来获取图片(伪代码 image = imageDict[serverFileKey])
  535. */
  536. //2.3 拼接数据(创建一个字符串来拼装)
  537. NSMutableString *string = [NSMutableString new];
  538. [string appendFormat:@"Content-Disposition:form-data; name=\"%@\"; filename=\"%@\" ", @"file", serverFileName];
  539. //[string appendFormat:@"%@", KNewLine];
  540. [string appendFormat:@"\r\n"];
  541. [string appendFormat:@"Content-Type:%@", serverContentTypes];
  542. // [string appendFormat:@"%@", KNewLine];
  543. // [string appendFormat:@"%@", KNewLine];
  544. [string appendFormat:@"\r\n"];
  545. [string appendFormat:@"\r\n"];
  546. // [boydData appendData:[string dataUsingEncoding:NSUTF8StringEncoding]];
  547. [paraString appendString:string];
  548. [boydData appendData:[paraString dataUsingEncoding:NSUTF8StringEncoding]];
  549. // 2.3 拼接数据(拼接文件数据)
  550. [boydData appendData:data];
  551. // 2.4 边界符号 (结束边界)
  552. NSString *fileEndBoundary = [NSString stringWithFormat:@"\r\n--%@--", Kboundary3];
  553. [boydData appendData:[fileEndBoundary dataUsingEncoding:NSUTF8StringEncoding]];
  554. return boydData;
  555. }
  556. #pragma mark 上传的文件已存在
  557. - (void)handleTaskDidUploadWith:(customUploadOperation*)operation withState:(NSInteger)state
  558. {
  559. // if(state == 1){
  560. // [[iToast makeText:NSLocalizedString(@"File_upload_file_already_exists",nil)] show];
  561. // }
  562. [self.uploadingOperationArr removeObject:operation];
  563. NSMutableArray *delArr = [NSMutableArray new];
  564. [delArr addObject:operation.fileModel];
  565. [[nasUploadFileManager shareInstance] deleteUploadFileRecordBy:delArr withDelCache:NO complete:^(BOOL isSuccess) {
  566. if (isSuccess) {
  567. }
  568. }];
  569. [self beginUpload];
  570. }
  571. #pragma mark - <NSURLSessionDataDelegate>
  572. // ssl 服务 证书信任
  573. - (void)URLSession:(NSURLSession *)session
  574. didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
  575. completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{
  576. if(![challenge.protectionSpace.authenticationMethod isEqualToString:@"NSURLAuthenticationMethodServerTrust"]) {
  577. return;
  578. }
  579. // 信任该插件
  580. NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
  581. // 第一个参数 告诉系统如何处置
  582. completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
  583. }
  584. //当请求协议是https的时候回调用该方法
  585. //Challenge 挑战 质询(受保护空间)
  586. //NSURLAuthenticationMethodServerTrust 服务器信任证书
  587. - (void)URLSession:(NSURLSession *)session
  588. task:(NSURLSessionTask *)task
  589. didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
  590. completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler {
  591. if(![challenge.protectionSpace.authenticationMethod isEqualToString:@"NSURLAuthenticationMethodServerTrust"]) {
  592. return;
  593. }
  594. // 信任该插件
  595. NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
  596. // 第一个参数 告诉系统如何处置
  597. completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
  598. }
  599. // 接受到响应调用
  600. - (void)URLSession:(NSURLSession *)session
  601. dataTask:(NSURLSessionDataTask *)dataTask
  602. didReceiveResponse:(NSURLResponse *)response
  603. completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
  604. completionHandler(NSURLSessionResponseAllow);
  605. }
  606. // 上传进度
  607. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
  608. //每包发送的大小bytesSent,totalBytesSent已经上传了多少;totalBytesExpectedToSend总共要发送多少
  609. // 32768 = 32KB
  610. HLog(@"didSendBodyData: %lld--%lld-%lld", bytesSent, totalBytesSent, totalBytesExpectedToSend);
  611. for (customUploadOperation*operation in _uploadingOperationArr) {
  612. if(operation.dataTask == task){
  613. operation.fileModel.didUploadBytes += bytesSent;
  614. //调整下大小 因为上传的数据 除了data 长度 还包含了 参数大小
  615. if(totalBytesSent == totalBytesExpectedToSend){
  616. operation.fileModel.didUploadBytes -= (totalBytesExpectedToSend - operation.onceDataLengt);
  617. }
  618. operation.i ++;
  619. if(operation.i >= _speedShowCount){
  620. [nasBackupsManager shareInstance].curPhotosBackupsTaskMod.didUploadBytes = operation.fileModel.didUploadBytes;
  621. [[nasBackupsManager shareInstance] changeBackupsFileStateFun];
  622. operation.i = 0;
  623. }
  624. break;
  625. }
  626. }
  627. }
  628. #pragma mark 取消单个任务
  629. - (void)cancelUploadTaskFunWith:(uploadFileDataModel*)fileModel
  630. {
  631. HLog(@"取消任务-- %@--%@",fileModel.filename,fileModel.taskId)
  632. @synchronized (self) {
  633. for (uploadFileDataModel*waitModel in _uploadWaitingUrlArr) {
  634. if([waitModel.localIdentifier isEqualToString:fileModel.localIdentifier]){
  635. [_uploadWaitingUrlArr removeObject:waitModel];
  636. return;
  637. }
  638. }
  639. for (customUploadOperation*operation in _uploadingOperationArr) {
  640. if([operation.fileModel.localIdentifier isEqualToString:fileModel.localIdentifier]){
  641. operation.isCancelType = YES;
  642. [operation.dataTask cancel];
  643. [_uploadingOperationArr removeObject:operation];
  644. [self beginUpload];
  645. break;
  646. }
  647. }
  648. }
  649. }
  650. #pragma mark 取消所有任务
  651. - (void)cancelUploadAllTaskFun
  652. {
  653. HLog(@"取消所有任务")
  654. @synchronized (self) {
  655. [_uploadWaitingUrlArr removeAllObjects];
  656. for (customUploadOperation*operation in _uploadingOperationArr) {
  657. operation.isCancelType = YES;
  658. [operation.dataTask cancel];
  659. }
  660. [_uploadingOperationArr removeAllObjects];
  661. }
  662. }
  663. #pragma mark 判断是否在上传中
  664. - (BOOL)checkUploadTaskDoingFun
  665. {
  666. if(_uploadWaitingUrlArr.count >0 || _uploadingOperationArr.count>0){
  667. return YES;
  668. }
  669. return NO;
  670. }
  671. #pragma mark - lazy load
  672. - (NSMutableArray *)uploadWaitingUrlArr {
  673. if (!_uploadWaitingUrlArr) {
  674. _uploadWaitingUrlArr = [NSMutableArray array];
  675. }
  676. return _uploadWaitingUrlArr;
  677. }
  678. - (NSMutableArray *)uploadingOperationArr {
  679. if (!_uploadingOperationArr) {
  680. _uploadingOperationArr = [NSMutableArray array];
  681. }
  682. return _uploadingOperationArr;
  683. }
  684. @end