123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- //
- // nasUploadManager.m
- // Private-X
- //
- // Created by xd h on 2024/8/7.
- //
- #import "nasUploadManager.h"
- #import "AFNetworking.h"
- #import "AFNetworkReachabilityManager.h"
- #import "AFHTTPSessionManager.h"
- #import "frpUploadModel.h"
- #define Kboundary @"Boundaryhxd"
- #define KNewLine [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]
- @interface nasUploadManager ()<NSURLSessionDataDelegate>
- @property(nonatomic,strong)AFHTTPSessionManager *uploadManager;
- @property (nonatomic, strong) NSURLSessionDataTask *uploadTask;
- @end
- @implementation nasUploadManager
- + (instancetype)shareInstance {
- static nasUploadManager *_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
- {
- _uploadManager = [[AFHTTPSessionManager alloc] init];
- _uploadManager.requestSerializer = [AFJSONRequestSerializer serializer];
- _uploadManager.responseSerializer = [AFJSONResponseSerializer serializer];
-
- [_uploadManager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
- _uploadManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json", @"text/javascript",@"text/html",@"text/plain",nil];
- _uploadManager.requestSerializer.timeoutInterval = 180;
-
- }
- #pragma mark NSURLSessionDataDelegate
- // 1响应
- - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))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);
-
- }
- // 2 接收数据
- //- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
- //
- // NSDictionary *infoDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
- // HLog(@"%@", infoDict);
- //
- //}
- // 3 完成
- //- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
- // HLog(@"上传完成 task:%@---error:%@", task,error);
- //}
- - (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=%@", Kboundary] 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",Kboundary];//\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", Kboundary];
- //[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--%@--", Kboundary];
- [boydData appendData:[fileEndBoundary dataUsingEncoding:NSUTF8StringEncoding]];
-
- return boydData;
- }
- - (void)startUpload:(NSMutableDictionary *)params model:(uploadFileDataModel*)dataModel 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:dataModel 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=%@",Kboundary] forHTTPHeaderField:@"Content-Type"];
- KWeakSelf
- //回话对象
- NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
-
- //请求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];
- self.uploadTask = 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)
- 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);
- }
- }
- #pragma mark afnetwork
- - (void)nasUploadFileToFileServiceWithParams:(NSMutableDictionary *)params model:(uploadFileDataModel*)dataModel data:(NSData *)data success:(netWork_Success)success faild:(netWork_Faild)faildStr {
-
- //test code
- // [self startUpload:params model:dataModel data:data success:success faild:faildStr];
- // return;
-
- NSString *urlString = ksharedAppDelegate.NASFileByBoxService;
- urlString = [[NSString alloc] initWithFormat:@"%@uploadFile",urlString];
-
- NSInteger position = 0;
- if([[params allKeys] containsObject:@"position"]){
- NSNumber *positionNumber = params[@"position"];
- position = positionNumber.longValue;
- }
-
- __block long dataLength = [data length];
- HLog(@"上传地址:%@---%@---position:%ld--data 长度:%ld ",urlString,params,position,[data length]);
-
- self.uploadTask = [_uploadManager POST:urlString parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
-
- NSString *mimeType =@"application/octet-stream";
- if ([[params allKeys] containsObject:@"imageType"]) {
- mimeType = @"image/jpeg";
- //mimeType = @"jpg";
- }
- else if ([[params allKeys] containsObject:@"videoType"]) {
- //mimeType = @"video/mp4";
- mimeType = @"video";
- }
-
- [formData appendPartWithFileData:data name:@"file" fileName:params[@"filename"] mimeType:mimeType];
-
- } progress:^(NSProgress * _Nonnull uploadProgress) {
- HLog(@"上传 Progress:--%@---%lld",uploadProgress,uploadProgress.completedUnitCount)
- //dataModel.didUploadBytes = position + (uploadProgress.completedUnitCount);
-
- long didSendData = (long)(uploadProgress.fractionCompleted *dataLength);
- if(uploadProgress.fractionCompleted==1){
- didSendData = dataLength;
- }
- dataModel.didUploadBytes = position + didSendData;
-
- [[NSNotificationCenter defaultCenter] postNotificationName:uploadFileRefreshNotification object:dataModel];
-
- } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
-
- success(responseObject);
-
- } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error, id _Nonnull responseObject) {
- if(error.code != -999){
- faildStr(error);
- }
- }];
-
- data = nil;
- }
- - (void)beginUploadDataBy:(uploadFileDataModel*)dataModel success:(netWork_Success)success faild:(netWork_Faild)faildStr
- {
- NSMutableDictionary *paraDict = [NSMutableDictionary new];
-
- NSString* taskUid = dataModel.taskId;
- if(!taskUid || taskUid.length == 0){
- taskUid = [iTools getTaskUidStr];
- }
-
- [paraDict setObject:taskUid forKey:@"taskId"];
- [paraDict setObject:@0 forKey:@"position"];
- [paraDict setObject:@"true" forKey:@"isLast"];
- if(dataModel.savePath){
- [paraDict setObject:dataModel.savePath forKey:@"savePath"];
- }
- else{
- HLog(@"获取保存路径失败")
- return;
- }
-
- if(dataModel.filename){
- [paraDict setObject:dataModel.filename forKey:@"filename"];
- }
- else{
- HLog(@"获取用户名失败")
- return;
- }
-
- KWeakSelf
- if(dataModel.curUploadFileType == uploadFileTypeImage){
- [paraDict setObject:@1 forKey:@"imageType"];
- NSData *curData = dataModel.imageData;
-
- [self nasUploadFileToFileServiceWithParams:paraDict model:dataModel data:curData success:^(id _Nonnull responseObject) {
- HLog(@"%@上传完成 000",dataModel.filename)
- success(responseObject);
- } faild:^(NSError * _Nonnull error) {
- HLog(@"%@上传失败",dataModel.filename)
- faildStr(error);
- }];
- }
- else{
- [paraDict setObject:@0 forKey:@"videoType"];
- [paraDict setObject:@"false" forKey:@"isLast"];
-
- long curPosition = dataModel.didUploadBytes;
- [self beginUploadVideoDataFunBy:dataModel with:curPosition withPara:paraDict success:^(id _Nonnull responseObject) {
- success(responseObject);
- } faild:^(NSError * _Nonnull error) {
- faildStr(error);
- }];
- }
-
- }
- - (void)beginUploadVideoDataFunBy:(uploadFileDataModel*)dataModel with:(NSInteger)position withPara:(NSMutableDictionary*)paraDict success:(netWork_Success)success faild:(netWork_Faild)faildStr
- {
- BOOL isLastPicece = NO;
- if((dataModel.totalBytes - position) <= MaxNasUploadPieceSzie){
- [paraDict setObject:@"true" forKey:@"isLast"];
- isLastPicece = YES;
- }
-
- [paraDict setObject:[NSNumber numberWithLong:position] forKey:@"position"];
-
- //视频数据切片
- __block NSData *videoData = [self cutVideoFileFunAtIndex:position withMaxLenght:MaxNasUploadPieceSzie withModel:dataModel];
-
- KWeakSelf
- [self nasUploadFileToFileServiceWithParams:paraDict model:dataModel data:videoData success:^(id _Nonnull responseObject) {
- HLog(@"%@上传完成 222 %@",dataModel.filename,responseObject)
- videoData = nil;
-
- frpUploadModel *model = [[frpUploadModel alloc] initWithDictionary:responseObject error:nil];
- if(model && model.msg){
- if (isLastPicece) {
- success(responseObject);
- }
- else{
- [weakSelf beginUploadVideoDataFunBy:dataModel with:model.position withPara:paraDict success:^(id _Nonnull responseObject) {
- success(responseObject);
- } faild:^(NSError * _Nonnull error) {
- NSError *err = error;
- if(error.code != -999){
- faildStr(err);
- }
-
- }];
- }
- }
- else{
- videoData = nil;
- NSError *err = [NSError new];
- faildStr(err);
- }
-
- } faild:^(NSError * _Nonnull error) {
- HLog(@"%@上传失败---%@",dataModel.filename,error)
- videoData = nil;
- faildStr(error);
- }];
- }
- #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];
-
- //把视频切成两份文件给凌云
- // NSData* chunk = [fileHandle readDataOfLength:MaxNasUploadPieceSzie];
- //
- // [cachesFileManager getFileNameWithContent:chunk fileName:[[NSString alloc] initWithFormat:@"1_%@",dataModel.filename] type:uploadFileTypeVideo];
- //
- // [fileHandle seekToFileOffset:MaxNasUploadPieceSzie];
- // NSData* chunk2 = [fileHandle readDataToEndOfFile];
- // [cachesFileManager getFileNameWithContent:chunk2 fileName:[[NSString alloc] initWithFormat:@"2_%@",dataModel.filename] type:uploadFileTypeVideo];
- //
- // return chunk2;
-
- 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)cancelUploadTaskFun
- {
- [self.uploadTask cancel];
- }
- @end
|