TVCClient.m 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052
  1. //
  2. // TVCClient.m
  3. // VCDemo
  4. //
  5. // Created by kennethmiao on 16/10/18.
  6. // Copyright © 2016年 kennethmiao. All rights reserved.
  7. //
  8. #import "TVCClient.h"
  9. #import "TVCCommon.h"
  10. #import "TVCClientInner.h"
  11. #import "TVCReport.h"
  12. #import <AVFoundation/AVFoundation.h>
  13. #import <QCloudCore/QCloudCore.h>
  14. #import <QCloudCore/QCloudAuthentationV5Creator.h>
  15. #import <QCloudCOSXML/QCloudCOSXML.h>
  16. #include <sys/types.h>
  17. #include <sys/socket.h>
  18. #include <arpa/inet.h>
  19. #include <netdb.h>
  20. //#import "TXRTMPAPI.h"
  21. #define TVCMultipartResumeSessionKey @"TVCMultipartResumeSessionKey" // 点播vodSessionKey
  22. #define TVCMultipartResumeExpireTimeKey @"TVCMultipartResumeExpireTimeKey" // vodSessionKey过期时间
  23. #define TVCMultipartFileLastModTime @"TVCMultipartFileLastModTime" // 文件最后修改时间,用于在断点续传的时候判断文件是否修改
  24. #define TVCMultipartResumeData @"TVCMultipartUploadResumeData" // cos分片上传文件resumeData
  25. #define TVCUGCUploadCosKey @"ugc_upload"
  26. @interface TVCClient () <QCloudSignatureProvider>
  27. @property(nonatomic, strong) TVCConfig *config;
  28. @property(nonatomic, strong) QCloudAuthentationV5Creator* creator;
  29. @property(nonatomic, strong) NSString* reqKey;
  30. @property(nonatomic, strong) NSString* serverIP;
  31. @property (nonatomic, strong) QCloudCOSXMLUploadObjectRequest* uploadRequest;
  32. @property(nonatomic, strong) TVCReportInfo* reportInfo;
  33. @end
  34. @implementation TVCClient
  35. - (void)dealloc {
  36. NSLog(@"dealloc TVCClient");
  37. }
  38. - (instancetype)initWithConfig:(TVCConfig *)config {
  39. self = [super init];
  40. if (self) {
  41. self.config = config;
  42. self.reqKey = @"";
  43. self.serverIP = @"";
  44. self.reportInfo = [[TVCReportInfo alloc] init];
  45. }
  46. return self;
  47. }
  48. - (void)uploadVideo:(TVCUploadParam *)param result:(TVCResultBlock)result progress:(TVCProgressBlock)progress {
  49. TVCUploadResponse *rsp = nil;
  50. //check config
  51. rsp = [self checkConfig:self.config];
  52. if (rsp.retCode != TVC_OK) {
  53. dispatch_async(dispatch_get_main_queue(), ^{
  54. result(rsp);
  55. });
  56. return;
  57. }
  58. //check param
  59. rsp = [self checkParam:param];
  60. if (rsp.retCode != TVC_OK) {
  61. dispatch_async(dispatch_get_main_queue(), ^{
  62. result(rsp);
  63. });
  64. return;
  65. }
  66. //init upload context;
  67. TVCUploadContext *uploadContext = [[TVCUploadContext alloc] init];
  68. uploadContext.uploadParam = param;
  69. uploadContext.resultBlock = result;
  70. uploadContext.progressBlock = progress;
  71. if (param.videoPath.length > 0) {
  72. uploadContext.isUploadVideo = YES;
  73. }
  74. if (param.coverPath.length > 0) {
  75. uploadContext.isUploadCover = YES;
  76. }
  77. // get file information
  78. unsigned long long fileSize = 0;
  79. unsigned long long coverSize = 0;
  80. unsigned long long fileLastModTime = 0;
  81. NSFileManager *manager = [NSFileManager defaultManager];
  82. long long reqTime = [[NSDate date] timeIntervalSince1970] * 1000;
  83. if ([manager fileExistsAtPath:param.videoPath]) {
  84. fileSize = [[manager attributesOfItemAtPath:param.videoPath error:nil] fileSize];
  85. fileLastModTime = [[[manager attributesOfItemAtPath:param.videoPath error:nil] fileModificationDate] timeIntervalSince1970];
  86. uploadContext.videoSize = fileSize;
  87. uploadContext.videoLastModTime = fileLastModTime;
  88. if (uploadContext.isUploadCover) {
  89. if ([manager fileExistsAtPath:param.coverPath]) {
  90. coverSize = [[manager attributesOfItemAtPath:param.coverPath error:nil] fileSize];
  91. uploadContext.coverSize = coverSize;
  92. } else {
  93. [self txReport:TVC_UPLOAD_EVENT_ID_INIT errCode:TVC_ERR_FILE_NOT_EXIST errInfo:@"coverPath is not exist" reqTime:reqTime reqTimeCost:0 reqKey:@"" appId:0 fileSize:0 fileType:[self getFileType:param.coverPath] fileName:[self getFileName:param.coverPath] sessionKey:@"" fileId:@""];
  94. NSLog(@"coverPath is not exist");
  95. dispatch_async(dispatch_get_main_queue(), ^{
  96. TVCUploadResponse *rsp = [[TVCUploadResponse alloc] init];
  97. rsp.retCode = TVC_ERR_FILE_NOT_EXIST;
  98. rsp.descMsg = @"coverPath is not exist";
  99. result(rsp);
  100. });
  101. return;
  102. }
  103. }
  104. } else {
  105. [self txReport:TVC_UPLOAD_EVENT_ID_INIT errCode:TVC_ERR_FILE_NOT_EXIST errInfo:@"videoPath is not exist" reqTime:reqTime reqTimeCost:0 reqKey:@"" appId:0 fileSize:0 fileType:[self getFileType:param.videoPath] fileName:[self getFileName:param.videoPath] sessionKey:@"" fileId:@""];
  106. NSLog(@"videoPath is not exist");
  107. dispatch_async(dispatch_get_main_queue(), ^{
  108. TVCUploadResponse *rsp = [[TVCUploadResponse alloc] init];
  109. rsp.retCode = TVC_ERR_FILE_NOT_EXIST;
  110. rsp.descMsg = @"videoPath is not exist";
  111. result(rsp);
  112. });
  113. return;
  114. }
  115. //1.获取cos参数
  116. NSString* vodSessionKey = nil;
  117. if (self.config.enableResume == YES) {
  118. vodSessionKey = [self getSessionFromFilepath:uploadContext];
  119. }
  120. [self getCosInitParam:uploadContext withVodSessionKey:vodSessionKey];
  121. }
  122. - (BOOL)cancleUploadVideo {
  123. if (self.uploadRequest) {
  124. NSError* error;
  125. [self.uploadRequest cancelByProductingResumeData:&error];
  126. if (error) {
  127. return NO;
  128. } else {
  129. return YES;
  130. }
  131. }
  132. return NO;
  133. }
  134. + (NSString *)getVersion {
  135. return TVCVersion;
  136. }
  137. #pragma mark - InnerMethod
  138. - (TVCUploadResponse *)checkConfig:(TVCConfig *)config {
  139. TVCUploadResponse *rsp = [[TVCUploadResponse alloc] init];
  140. rsp.retCode = TVC_OK;
  141. // if(config.secretId.length <= 0){
  142. // rsp.retCode = TVC_ERR_UGC_REQUEST_FAILED;
  143. // rsp.descMsg = @"secretId should not be empty";
  144. // }
  145. if (config.signature.length <= 0) {
  146. rsp.retCode = TVC_ERR_INVALID_SIGNATURE;
  147. rsp.descMsg = @"signature should not be empty";
  148. }
  149. return rsp;
  150. }
  151. - (TVCUploadResponse *)checkParam:(TVCUploadParam *)param {
  152. TVCUploadResponse *rsp = [[TVCUploadResponse alloc] init];
  153. rsp.retCode = TVC_OK;
  154. if (param.videoPath.length <= 0) {
  155. rsp.retCode = TVC_ERR_INVALID_VIDEOPATH;
  156. rsp.descMsg = @"video path should not be empty";
  157. }
  158. if (param.videoName.length <= 0) {
  159. param.videoName = [self getFileName:param.videoPath];
  160. }
  161. return rsp;
  162. }
  163. - (NSMutableURLRequest *)getCosInitURLRequest:(TVCUploadContext *)uploadContext withVodSessionKey:(NSString *)vodSessionKey {
  164. TVCUploadParam *param = uploadContext.uploadParam;
  165. // set url
  166. NSString *baseUrl = nil;
  167. if (YES) {
  168. baseUrl = UCG_HTTPS_URL;
  169. } else {
  170. baseUrl = UCG_HTTP_URL;
  171. }
  172. baseUrl = [baseUrl stringByAppendingString:@"?Action="];
  173. baseUrl = [baseUrl stringByAppendingString:@"ApplyUploadUGC"];
  174. // set body
  175. NSMutableDictionary *dictParam = [[NSMutableDictionary alloc] init];
  176. [dictParam setValue:self.config.signature forKey:@"signature"];
  177. // 有vodSessionKey的话表示是断点续传
  178. if (vodSessionKey && vodSessionKey.length) {
  179. [dictParam setValue:vodSessionKey forKey:@"vodSessionKey"];
  180. } else {
  181. [dictParam setValue:param.videoName forKey:@"videoName"];
  182. [dictParam setValue:[self getFileType:param.videoPath] forKey:@"videoType"];
  183. [dictParam setValue:@(uploadContext.videoSize) forKey:@"videoSize"];
  184. if (uploadContext.isUploadCover) {
  185. [dictParam setValue:[self getFileName:param.coverPath] forKey:@"coverName"];
  186. [dictParam setValue:[self getFileType:param.coverPath] forKey:@"coverType"];
  187. [dictParam setValue:@(uploadContext.coverSize) forKey:@"coverSize"];
  188. }
  189. }
  190. NSError *error = nil;
  191. NSData *bodyData = [NSJSONSerialization dataWithJSONObject:dictParam options:0 error:&error];
  192. if (error) {
  193. return nil;
  194. }
  195. // create request
  196. NSURL *url =[NSURL URLWithString:baseUrl];
  197. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  198. [request setValue:[NSString stringWithFormat:@"%ld", (long) [bodyData length]] forHTTPHeaderField:@"Content-Length"];
  199. [request setHTTPMethod:@"POST"];
  200. [request setValue:@"application/json; charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
  201. [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
  202. [request setHTTPBody:bodyData];
  203. self.serverIP = [self queryIpWithDomain:url.host];
  204. return request;
  205. }
  206. - (NSMutableURLRequest *)getCosEndURLRequest:(TVCUploadContext *)uploadContext {
  207. NSString *baseUrl;;
  208. // TVCUploadParam *param = uploadContext.uploadParam;
  209. TVCUGCResult *ugc = uploadContext.cugResult;
  210. // if (YES) {
  211. baseUrl = [NSString stringWithFormat:@"https://%@/v3/index.php?Action=CommitUploadUGC", ugc.domain];
  212. // } else {
  213. // baseUrl = [NSString stringWithFormat:@"http://%@/v3/index.php?Action=CommitUploadUGC", ugc.domain];
  214. // }
  215. self.serverIP = [self queryIpWithDomain:ugc.domain];
  216. // set body
  217. NSMutableDictionary *dictParam = [[NSMutableDictionary alloc] init];
  218. [dictParam setValue:self.config.signature forKey:@"signature"];
  219. [dictParam setValue:ugc.uploadSession forKey:@"vodSessionKey"];
  220. NSError *error = nil;
  221. NSData *bodyData = [NSJSONSerialization dataWithJSONObject:dictParam options:0 error:&error];
  222. if (error) {
  223. return nil;
  224. }
  225. // create request
  226. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:baseUrl]];
  227. [request setValue:[NSString stringWithFormat:@"%ld", (long) [bodyData length]] forHTTPHeaderField:@"Content-Length"];
  228. [request setHTTPMethod:@"POST"];
  229. [request setValue:@"application/json; charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
  230. [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
  231. [request setHTTPBody:bodyData];
  232. NSLog(@"cos end req : %s", [baseUrl UTF8String]);
  233. return request;
  234. }
  235. - (void)getCosInitParam:(TVCUploadContext *)uploadContext withVodSessionKey:(NSString *)vodSessionKey {
  236. TVCResultBlock result = uploadContext.resultBlock;
  237. uploadContext.reqTime = [[NSDate date] timeIntervalSince1970] * 1000;
  238. uploadContext.initReqTime = uploadContext.reqTime;
  239. self.reqKey = [NSString stringWithFormat:@"%lld;%lld", uploadContext.videoLastModTime, uploadContext.initReqTime];
  240. NSMutableURLRequest *cosRequest = [self getCosInitURLRequest:uploadContext withVodSessionKey:vodSessionKey];
  241. if (cosRequest == nil) {
  242. if (uploadContext.resultBlock) {
  243. dispatch_async(dispatch_get_main_queue(), ^{
  244. TVCUploadResponse *initResp = [[TVCUploadResponse alloc] init];
  245. initResp.retCode = TVC_ERR_UGC_REQUEST_FAILED;
  246. initResp.descMsg = @"create ugc publish request failed";
  247. result(initResp);
  248. });
  249. return;
  250. }
  251. }
  252. NSURLSessionConfiguration *initCfg = [NSURLSessionConfiguration defaultSessionConfiguration];
  253. [initCfg setRequestCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
  254. if (self.config.timeoutInterval > 0) {
  255. [initCfg setTimeoutIntervalForRequest:self.config.timeoutInterval];
  256. } else {
  257. [initCfg setTimeoutIntervalForRequest:kTimeoutInterval];
  258. }
  259. NSURLSession *initSess = [NSURLSession sessionWithConfiguration:initCfg delegate:[[TVCHttpsDelegate alloc] init] delegateQueue:nil];
  260. __weak TVCClient *ws = self;
  261. __weak NSURLSession *wis = initSess;
  262. NSURLSessionTask *initTask = [initSess dataTaskWithRequest:cosRequest completionHandler:^(NSData *_Nullable initData, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  263. //invalid NSURLSession
  264. [wis invalidateAndCancel];
  265. TVCUploadResponse *rsp = [[TVCUploadResponse alloc] init];
  266. unsigned long long reqTimeCost = 0;
  267. NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
  268. if (error || httpResponse.statusCode != 200 || initData == nil) {
  269. // 删除session
  270. [self setSession:nil resumeData:nil lastModTime:0 withFilePath:uploadContext.uploadParam.videoPath];
  271. //1步骤出错
  272. NSLog(@"ugc init http req fail : error=%ld response=%s", (long)error.code, [httpResponse.description UTF8String]);
  273. rsp.retCode = TVC_ERR_UGC_REQUEST_FAILED;
  274. rsp.descMsg = [NSString stringWithFormat:@"ugc code:%ld, ugc desc:%@", (long)error.code, @"ugc init http req fail"];
  275. reqTimeCost = [[NSDate date] timeIntervalSince1970] * 1000 - uploadContext.reqTime;
  276. [ws txReport:TVC_UPLOAD_EVENT_ID_INIT errCode:rsp.retCode errInfo:rsp.descMsg reqTime:uploadContext.reqTime reqTimeCost:reqTimeCost reqKey:ws.reqKey appId:0 fileSize:uploadContext.videoSize fileType:[ws getFileType:uploadContext.uploadParam.videoPath] fileName:[ws getFileName:uploadContext.uploadParam.videoPath] sessionKey:@"" fileId:@""];
  277. if (result) {
  278. dispatch_async(dispatch_get_main_queue(), ^{
  279. result(rsp);
  280. });
  281. }
  282. return;
  283. }
  284. NSError *jsonErr = nil;
  285. NSDictionary *initDict = [NSJSONSerialization JSONObjectWithData:initData options:NSJSONReadingAllowFragments error:&jsonErr];
  286. if (jsonErr || ![initDict isKindOfClass:[NSDictionary class]]) {
  287. // 删除session
  288. [self setSession:nil resumeData:nil lastModTime:0 withFilePath:uploadContext.uploadParam.videoPath];
  289. rsp.retCode = TVC_ERR_UGC_PARSE_FAILED;
  290. rsp.descMsg = [NSString stringWithFormat:@"ugc code:%ld, ugc desc:%@", (long)jsonErr.code, @"ugc parse init http fail"];
  291. reqTimeCost = [[NSDate date] timeIntervalSince1970] * 1000 - uploadContext.reqTime;
  292. [ws txReport:TVC_UPLOAD_EVENT_ID_INIT errCode:rsp.retCode errInfo:rsp.descMsg reqTime:uploadContext.reqTime reqTimeCost:reqTimeCost reqKey:ws.reqKey appId:0 fileSize:uploadContext.videoSize
  293. fileType:[ws getFileType:uploadContext.uploadParam.videoPath] fileName:[ws getFileName:uploadContext.uploadParam.videoPath] sessionKey:@"" fileId:@""];
  294. if (result) {
  295. dispatch_async(dispatch_get_main_queue(), ^{
  296. result(rsp);
  297. });
  298. }
  299. return;
  300. }
  301. int code = -1;
  302. if ([[initDict objectForKey:kCode] isKindOfClass:[NSNumber class]]) {
  303. code = [[initDict objectForKey:kCode] intValue];
  304. }
  305. NSString *msg;;
  306. if ([[initDict objectForKey:kMessage] isKindOfClass:[NSString class]]) {
  307. msg = [initDict objectForKey:kMessage];
  308. }
  309. if (code != TVC_OK) {
  310. // 删除session
  311. [self setSession:nil resumeData:nil lastModTime:0 withFilePath:uploadContext.uploadParam.videoPath];
  312. rsp.retCode = TVC_ERR_UGC_REQUEST_FAILED;
  313. rsp.descMsg = [NSString stringWithFormat:@"ugc code:%d, ugc desc:%@", code, msg];
  314. reqTimeCost = [[NSDate date] timeIntervalSince1970] * 1000 - uploadContext.reqTime;
  315. [ws txReport:TVC_UPLOAD_EVENT_ID_INIT errCode:rsp.retCode errInfo:rsp.descMsg reqTime:uploadContext.reqTime reqTimeCost:reqTimeCost reqKey:ws.reqKey appId:0 fileSize:uploadContext.videoSize
  316. fileType:[ws getFileType:uploadContext.uploadParam.videoPath] fileName:[ws getFileName:uploadContext.uploadParam.videoPath] sessionKey:@"" fileId:@""];
  317. //1步骤出错
  318. if (result) {
  319. dispatch_async(dispatch_get_main_queue(), ^{
  320. result(rsp);
  321. });
  322. }
  323. return;
  324. }
  325. NSDictionary *dataDict = nil;
  326. if ([[initDict objectForKey:kData] isKindOfClass:[NSDictionary class]]) {
  327. dataDict = [initDict objectForKey:kData];
  328. }
  329. if (!dataDict) {
  330. // 删除session
  331. [self setSession:nil resumeData:nil lastModTime:0 withFilePath:uploadContext.uploadParam.videoPath];
  332. rsp.retCode = TVC_ERR_UGC_PARSE_FAILED;
  333. rsp.descMsg = @"data is not json string";
  334. reqTimeCost = [[NSDate date] timeIntervalSince1970] * 1000 - uploadContext.reqTime;
  335. [ws txReport:TVC_UPLOAD_EVENT_ID_INIT errCode:rsp.retCode errInfo:rsp.descMsg reqTime:uploadContext.reqTime reqTimeCost:reqTimeCost reqKey:ws.reqKey appId:0 fileSize:uploadContext.videoSize
  336. fileType:[ws getFileType:uploadContext.uploadParam.videoPath] fileName:[ws getFileName:uploadContext.uploadParam.videoPath] sessionKey:@"" fileId:@""];
  337. if (result) {
  338. dispatch_async(dispatch_get_main_queue(), ^{
  339. result(rsp);
  340. });
  341. }
  342. return;
  343. }
  344. // print json log
  345. NSError *parseError = nil;
  346. NSData *jsonData = [NSJSONSerialization dataWithJSONObject:initDict options:NSJSONWritingPrettyPrinted error:&parseError];
  347. NSString *initDictStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
  348. NSLog(@"init cos dic : %s", [initDictStr UTF8String]);
  349. TVCUGCResult *ugc = [[TVCUGCResult alloc] init];
  350. if ([[dataDict objectForKey:@"video"] isKindOfClass:[NSDictionary class]]) {
  351. NSDictionary *videoDict = [dataDict objectForKey:@"video"];
  352. ugc.videoSign = [videoDict objectForKey:@"storageSignature"];
  353. ugc.videoPath = [videoDict objectForKey:@"storagePath"];
  354. }
  355. if ([[dataDict objectForKey:@"cover"] isKindOfClass:[NSDictionary class]]) {
  356. NSDictionary *coverDict = [dataDict objectForKey:@"cover"];
  357. ugc.imageSign = [coverDict objectForKey:@"storageSignature"];
  358. ugc.imagePath = [coverDict objectForKey:@"storagePath"];
  359. }
  360. if ([[dataDict objectForKey:@"appId"] isKindOfClass:[NSNumber class]]) {
  361. ugc.userAppid = [[dataDict objectForKey:@"appId"] stringValue];
  362. }
  363. if ([[dataDict objectForKey:@"tempCertificate"] isKindOfClass:[NSDictionary class]]) {
  364. NSDictionary *cosTmp = [dataDict objectForKey:@"tempCertificate"];
  365. ugc.tmpSecretId = [cosTmp objectForKey:@"secretId"];
  366. ugc.tmpSecretKey = [cosTmp objectForKey:@"secretKey"];
  367. ugc.tmpToken = [cosTmp objectForKey:@"token"];
  368. ugc.tmpExpiredTime = [[cosTmp objectForKey:@"expiredTime"] longLongValue];
  369. }
  370. if ([[dataDict objectForKey:@"timestamp"] isKindOfClass:[NSNumber class]]) {
  371. ugc.currentTS = [[dataDict objectForKey:@"timestamp"] longLongValue];
  372. }
  373. if ([[dataDict objectForKey:@"storageAppId"] isKindOfClass:[NSNumber class]]) {
  374. ugc.uploadAppid = [[dataDict objectForKey:@"storageAppId"] stringValue];
  375. }
  376. if ([[dataDict objectForKey:@"storageBucket"] isKindOfClass:[NSString class]]) {
  377. ugc.uploadBucket = [dataDict objectForKey:@"storageBucket"];
  378. }
  379. if ([[dataDict objectForKey:@"vodSessionKey"] isKindOfClass:[NSString class]]) {
  380. ugc.uploadSession = [dataDict objectForKey:@"vodSessionKey"];
  381. }
  382. if ([[dataDict objectForKey:@"storageRegionV5"] isKindOfClass:[NSString class]]) {
  383. ugc.uploadRegion = [dataDict objectForKey:@"storageRegionV5"];
  384. }
  385. if ([[dataDict objectForKey:@"domain"] isKindOfClass:[NSString class]]) {
  386. ugc.domain = [dataDict objectForKey:@"domain"];
  387. }
  388. uploadContext.cugResult = ugc;
  389. NSLog(@"init cugResult %s", [[uploadContext.cugResult description] UTF8String]);
  390. reqTimeCost = [[NSDate date] timeIntervalSince1970] * 1000 - uploadContext.reqTime;
  391. [ws txReport:TVC_UPLOAD_EVENT_ID_INIT errCode:TVC_OK errInfo:@"" reqTime:uploadContext.reqTime reqTimeCost:reqTimeCost reqKey:ws.reqKey appId:ugc.userAppid fileSize:uploadContext.videoSize
  392. fileType:[ws getFileType:uploadContext.uploadParam.videoPath] fileName:[ws getFileName:uploadContext.uploadParam.videoPath] sessionKey:ugc.uploadSession fileId:@""];
  393. [ws setupCOSXMLShareService:uploadContext];
  394. //2.开始上传
  395. uploadContext.reqTime = [[NSDate date] timeIntervalSince1970] * 1000;
  396. if (vodSessionKey && vodSessionKey.length) {
  397. [ws commitCosUpload:uploadContext withResumeUpload:YES];
  398. } else {
  399. [ws commitCosUpload:uploadContext withResumeUpload:NO];
  400. }
  401. }];
  402. [initTask resume];
  403. }
  404. - (void) signatureWithFields:(QCloudSignatureFields*)fileds
  405. request:(QCloudBizHTTPRequest*)request
  406. urlRequest:(NSMutableURLRequest*)urlRequst
  407. compelete:(QCloudHTTPAuthentationContinueBlock)continueBlock
  408. {
  409. QCloudSignature* signature = nil;
  410. if (_creator != nil) {
  411. signature = [_creator signatureForData:urlRequst];
  412. }
  413. continueBlock(signature, nil);
  414. }
  415. - (void)setupCOSXMLShareService:(TVCUploadContext *)uploadContext {
  416. QCloudCredential* credential = [QCloudCredential new];
  417. credential.secretID = uploadContext.cugResult.tmpSecretId;
  418. credential.secretKey = uploadContext.cugResult.tmpSecretKey;
  419. credential.token = uploadContext.cugResult.tmpToken;
  420. long long nowTime = [[NSDate date] timeIntervalSince1970];
  421. long long serverTS = uploadContext.cugResult.currentTS;
  422. //如果本地时间戳跟后台返回的当前时间戳相差太大,就用后台返回的时间戳。避免本地时间错误导致403
  423. if (serverTS != 0 && nowTime - serverTS > 10*60 ) {
  424. credential.startDate = [NSDate dateWithTimeIntervalSince1970:serverTS];
  425. }
  426. credential.experationDate = [NSDate dateWithTimeIntervalSince1970:uploadContext.cugResult.tmpExpiredTime];
  427. _creator = [[QCloudAuthentationV5Creator alloc] initWithCredential:credential];
  428. QCloudServiceConfiguration* configuration = [QCloudServiceConfiguration new];
  429. configuration.appID = uploadContext.cugResult.uploadAppid;
  430. configuration.signatureProvider = self;
  431. QCloudCOSXMLEndPoint* endpoint = [[QCloudCOSXMLEndPoint alloc] init];
  432. endpoint.regionName = uploadContext.cugResult.uploadRegion;
  433. endpoint.useHTTPS = self.config.enableHttps;
  434. configuration.endpoint = endpoint;
  435. self.serverIP = [self queryIpWithDomain:[endpoint serverURLWithBucket:uploadContext.cugResult.uploadBucket appID:uploadContext.cugResult.uploadAppid].host];
  436. [QCloudCOSXMLService registerCOSXMLWithConfiguration:configuration withKey:TVCUGCUploadCosKey];
  437. [QCloudCOSTransferMangerService registerCOSTransferMangerWithConfiguration:configuration withKey:TVCUGCUploadCosKey];
  438. }
  439. - (void)commitCosUpload:(TVCUploadContext *)uploadContext withResumeUpload:(BOOL)isResumeUpload {
  440. dispatch_group_t group = dispatch_group_create();
  441. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  442. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  443. uploadContext.gcdGroup = group;
  444. uploadContext.gcdSem = semaphore;
  445. uploadContext.gcdQueue = queue;
  446. //2-1.开始上传视频
  447. TVCUploadParam *param = uploadContext.uploadParam;
  448. TVCUGCResult *cug = uploadContext.cugResult;
  449. NSLog(@"uploadCosVideo begin : cosBucket:%@ ,cos videoPath:%@, path:%@", cug.uploadBucket, cug.videoPath, param.videoPath);
  450. __block long long reqTimeCost = 0;
  451. __weak TVCClient *ws = self;
  452. if (uploadContext.isUploadVideo) {
  453. dispatch_group_async(group, queue, ^{
  454. QCloudCOSXMLUploadObjectRequest* videoUpload;
  455. if (uploadContext.resumeData != nil && uploadContext.resumeData.length != 0) {
  456. videoUpload = [QCloudCOSXMLUploadObjectRequest requestWithRequestData:uploadContext.resumeData];
  457. } else {
  458. videoUpload = [QCloudCOSXMLUploadObjectRequest new];
  459. videoUpload.body = [NSURL fileURLWithPath:param.videoPath];
  460. videoUpload.bucket = cug.uploadBucket;
  461. videoUpload.object = cug.videoPath;
  462. [videoUpload setInitMultipleUploadFinishBlock:^(QCloudInitiateMultipartUploadResult *multipleUploadInitResult, QCloudCOSXMLUploadObjectResumeData resumeData) {
  463. if (multipleUploadInitResult != nil && resumeData != nil) {
  464. [self setSession:cug.uploadSession resumeData:resumeData lastModTime:uploadContext.videoLastModTime withFilePath:param.videoPath];
  465. }
  466. }];
  467. }
  468. [videoUpload setFinishBlock:^(QCloudUploadObjectResult *result, NSError * error) {
  469. NSLog(@"uploadCosVideo finish : cosBucket:%@ ,cos videoPath:%@, path:%@, size:%lld", cug.uploadBucket, cug.videoPath, param.videoPath, uploadContext.videoSize);
  470. if (error) {
  471. reqTimeCost = [[NSDate date] timeIntervalSince1970] * 1000 - uploadContext.reqTime;
  472. NSString * errInfo = error.description;
  473. NSString * cosErrorCode = @"";
  474. if (error.userInfo != nil) {
  475. errInfo = error.userInfo.description;
  476. cosErrorCode = error.userInfo[@"Code"];
  477. }
  478. if ([cosErrorCode isEqualToString:@"RequestTimeTooSkewed"]) {
  479. uploadContext.isShouldRetry = YES;
  480. }
  481. [ws txReport:TVC_UPLOAD_EVENT_ID_COS errCode:TVC_ERR_VIDEO_UPLOAD_FAILED errInfo:errInfo reqTime:uploadContext.reqTime reqTimeCost:reqTimeCost reqKey:ws.reqKey appId:cug.userAppid fileSize:uploadContext.videoSize
  482. fileType:[ws getFileType:uploadContext.uploadParam.videoPath] fileName:[ws getFileName:uploadContext.uploadParam.videoPath] sessionKey:cug.uploadSession fileId:@""];
  483. // 取消的情况不清除session缓存
  484. if (error.code == -34009) {
  485. uploadContext.lastStatus = TVC_ERR_USER_CANCLE;
  486. uploadContext.desc = [NSString stringWithFormat:@"upload video, user cancled"];
  487. } else {
  488. uploadContext.lastStatus = TVC_ERR_VIDEO_UPLOAD_FAILED;
  489. uploadContext.desc = [NSString stringWithFormat:@"upload video, cos code:%ld, cos desc:%@", (long)error.code, error.description];
  490. //网络断开,不清除session缓存
  491. if (error.code != -34004) {
  492. [ws setSession:nil resumeData:nil lastModTime:0 withFilePath:param.videoPath];
  493. }
  494. dispatch_semaphore_signal(semaphore);
  495. }
  496. } else {
  497. NSLog(@"upload video succ");
  498. //视频上传完成,清除session缓存
  499. [ws setSession:nil resumeData:nil lastModTime:0 withFilePath:param.videoPath];
  500. //2-2.开始上传封面
  501. if (uploadContext.isUploadCover) {
  502. uploadContext.reqTime = [[NSDate date] timeIntervalSince1970] * 1000;
  503. QCloudCOSXMLUploadObjectRequest* coverUpload = [QCloudCOSXMLUploadObjectRequest new];
  504. coverUpload.body = [NSURL fileURLWithPath:param.coverPath];
  505. coverUpload.bucket = cug.uploadBucket;
  506. coverUpload.object = cug.imagePath;
  507. [coverUpload setFinishBlock:^(QCloudUploadObjectResult *result, NSError * error) {
  508. if (error) {
  509. //2-2步骤出错
  510. NSLog(@"upload cover fail : %ld", (long)error.code);
  511. NSString * errInfo = error.description;
  512. if (error.userInfo != nil) {
  513. errInfo = error.userInfo.description;
  514. }
  515. uploadContext.lastStatus = TVC_ERR_COVER_UPLOAD_FAILED;
  516. uploadContext.desc = errInfo;
  517. } else {
  518. NSLog(@"upload cover succ");
  519. }
  520. reqTimeCost = [[NSDate date] timeIntervalSince1970] * 1000 - uploadContext.reqTime;
  521. [ws txReport:TVC_UPLOAD_EVENT_ID_COS errCode:uploadContext.lastStatus errInfo:uploadContext.desc reqTime:uploadContext.reqTime reqTimeCost:reqTimeCost reqKey:ws.reqKey appId:cug.userAppid fileSize:uploadContext.coverSize fileType:[ws getFileType:uploadContext.uploadParam.coverPath] fileName:[ws getFileName:uploadContext.uploadParam.coverPath] sessionKey:cug.uploadSession fileId:@""];
  522. dispatch_semaphore_signal(semaphore);
  523. }];
  524. TVCProgressBlock progress = uploadContext.progressBlock;
  525. [coverUpload setSendProcessBlock:^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
  526. if (progress) {
  527. uint64_t total = uploadContext.videoSize + uploadContext.coverSize;
  528. uploadContext.currentUpload += totalBytesSent;
  529. if (uploadContext.currentUpload > total) {
  530. uploadContext.currentUpload = total;
  531. }
  532. progress(uploadContext.currentUpload, total);
  533. }
  534. }];
  535. ws.uploadRequest = coverUpload;
  536. [[QCloudCOSTransferMangerService costransfermangerServiceForKey:TVCUGCUploadCosKey] UploadObject:coverUpload];
  537. }
  538. }
  539. dispatch_semaphore_signal(semaphore);
  540. }];
  541. TVCProgressBlock progress = uploadContext.progressBlock;
  542. [videoUpload setSendProcessBlock:^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
  543. if (progress) {
  544. uint64_t total = uploadContext.videoSize + uploadContext.coverSize;
  545. uploadContext.currentUpload = totalBytesSent;
  546. if (uploadContext.currentUpload > total) {
  547. uploadContext.currentUpload = total;
  548. }
  549. progress(uploadContext.currentUpload, total);
  550. }
  551. }];
  552. ws.uploadRequest = videoUpload;
  553. [[QCloudCOSTransferMangerService costransfermangerServiceForKey:TVCUGCUploadCosKey] UploadObject:videoUpload];
  554. });
  555. }
  556. [self notifyCosUploadEnd:uploadContext];
  557. }
  558. - (void)notifyCosUploadEnd:(TVCUploadContext *)uploadContext {
  559. __weak TVCClient *ws = self;
  560. dispatch_group_notify(uploadContext.gcdGroup, uploadContext.gcdQueue, ^{
  561. if (uploadContext.isUploadVideo) {
  562. dispatch_semaphore_wait(uploadContext.gcdSem, DISPATCH_TIME_FOREVER);
  563. }
  564. if (uploadContext.isUploadCover) {
  565. dispatch_semaphore_wait(uploadContext.gcdSem, DISPATCH_TIME_FOREVER);
  566. }
  567. TVCResultBlock result = uploadContext.resultBlock;
  568. if (uploadContext.lastStatus != TVC_OK) {
  569. // 上传失败,由于签名时间太短,上传未完成导致的,重试
  570. if (uploadContext.isShouldRetry) {
  571. uploadContext.lastStatus = TVC_OK;
  572. uploadContext.isShouldRetry = NO;
  573. dispatch_async(dispatch_get_main_queue(), ^{
  574. //1.获取cos参数
  575. NSString* vodSessionKey = nil;
  576. if (self.config.enableResume == YES) {
  577. vodSessionKey = [self getSessionFromFilepath:uploadContext];
  578. }
  579. [self getCosInitParam:uploadContext withVodSessionKey:vodSessionKey];
  580. });
  581. } else if (result) {
  582. dispatch_async(dispatch_get_main_queue(), ^{
  583. TVCUploadResponse *rsp = [[TVCUploadResponse alloc] init];
  584. rsp.retCode = uploadContext.lastStatus;
  585. rsp.descMsg = uploadContext.desc;
  586. result(rsp);
  587. });
  588. return;
  589. }
  590. } else {
  591. //3.完成上传
  592. NSLog(@"complete upload task");
  593. NSMutableURLRequest *cosFiniURLRequest = [ws getCosEndURLRequest:uploadContext];
  594. NSURLSessionConfiguration *finishCfg = [NSURLSessionConfiguration defaultSessionConfiguration];
  595. [finishCfg setRequestCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
  596. if (self.config.timeoutInterval > 0) {
  597. [finishCfg setTimeoutIntervalForRequest:self.config.timeoutInterval];
  598. } else {
  599. [finishCfg setTimeoutIntervalForRequest:kTimeoutInterval];
  600. }
  601. NSURLSession *finishSess = [NSURLSession sessionWithConfiguration:finishCfg delegate:[[TVCHttpsDelegate alloc] init] delegateQueue:nil];
  602. __weak NSURLSession *wfs = finishSess;
  603. NSURLSessionTask *finiTask = [finishSess dataTaskWithRequest:cosFiniURLRequest completionHandler:^(NSData *_Nullable finiData, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  604. //invalid NSURLSession
  605. [wfs invalidateAndCancel];
  606. NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
  607. if (error || httpResponse.statusCode != 200 || finiData == nil) {
  608. //3步骤出错
  609. NSLog(@"cos end http req fail : error=%ld response=%s", (long)error.code, [httpResponse.description UTF8String]);
  610. if (result) {
  611. dispatch_async(dispatch_get_main_queue(), ^{
  612. TVCUploadResponse *initResp = [[TVCUploadResponse alloc] init];
  613. initResp.retCode = TVC_ERR_UGC_FINISH_REQ_FAILED;
  614. initResp.descMsg = [NSString stringWithFormat:@"ugc code:%ld, ugc desc:%@", error.code, @"ugc finish http req fail"];
  615. result(initResp);
  616. long long reqTimeCost = [[NSDate date] timeIntervalSince1970] * 1000 - uploadContext.reqTime;
  617. [ws txReport:TVC_UPLOAD_EVENT_ID_FINISH errCode:initResp.retCode errInfo:initResp.descMsg reqTime:uploadContext.reqTime reqTimeCost:reqTimeCost reqKey:ws.reqKey appId:uploadContext.cugResult.userAppid fileSize:uploadContext.videoSize fileType:[ws getFileType:uploadContext.uploadParam.videoPath] fileName:[ws getFileName:uploadContext.uploadParam.videoPath] sessionKey:uploadContext.cugResult.uploadSession fileId:@""];
  618. });
  619. }
  620. return;
  621. }
  622. NSDictionary *finiDict = [NSJSONSerialization JSONObjectWithData:finiData options:(NSJSONReadingMutableLeaves) error:nil];
  623. NSError *parseError = nil;
  624. NSData *jsonData = [NSJSONSerialization dataWithJSONObject:finiDict options:NSJSONWritingPrettyPrinted error:&parseError];
  625. NSString *finiDictStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
  626. NSLog(@"end cos dic : %@", finiDictStr);
  627. int code = -1;
  628. if ([[finiDict objectForKey:kCode] isKindOfClass:[NSNumber class]]) {
  629. code = [[finiDict objectForKey:kCode] intValue];
  630. }
  631. NSString *msg;;
  632. if ([[finiDict objectForKey:kMessage] isKindOfClass:[NSString class]]) {
  633. msg = [finiDict objectForKey:kMessage];
  634. }
  635. NSDictionary *dataDict = nil;
  636. NSString *videoURL = @"";
  637. NSString *coverURL = @"";
  638. NSString *videoID = @"";
  639. if ([[finiDict objectForKey:kData] isKindOfClass:[NSDictionary class]]) {
  640. dataDict = [finiDict objectForKey:kData];
  641. NSDictionary *videoDic = nil;
  642. NSDictionary *coverDic = nil;
  643. if ([[dataDict objectForKey:@"video"] isKindOfClass:[NSDictionary class]]) {
  644. videoDic = [dataDict objectForKey:@"video"];
  645. if (ws.config.enableHttps == YES) {
  646. videoURL = [[videoDic objectForKey:@"url"] stringByReplacingOccurrencesOfString:@"http:" withString:@"https:"];
  647. } else {
  648. videoURL = [videoDic objectForKey:@"url"];
  649. }
  650. }
  651. if ([[dataDict objectForKey:@"cover"] isKindOfClass:[NSDictionary class]]) {
  652. coverDic = [dataDict objectForKey:@"cover"];
  653. if (ws.config.enableHttps == YES) {
  654. coverURL = [[coverDic objectForKey:@"url"] stringByReplacingOccurrencesOfString:@"http:" withString:@"https:"];
  655. } else {
  656. coverURL = [coverDic objectForKey:@"url"];
  657. }
  658. }
  659. if ([[dataDict objectForKey:@"fileId"] isKindOfClass:[NSString class]]) {
  660. videoID = [dataDict objectForKey:@"fileId"];
  661. }
  662. }
  663. TVCUploadResponse *finiResp = [[TVCUploadResponse alloc] init];
  664. if (code != TVC_OK) {
  665. //3步骤出错
  666. finiResp.retCode = TVC_ERR_UGC_FINISH_RSP_FAILED;
  667. finiResp.descMsg = [NSString stringWithFormat:@"ugc code:%d, ugc desc:%@ ugc finish http rsp fail", code, msg];
  668. if (result) {
  669. dispatch_async(dispatch_get_main_queue(), ^{
  670. result(finiResp);
  671. long long reqTimeCost = [[NSDate date] timeIntervalSince1970] * 1000 - uploadContext.reqTime;
  672. [ws txReport:TVC_UPLOAD_EVENT_ID_FINISH errCode:finiResp.retCode errInfo:finiResp.descMsg reqTime:uploadContext.reqTime reqTimeCost:reqTimeCost reqKey:ws.reqKey appId:uploadContext.cugResult.userAppid fileSize:uploadContext.videoSize fileType:[ws getFileType:uploadContext.uploadParam.videoPath] fileName:[ws getFileName:uploadContext.uploadParam.videoPath] sessionKey:uploadContext.cugResult.uploadSession fileId:@""];
  673. });
  674. }
  675. return;
  676. } else {
  677. //所有步骤成功完成
  678. finiResp.retCode = TVC_OK;
  679. finiResp.videoId = videoID;
  680. finiResp.videoURL = videoURL;
  681. finiResp.coverURL = coverURL;
  682. if (result) {
  683. dispatch_async(dispatch_get_main_queue(), ^{
  684. result(finiResp);
  685. long long reqTimeCost = [[NSDate date] timeIntervalSince1970] * 1000 - uploadContext.reqTime;
  686. [ws txReport:TVC_UPLOAD_EVENT_ID_FINISH errCode:finiResp.retCode errInfo:finiResp.descMsg reqTime:uploadContext.reqTime reqTimeCost:reqTimeCost reqKey:ws.reqKey appId:uploadContext.cugResult.userAppid fileSize:uploadContext.videoSize fileType:[ws getFileType:uploadContext.uploadParam.videoPath] fileName:[ws getFileName:uploadContext.uploadParam.videoPath] sessionKey:uploadContext.cugResult.uploadSession fileId:videoID];
  687. });
  688. }
  689. return;
  690. }
  691. }];
  692. [finiTask resume];
  693. }
  694. });
  695. }
  696. - (NSString *)getLastComponent:(NSString *)filePath {
  697. return [filePath lastPathComponent];
  698. }
  699. - (NSString *)getFileName:(NSString *)filePath {
  700. return [[filePath lastPathComponent] stringByDeletingPathExtension];
  701. }
  702. - (NSString *)getFileType:(NSString *)filePath {
  703. return [filePath pathExtension];
  704. }
  705. #pragma mark -- 断点续传
  706. // 本地保存 filePath --> session、filePath --> expireTime,filePath --> fileLastModTime, filePath --> resumeData 的映射集合,格式为json
  707. // "TVCMultipartResumeSessionKey": {filePath1: session1, filePath2: session2, filePath3: session3}
  708. // "TVCMultipartResumeExpireTimeKey": {filePath1: expireTime1, filePath2: expireTime2, filePath3: expireTime3}
  709. // session的过期时间是1天
  710. - (NSString *)getSessionFromFilepath:(TVCUploadContext *)uploadContext {
  711. NSString* filePath = uploadContext.uploadParam.videoPath;
  712. if (filePath == nil || filePath.length == 0) {
  713. return nil;
  714. }
  715. NSMutableDictionary *sessionDic = [[NSMutableDictionary alloc] init];
  716. NSMutableDictionary *timeDic = [[NSMutableDictionary alloc] init];
  717. NSMutableDictionary *lastModTimeDic = [[NSMutableDictionary alloc] init];
  718. NSMutableDictionary *resumeDataDic = [[NSMutableDictionary alloc] init];
  719. NSError *jsonErr = nil;
  720. // read [itemPath, session]
  721. NSString *strPathToSession = [[NSUserDefaults standardUserDefaults] objectForKey:TVCMultipartResumeSessionKey];
  722. if (strPathToSession == nil) {
  723. NSLog(@"TVCMultipartResumeSessionKey is nil");
  724. return nil;
  725. }
  726. sessionDic = [NSJSONSerialization JSONObjectWithData:[strPathToSession dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&jsonErr];
  727. if (jsonErr) {
  728. NSLog(@"TVCMultipartResumeSessionKey is not json format: %@", strPathToSession);
  729. return nil;
  730. }
  731. // read [itemPath, expireTime]
  732. NSString *strPathToExpireTime = [[NSUserDefaults standardUserDefaults] objectForKey:TVCMultipartResumeExpireTimeKey];
  733. if (strPathToExpireTime == nil) {
  734. NSLog(@"TVCMultipartResumeSessionKey expireTime is nil");
  735. return nil;
  736. }
  737. timeDic = [NSJSONSerialization JSONObjectWithData:[strPathToExpireTime dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&jsonErr];
  738. if (jsonErr) {
  739. NSLog(@"TVCMultipartResumeExpireTimeKey is not json format: %@", strPathToExpireTime);
  740. return nil;
  741. }
  742. // read [itemPath, fileLastModTime]
  743. NSString *strPathToLastModTime = [[NSUserDefaults standardUserDefaults] objectForKey:TVCMultipartFileLastModTime];
  744. if (strPathToLastModTime == nil) {
  745. NSLog(@"TVCMultipartResumeSessionKey lastModTime is nil");
  746. return nil;
  747. }
  748. lastModTimeDic = [NSJSONSerialization JSONObjectWithData:[strPathToLastModTime dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&jsonErr];
  749. if (jsonErr) {
  750. NSLog(@"TVCMultipartFileLastModTime is not json format: %@", strPathToLastModTime);
  751. return nil;
  752. }
  753. // read [itemPath, resumeData]
  754. NSString *strPathToResumeData = [[NSUserDefaults standardUserDefaults] objectForKey:TVCMultipartResumeData];
  755. if (strPathToResumeData == nil) {
  756. NSLog(@"TVCMultipartResumeSessionKey resumeData is nil");
  757. return nil;
  758. }
  759. resumeDataDic = [NSJSONSerialization JSONObjectWithData:[strPathToResumeData dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&jsonErr];
  760. if (jsonErr) {
  761. NSLog(@"TVCMultipartReumeData is not json format: %@", strPathToResumeData);
  762. return nil;
  763. }
  764. NSString *session = [sessionDic objectForKey:filePath];
  765. NSInteger expireTime = [[timeDic objectForKey:filePath] integerValue];
  766. unsigned long long lastModTime = [[lastModTimeDic objectForKey:filePath] unsignedLongLongValue];
  767. NSString* sResumeData = [resumeDataDic objectForKey:filePath];
  768. NSInteger nowTime = (NSInteger) [[NSDate date] timeIntervalSince1970] + 1;
  769. NSString *ret = nil;
  770. if (session && nowTime < expireTime && lastModTime == uploadContext.videoLastModTime && sResumeData != nil && sResumeData.length != 0) {
  771. ret = session;
  772. NSData *resumeData = [[NSData alloc] initWithBase64EncodedString:sResumeData options:0];
  773. uploadContext.resumeData = resumeData;
  774. } else {
  775. NSLog(@"TVCMultipartReumeData is invalid");
  776. }
  777. // 删除过期的session,并保存
  778. NSMutableDictionary *newSessionDic = [[NSMutableDictionary alloc] init];
  779. NSMutableDictionary *newTimeDic = [[NSMutableDictionary alloc] init];
  780. NSMutableDictionary *newLastModTimeDic = [[NSMutableDictionary alloc] init];
  781. NSMutableDictionary *newResumeDataDic = [[NSMutableDictionary alloc] init];
  782. for (NSString *key in timeDic) {
  783. NSInteger expireTime = [[timeDic objectForKey:key] integerValue];
  784. if (nowTime < expireTime) {
  785. [newSessionDic setValue:[sessionDic objectForKey:key] forKey:key];
  786. [newTimeDic setValue:[timeDic objectForKey:key] forKey:key];
  787. [newLastModTimeDic setValue:[lastModTimeDic objectForKey:key] forKey:key];
  788. [newResumeDataDic setValue:[resumeDataDic objectForKey:key] forKey:key];
  789. }
  790. }
  791. // 将newSessionDic 和 newTimeDic 保存文件
  792. NSData *newSessionJsonData = [NSJSONSerialization dataWithJSONObject:newSessionDic options:0 error:&jsonErr];
  793. NSData *newTimeJsonData = [NSJSONSerialization dataWithJSONObject:newTimeDic options:0 error:&jsonErr];
  794. NSData *newLastModTimeJsonData = [NSJSONSerialization dataWithJSONObject:newLastModTimeDic options:0 error:&jsonErr];
  795. NSData *newResumeDataJsonData = [NSJSONSerialization dataWithJSONObject:newResumeDataDic options:0 error:&jsonErr];
  796. NSString *strNeweSession = [[NSString alloc] initWithData:newSessionJsonData encoding:NSUTF8StringEncoding];
  797. NSString *strNewTime = [[NSString alloc] initWithData:newTimeJsonData encoding:NSUTF8StringEncoding];
  798. NSString *strNewLastModTime = [[NSString alloc] initWithData:newLastModTimeJsonData encoding:NSUTF8StringEncoding];
  799. NSString *strNewResumeData = [[NSString alloc] initWithData:newResumeDataJsonData encoding:NSUTF8StringEncoding];
  800. [[NSUserDefaults standardUserDefaults] setObject:strNeweSession forKey:TVCMultipartResumeSessionKey];
  801. [[NSUserDefaults standardUserDefaults] setObject:strNewTime forKey:TVCMultipartResumeExpireTimeKey];
  802. [[NSUserDefaults standardUserDefaults] setObject:strNewLastModTime forKey:TVCMultipartFileLastModTime];
  803. [[NSUserDefaults standardUserDefaults] setObject:strNewResumeData forKey:TVCMultipartResumeData];
  804. [[NSUserDefaults standardUserDefaults] synchronize];
  805. return ret;
  806. }
  807. - (void)setSession:(NSString *)session resumeData:(NSData *)resumeData lastModTime:(uint64_t)lastModTime withFilePath:(NSString *)filePath {
  808. if (filePath == nil || filePath.length == 0) {
  809. return;
  810. }
  811. NSMutableDictionary *sessionDic = [[NSMutableDictionary alloc] init];
  812. NSMutableDictionary *timeDic = [[NSMutableDictionary alloc] init];
  813. NSMutableDictionary *lastModTimeDic = [[NSMutableDictionary alloc] init];
  814. NSMutableDictionary *resumeDataDic = [[NSMutableDictionary alloc] init];
  815. NSError *jsonErr = nil;
  816. // read [itemPath, session]
  817. NSString *strPathToSession = [[NSUserDefaults standardUserDefaults] objectForKey:TVCMultipartResumeSessionKey];
  818. if (strPathToSession) {
  819. NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:[strPathToSession dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&jsonErr];
  820. sessionDic = [NSMutableDictionary dictionaryWithDictionary:dic];
  821. }
  822. // read [itemPath, expireTime]
  823. NSString *strPathToExpireTime = [[NSUserDefaults standardUserDefaults] objectForKey:TVCMultipartResumeExpireTimeKey];
  824. if (strPathToExpireTime) {
  825. NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:[strPathToExpireTime dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&jsonErr];
  826. timeDic = [NSMutableDictionary dictionaryWithDictionary:dic];
  827. }
  828. // read [itemPath, lastModTime]
  829. NSString *strPathToLastModTime = [[NSUserDefaults standardUserDefaults] objectForKey:TVCMultipartFileLastModTime];
  830. if (strPathToLastModTime) {
  831. NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:[strPathToLastModTime dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&jsonErr];
  832. lastModTimeDic = [NSMutableDictionary dictionaryWithDictionary:dic];
  833. }
  834. // read [itemPath, resumeData]
  835. NSString *strPathToResumeData = [[NSUserDefaults standardUserDefaults] objectForKey:TVCMultipartResumeData];
  836. if (strPathToResumeData) {
  837. NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:[strPathToResumeData dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&jsonErr];
  838. resumeDataDic = [NSMutableDictionary dictionaryWithDictionary:dic];
  839. }
  840. // 设置过期时间为1天
  841. NSInteger expireTime = (NSInteger) [[NSDate date] timeIntervalSince1970] + 24 * 60 * 60;
  842. // session、resumeDataDic 为空,lastModTime为0就表示删掉该 [key, value]
  843. if (session == nil || session.length == 0
  844. || resumeData == nil || resumeData.length == 0
  845. || lastModTime == 0) {
  846. [sessionDic removeObjectForKey:filePath];
  847. [timeDic removeObjectForKey:filePath];
  848. [lastModTimeDic removeObjectForKey:filePath];
  849. [resumeDataDic removeObjectForKey:filePath];
  850. } else {
  851. [sessionDic setValue:session forKey:filePath];
  852. [timeDic setValue:@(expireTime) forKey:filePath];
  853. [lastModTimeDic setValue:@(lastModTime) forKey:filePath];
  854. NSString * sResumeData = [resumeData base64EncodedStringWithOptions:0];
  855. [resumeDataDic setValue:sResumeData forKey:filePath];
  856. }
  857. // 保存文件
  858. NSData *newSessionJsonData = [NSJSONSerialization dataWithJSONObject:sessionDic options:0 error:&jsonErr];
  859. NSData *newTimeJsonData = [NSJSONSerialization dataWithJSONObject:timeDic options:0 error:&jsonErr];
  860. NSData *newLastModTimeJsonData = [NSJSONSerialization dataWithJSONObject:lastModTimeDic options:0 error:&jsonErr];
  861. NSData *newResumeDaaJsonData = [NSJSONSerialization dataWithJSONObject:resumeDataDic options:0 error:&jsonErr];
  862. NSString *strNeweSession = [[NSString alloc] initWithData:newSessionJsonData encoding:NSUTF8StringEncoding];
  863. NSString *strNewTime = [[NSString alloc] initWithData:newTimeJsonData encoding:NSUTF8StringEncoding];
  864. NSString *strNewLastModTime = [[NSString alloc] initWithData:newLastModTimeJsonData encoding:NSUTF8StringEncoding];
  865. NSString *strNewResumeData = [[NSString alloc] initWithData:newResumeDaaJsonData encoding:NSUTF8StringEncoding];
  866. [[NSUserDefaults standardUserDefaults] setObject:strNeweSession forKey:TVCMultipartResumeSessionKey];
  867. [[NSUserDefaults standardUserDefaults] setObject:strNewTime forKey:TVCMultipartResumeExpireTimeKey];
  868. [[NSUserDefaults standardUserDefaults] setObject:strNewLastModTime forKey:TVCMultipartFileLastModTime];
  869. [[NSUserDefaults standardUserDefaults] setObject:strNewResumeData forKey:TVCMultipartResumeData];
  870. [[NSUserDefaults standardUserDefaults] synchronize];
  871. }
  872. - (void) txReport:(int)eventId errCode:(int)errCode errInfo:(NSString*)errInfo reqTime:(int64_t)reqTime reqTimeCost:(int64_t)reqTimeCost reqKey:(NSString*)reqKey appId:(NSString*)appId fileSize:(int64_t)fileSize fileType:(NSString*)fileType fileName:(NSString*)fileName sessionKey:(NSString*)sessionKey fileId:(NSString*)fileId
  873. {
  874. self.reportInfo.reqType = eventId;
  875. self.reportInfo.errCode = errCode;
  876. self.reportInfo.errMsg = (errInfo == nil? @"": errInfo);
  877. self.reportInfo.reqTime = reqTime;
  878. self.reportInfo.reqTimeCost = reqTimeCost;
  879. self.reportInfo.fileSize = fileSize;
  880. self.reportInfo.fileType = fileType;
  881. self.reportInfo.fileName = fileName;
  882. self.reportInfo.appId = [appId longLongValue];
  883. self.reportInfo.reqServerIp = self.serverIP;
  884. self.reportInfo.reportId = self.config.userID;
  885. self.reportInfo.reqKey = reqKey;
  886. self.reportInfo.vodSessionKey = sessionKey;
  887. self.reportInfo.vodSessionKey = sessionKey;
  888. self.reportInfo.fileId = fileId;
  889. [[TVCReport shareInstance] addReportInfo:self.reportInfo];
  890. return;
  891. }
  892. - (NSString *)queryIpWithDomain:(NSString *)domain
  893. {
  894. struct hostent *hs;
  895. struct sockaddr_in server;
  896. if ((hs = gethostbyname([domain UTF8String])) != NULL)
  897. {
  898. server.sin_addr = *((struct in_addr*)hs->h_addr_list[0]);
  899. return [NSString stringWithUTF8String:inet_ntoa(server.sin_addr)];
  900. }
  901. return domain;
  902. }
  903. -(NSDictionary *)getStatusInfo{
  904. NSMutableDictionary *info = [NSMutableDictionary dictionary];
  905. [info setObject:[NSString stringWithFormat:@"%d", self.reportInfo.reqType] forKey:@"reqType"];
  906. [info setObject:[NSString stringWithFormat:@"%d", self.reportInfo.errCode] forKey:@"errCode"];
  907. [info setObject:self.reportInfo.errMsg forKey:@"errMsg"];
  908. [info setObject:[NSString stringWithFormat:@"%lld", self.reportInfo.reqTime] forKey:@"reqTime"];
  909. [info setObject:[NSString stringWithFormat:@"%lld", self.reportInfo.reqTimeCost] forKey:@"reqTimeCost"];
  910. [info setObject:[NSString stringWithFormat:@"%lld", self.reportInfo.fileSize] forKey:@"fileSize"];
  911. [info setObject:self.reportInfo.fileType forKey:@"fileType"];
  912. [info setObject:self.reportInfo.fileName forKey:@"fileName"];
  913. [info setObject:self.reportInfo.fileId forKey:@"fileId"];
  914. [info setObject:[NSString stringWithFormat:@"%lld", self.reportInfo.appId] forKey:@"appId"];
  915. [info setObject:self.reportInfo.reqServerIp forKey:@"reqServerIp"];
  916. [info setObject:self.reportInfo.reportId forKey:@"reportId"];
  917. [info setObject:self.reportInfo.reqKey forKey:@"reqKey"];
  918. [info setObject:self.reportInfo.vodSessionKey forKey:@"vodSessionKey"];
  919. return info;
  920. }
  921. @end