QNPartsUpload.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. //
  2. // QNPartsUpload.m
  3. // QiniuSDK_Mac
  4. //
  5. // Created by yangsen on 2020/5/7.
  6. // Copyright © 2020 Qiniu. All rights reserved.
  7. //
  8. #import "QNDefine.h"
  9. #import "QNUtils.h"
  10. #import "QNLogUtil.h"
  11. #import "QNPartsUpload.h"
  12. #import "QNZoneInfo.h"
  13. #import "QNReportItem.h"
  14. #import "QNRequestTransaction.h"
  15. #import "QNPartsUploadPerformerV1.h"
  16. #import "QNPartsUploadPerformerV2.h"
  17. #define kQNRecordFileInfoKey @"recordFileInfo"
  18. #define kQNRecordZoneInfoKey @"recordZoneInfo"
  19. @interface QNPartsUpload()
  20. @property(nonatomic, strong)QNPartsUploadPerformer *uploadPerformer;
  21. @property( atomic, strong)QNResponseInfo *uploadDataErrorResponseInfo;
  22. @property( atomic, strong)NSDictionary *uploadDataErrorResponse;
  23. @end
  24. @implementation QNPartsUpload
  25. - (void)initData {
  26. [super initData];
  27. // 根据文件从本地恢复上传信息,如果没有则重新构建上传信息
  28. if (self.config.resumeUploadVersion == QNResumeUploadVersionV1) {
  29. QNLogInfo(@"key:%@ 分片V1", self.key);
  30. self.uploadPerformer = [[QNPartsUploadPerformerV1 alloc] initWithSource:self.uploadSource
  31. fileName:self.fileName
  32. key:self.key
  33. token:self.token
  34. option:self.option
  35. configuration:self.config
  36. recorderKey:self.recorderKey];
  37. } else {
  38. QNLogInfo(@"key:%@ 分片V2", self.key);
  39. self.uploadPerformer = [[QNPartsUploadPerformerV2 alloc] initWithSource:self.uploadSource
  40. fileName:self.fileName
  41. key:self.key
  42. token:self.token
  43. option:self.option
  44. configuration:self.config
  45. recorderKey:self.recorderKey];
  46. }
  47. }
  48. - (BOOL)isAllUploaded {
  49. return [self.uploadPerformer.uploadInfo isAllUploaded];
  50. }
  51. - (void)setErrorResponseInfo:(QNResponseInfo *)responseInfo errorResponse:(NSDictionary *)response{
  52. if (!responseInfo) {
  53. return;
  54. }
  55. if (!self.uploadDataErrorResponseInfo || responseInfo.statusCode != kQNSDKInteriorError) {
  56. self.uploadDataErrorResponseInfo = responseInfo;
  57. self.uploadDataErrorResponse = response ?: responseInfo.responseDictionary;
  58. }
  59. }
  60. - (int)prepareToUpload{
  61. int code = [super prepareToUpload];
  62. if (code != 0) {
  63. return code;
  64. }
  65. // 配置当前region
  66. if (self.uploadPerformer.currentRegion && self.uploadPerformer.currentRegion.isValid) {
  67. // currentRegion有值,为断点续传,将region插入至regionList第一处
  68. [self insertRegionAtFirst:self.uploadPerformer.currentRegion];
  69. QNLogInfo(@"key:%@ 使用缓存region", self.key);
  70. } else {
  71. // currentRegion无值 切换region
  72. [self.uploadPerformer switchRegion:[self getCurrentRegion]];
  73. }
  74. QNLogInfo(@"key:%@ region:%@", self.key, self.uploadPerformer.currentRegion.zoneInfo.regionId);
  75. if (self.uploadSource == nil) {
  76. code = kQNLocalIOError;
  77. }
  78. return code;
  79. }
  80. - (BOOL)switchRegion{
  81. BOOL isSuccess = [super switchRegion];
  82. if (isSuccess) {
  83. [self.uploadPerformer switchRegion:self.getCurrentRegion];
  84. QNLogInfo(@"key:%@ 切换region:%@", self.key , self.uploadPerformer.currentRegion.zoneInfo.regionId);
  85. }
  86. return isSuccess;
  87. }
  88. - (BOOL)switchRegionAndUploadIfNeededWithErrorResponse:(QNResponseInfo *)errorResponseInfo {
  89. [self reportBlock];
  90. return [super switchRegionAndUploadIfNeededWithErrorResponse:errorResponseInfo];
  91. }
  92. - (BOOL)reloadUploadInfo {
  93. if (![super reloadUploadInfo]) {
  94. return NO;
  95. }
  96. // 重新加载资源
  97. return [self.uploadPerformer couldReloadInfo] && [self.uploadPerformer reloadInfo];
  98. }
  99. - (void)startToUpload{
  100. [super startToUpload];
  101. // 重置错误信息
  102. self.uploadDataErrorResponseInfo = nil;
  103. self.uploadDataErrorResponse = nil;
  104. QNLogInfo(@"key:%@ serverInit", self.key);
  105. // 1. 启动upload
  106. kQNWeakSelf;
  107. [self serverInit:^(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response) {
  108. kQNStrongSelf;
  109. if (!responseInfo.isOK) {
  110. if (![self switchRegionAndUploadIfNeededWithErrorResponse:responseInfo]) {
  111. [self complete:responseInfo response:response];
  112. }
  113. return;
  114. }
  115. QNLogInfo(@"key:%@ uploadRestData", self.key);
  116. // 2. 上传数据
  117. kQNWeakSelf;
  118. [self uploadRestData:^{
  119. kQNStrongSelf;
  120. if (![self isAllUploaded]) {
  121. if (![self switchRegionAndUploadIfNeededWithErrorResponse:self.uploadDataErrorResponseInfo]) {
  122. [self complete:self.uploadDataErrorResponseInfo response:self.uploadDataErrorResponse];
  123. }
  124. return;
  125. }
  126. // 只有再读取结束再能知道文件大小,需要检测
  127. if ([self.uploadPerformer.uploadInfo getSourceSize] == 0) {
  128. QNResponseInfo *responseInfo = [QNResponseInfo responseInfoOfZeroData:@"file is empty"];
  129. [self complete:responseInfo response:responseInfo.responseDictionary];
  130. return;
  131. }
  132. QNLogInfo(@"key:%@ completeUpload errorResponseInfo:%@", self.key, self.uploadDataErrorResponseInfo);
  133. // 3. 组装文件
  134. kQNWeakSelf;
  135. [self completeUpload:^(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response) {
  136. kQNStrongSelf;
  137. if (!responseInfo.isOK) {
  138. if (![self switchRegionAndUploadIfNeededWithErrorResponse:responseInfo]) {
  139. [self complete:responseInfo response:response];
  140. }
  141. return;
  142. }
  143. [self complete:responseInfo response:response];
  144. }];
  145. }];
  146. }];
  147. }
  148. - (void)uploadRestData:(dispatch_block_t)completeHandler {
  149. QNLogInfo(@"key:%@ 串行分片", self.key);
  150. [self performUploadRestData:completeHandler];
  151. }
  152. - (void)performUploadRestData:(dispatch_block_t)completeHandler {
  153. if ([self isAllUploaded]) {
  154. completeHandler();
  155. return;
  156. }
  157. kQNWeakSelf;
  158. [self uploadNextData:^(BOOL stop, QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response) {
  159. kQNStrongSelf;
  160. if (stop || !responseInfo.isOK) {
  161. completeHandler();
  162. } else {
  163. [self performUploadRestData:completeHandler];
  164. }
  165. }];
  166. }
  167. //MARK:-- concurrent upload model API
  168. - (void)serverInit:(void(^)(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))completeHandler {
  169. kQNWeakSelf;
  170. void(^completeHandlerP)(QNResponseInfo *, QNUploadRegionRequestMetrics *, NSDictionary *) = ^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response){
  171. kQNStrongSelf;
  172. if (!responseInfo.isOK) {
  173. [self setErrorResponseInfo:responseInfo errorResponse:response];
  174. }
  175. [self addRegionRequestMetricsOfOneFlow:metrics];
  176. completeHandler(responseInfo, response);
  177. };
  178. [self.uploadPerformer serverInit:completeHandlerP];
  179. }
  180. - (void)uploadNextData:(void(^)(BOOL stop, QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))completeHandler {
  181. kQNWeakSelf;
  182. void(^completeHandlerP)(BOOL, QNResponseInfo *, QNUploadRegionRequestMetrics *, NSDictionary *) = ^(BOOL stop, QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response){
  183. kQNStrongSelf;
  184. if (!responseInfo.isOK) {
  185. [self setErrorResponseInfo:responseInfo errorResponse:response];
  186. }
  187. [self addRegionRequestMetricsOfOneFlow:metrics];
  188. completeHandler(stop, responseInfo, response);
  189. };
  190. [self.uploadPerformer uploadNextData:completeHandlerP];
  191. }
  192. - (void)completeUpload:(void(^)(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))completeHandler {
  193. kQNWeakSelf;
  194. void(^completeHandlerP)(QNResponseInfo *, QNUploadRegionRequestMetrics *, NSDictionary *) = ^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response){
  195. kQNStrongSelf;
  196. if (!responseInfo.isOK) {
  197. [self setErrorResponseInfo:responseInfo errorResponse:response];
  198. }
  199. [self addRegionRequestMetricsOfOneFlow:metrics];
  200. completeHandler(responseInfo, response);
  201. };
  202. [self.uploadPerformer completeUpload:completeHandlerP];
  203. }
  204. - (void)complete:(QNResponseInfo *)info response:(NSDictionary *)response{
  205. [self.uploadSource close];
  206. if ([self shouldRemoveUploadInfoRecord:info]) {
  207. [self.uploadPerformer removeUploadInfoRecord];
  208. }
  209. [super complete:info response:response];
  210. [self reportBlock];
  211. }
  212. - (BOOL)shouldRemoveUploadInfoRecord:(QNResponseInfo *)info {
  213. return info.isOK || info.statusCode == 612 || info.statusCode == 614 || info.statusCode == 701;
  214. }
  215. //MARK:-- 统计block日志
  216. - (void)reportBlock{
  217. QNUploadRegionRequestMetrics *metrics = self.currentRegionRequestMetrics ?: [QNUploadRegionRequestMetrics emptyMetrics];
  218. QNReportItem *item = [QNReportItem item];
  219. [item setReportValue:QNReportLogTypeBlock forKey:QNReportBlockKeyLogType];
  220. [item setReportValue:@([[NSDate date] timeIntervalSince1970]) forKey:QNReportBlockKeyUpTime];
  221. [item setReportValue:self.token.bucket forKey:QNReportBlockKeyTargetBucket];
  222. [item setReportValue:self.key forKey:QNReportBlockKeyTargetKey];
  223. [item setReportValue:[self getTargetRegion].zoneInfo.regionId forKey:QNReportBlockKeyTargetRegionId];
  224. [item setReportValue:[self getCurrentRegion].zoneInfo.regionId forKey:QNReportBlockKeyCurrentRegionId];
  225. [item setReportValue:metrics.totalElapsedTime forKey:QNReportBlockKeyTotalElapsedTime];
  226. [item setReportValue:metrics.bytesSend forKey:QNReportBlockKeyBytesSent];
  227. [item setReportValue:self.uploadPerformer.recoveredFrom forKey:QNReportBlockKeyRecoveredFrom];
  228. [item setReportValue:@([self.uploadSource getSize]) forKey:QNReportBlockKeyFileSize];
  229. [item setReportValue:@([QNUtils getCurrentProcessID]) forKey:QNReportBlockKeyPid];
  230. [item setReportValue:@([QNUtils getCurrentThreadID]) forKey:QNReportBlockKeyTid];
  231. [item setReportValue:metrics.metricsList.lastObject.hijacked forKey:QNReportBlockKeyHijacking];
  232. // 统计当前 region 上传速度 文件大小 / 总耗时
  233. if (self.uploadDataErrorResponseInfo == nil && [self.uploadSource getSize] > 0 && [metrics totalElapsedTime] > 0) {
  234. NSNumber *speed = [QNUtils calculateSpeed:[self.uploadSource getSize] totalTime:[metrics totalElapsedTime].longLongValue];
  235. [item setReportValue:speed forKey:QNReportBlockKeyPerceptiveSpeed];
  236. }
  237. if (self.config.resumeUploadVersion == QNResumeUploadVersionV1) {
  238. [item setReportValue:@(1) forKey:QNReportBlockKeyUpApiVersion];
  239. } else {
  240. [item setReportValue:@(2) forKey:QNReportBlockKeyUpApiVersion];
  241. }
  242. [item setReportValue:[QNUtils getCurrentNetworkType] forKey:QNReportBlockKeyClientTime];
  243. [item setReportValue:[QNUtils systemName] forKey:QNReportBlockKeyOsName];
  244. [item setReportValue:[QNUtils systemVersion] forKey:QNReportBlockKeyOsVersion];
  245. [item setReportValue:[QNUtils sdkLanguage] forKey:QNReportBlockKeySDKName];
  246. [item setReportValue:[QNUtils sdkVersion] forKey:QNReportBlockKeySDKVersion];
  247. [kQNReporter reportItem:item token:self.token.token];
  248. }
  249. - (NSString *)upType {
  250. if (self.config == nil) {
  251. return nil;
  252. }
  253. NSString *sourceType = @"";
  254. if ([self.uploadSource respondsToSelector:@selector(sourceType)]) {
  255. sourceType = [self.uploadSource sourceType];
  256. }
  257. if (self.config.resumeUploadVersion == QNResumeUploadVersionV1) {
  258. return [NSString stringWithFormat:@"%@<%@>",QNUploadUpTypeResumableV1, sourceType];
  259. } else {
  260. return [NSString stringWithFormat:@"%@<%@>",QNUploadUpTypeResumableV2, sourceType];
  261. }
  262. }
  263. @end