123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- //
- // QNPartsUpload.m
- // QiniuSDK_Mac
- //
- // Created by yangsen on 2020/5/7.
- // Copyright © 2020 Qiniu. All rights reserved.
- //
- #import "QNDefine.h"
- #import "QNUtils.h"
- #import "QNLogUtil.h"
- #import "QNPartsUpload.h"
- #import "QNZoneInfo.h"
- #import "QNReportItem.h"
- #import "QNRequestTransaction.h"
- #import "QNPartsUploadPerformerV1.h"
- #import "QNPartsUploadPerformerV2.h"
- #define kQNRecordFileInfoKey @"recordFileInfo"
- #define kQNRecordZoneInfoKey @"recordZoneInfo"
- @interface QNPartsUpload()
- @property(nonatomic, strong)QNPartsUploadPerformer *uploadPerformer;
- @property( atomic, strong)QNResponseInfo *uploadDataErrorResponseInfo;
- @property( atomic, strong)NSDictionary *uploadDataErrorResponse;
- @end
- @implementation QNPartsUpload
- - (void)initData {
- [super initData];
- // 根据文件从本地恢复上传信息,如果没有则重新构建上传信息
- if (self.config.resumeUploadVersion == QNResumeUploadVersionV1) {
- QNLogInfo(@"key:%@ 分片V1", self.key);
- self.uploadPerformer = [[QNPartsUploadPerformerV1 alloc] initWithSource:self.uploadSource
- fileName:self.fileName
- key:self.key
- token:self.token
- option:self.option
- configuration:self.config
- recorderKey:self.recorderKey];
- } else {
- QNLogInfo(@"key:%@ 分片V2", self.key);
- self.uploadPerformer = [[QNPartsUploadPerformerV2 alloc] initWithSource:self.uploadSource
- fileName:self.fileName
- key:self.key
- token:self.token
- option:self.option
- configuration:self.config
- recorderKey:self.recorderKey];
- }
- }
- - (BOOL)isAllUploaded {
- return [self.uploadPerformer.uploadInfo isAllUploaded];
- }
- - (void)setErrorResponseInfo:(QNResponseInfo *)responseInfo errorResponse:(NSDictionary *)response{
- if (!responseInfo) {
- return;
- }
- if (!self.uploadDataErrorResponseInfo || responseInfo.statusCode != kQNSDKInteriorError) {
- self.uploadDataErrorResponseInfo = responseInfo;
- self.uploadDataErrorResponse = response ?: responseInfo.responseDictionary;
- }
- }
- - (int)prepareToUpload{
- int code = [super prepareToUpload];
- if (code != 0) {
- return code;
- }
-
- // 配置当前region
- if (self.uploadPerformer.currentRegion && self.uploadPerformer.currentRegion.isValid) {
- // currentRegion有值,为断点续传,将region插入至regionList第一处
- [self insertRegionAtFirst:self.uploadPerformer.currentRegion];
- QNLogInfo(@"key:%@ 使用缓存region", self.key);
- } else {
- // currentRegion无值 切换region
- [self.uploadPerformer switchRegion:[self getCurrentRegion]];
- }
- QNLogInfo(@"key:%@ region:%@", self.key, self.uploadPerformer.currentRegion.zoneInfo.regionId);
-
- if (self.uploadSource == nil) {
- code = kQNLocalIOError;
- }
- return code;
- }
- - (BOOL)switchRegion{
- BOOL isSuccess = [super switchRegion];
- if (isSuccess) {
- [self.uploadPerformer switchRegion:self.getCurrentRegion];
- QNLogInfo(@"key:%@ 切换region:%@", self.key , self.uploadPerformer.currentRegion.zoneInfo.regionId);
- }
- return isSuccess;
- }
- - (BOOL)switchRegionAndUploadIfNeededWithErrorResponse:(QNResponseInfo *)errorResponseInfo {
- [self reportBlock];
- return [super switchRegionAndUploadIfNeededWithErrorResponse:errorResponseInfo];
- }
- - (BOOL)reloadUploadInfo {
- if (![super reloadUploadInfo]) {
- return NO;
- }
-
- // 重新加载资源
- return [self.uploadPerformer couldReloadInfo] && [self.uploadPerformer reloadInfo];
- }
- - (void)startToUpload{
- [super startToUpload];
- // 重置错误信息
- self.uploadDataErrorResponseInfo = nil;
- self.uploadDataErrorResponse = nil;
-
-
- QNLogInfo(@"key:%@ serverInit", self.key);
-
- // 1. 启动upload
- kQNWeakSelf;
- [self serverInit:^(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response) {
- kQNStrongSelf;
-
- if (!responseInfo.isOK) {
- if (![self switchRegionAndUploadIfNeededWithErrorResponse:responseInfo]) {
- [self complete:responseInfo response:response];
- }
- return;
- }
-
- QNLogInfo(@"key:%@ uploadRestData", self.key);
-
- // 2. 上传数据
- kQNWeakSelf;
- [self uploadRestData:^{
- kQNStrongSelf;
-
- if (![self isAllUploaded]) {
- if (![self switchRegionAndUploadIfNeededWithErrorResponse:self.uploadDataErrorResponseInfo]) {
- [self complete:self.uploadDataErrorResponseInfo response:self.uploadDataErrorResponse];
- }
- return;
- }
-
- // 只有再读取结束再能知道文件大小,需要检测
- if ([self.uploadPerformer.uploadInfo getSourceSize] == 0) {
- QNResponseInfo *responseInfo = [QNResponseInfo responseInfoOfZeroData:@"file is empty"];
- [self complete:responseInfo response:responseInfo.responseDictionary];
- return;
- }
-
- QNLogInfo(@"key:%@ completeUpload errorResponseInfo:%@", self.key, self.uploadDataErrorResponseInfo);
-
- // 3. 组装文件
- kQNWeakSelf;
- [self completeUpload:^(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response) {
- kQNStrongSelf;
-
- if (!responseInfo.isOK) {
- if (![self switchRegionAndUploadIfNeededWithErrorResponse:responseInfo]) {
- [self complete:responseInfo response:response];
- }
- return;
- }
- [self complete:responseInfo response:response];
- }];
- }];
- }];
- }
- - (void)uploadRestData:(dispatch_block_t)completeHandler {
- QNLogInfo(@"key:%@ 串行分片", self.key);
- [self performUploadRestData:completeHandler];
- }
- - (void)performUploadRestData:(dispatch_block_t)completeHandler {
- if ([self isAllUploaded]) {
- completeHandler();
- return;
- }
-
- kQNWeakSelf;
- [self uploadNextData:^(BOOL stop, QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response) {
- kQNStrongSelf;
-
- if (stop || !responseInfo.isOK) {
- completeHandler();
- } else {
- [self performUploadRestData:completeHandler];
- }
- }];
- }
- //MARK:-- concurrent upload model API
- - (void)serverInit:(void(^)(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))completeHandler {
-
- kQNWeakSelf;
- void(^completeHandlerP)(QNResponseInfo *, QNUploadRegionRequestMetrics *, NSDictionary *) = ^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response){
- kQNStrongSelf;
-
- if (!responseInfo.isOK) {
- [self setErrorResponseInfo:responseInfo errorResponse:response];
- }
- [self addRegionRequestMetricsOfOneFlow:metrics];
- completeHandler(responseInfo, response);
- };
-
- [self.uploadPerformer serverInit:completeHandlerP];
- }
- - (void)uploadNextData:(void(^)(BOOL stop, QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))completeHandler {
-
- kQNWeakSelf;
- void(^completeHandlerP)(BOOL, QNResponseInfo *, QNUploadRegionRequestMetrics *, NSDictionary *) = ^(BOOL stop, QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response){
- kQNStrongSelf;
-
- if (!responseInfo.isOK) {
- [self setErrorResponseInfo:responseInfo errorResponse:response];
- }
- [self addRegionRequestMetricsOfOneFlow:metrics];
- completeHandler(stop, responseInfo, response);
- };
-
- [self.uploadPerformer uploadNextData:completeHandlerP];
- }
- - (void)completeUpload:(void(^)(QNResponseInfo * _Nullable responseInfo, NSDictionary * _Nullable response))completeHandler {
-
- kQNWeakSelf;
- void(^completeHandlerP)(QNResponseInfo *, QNUploadRegionRequestMetrics *, NSDictionary *) = ^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response){
- kQNStrongSelf;
-
- if (!responseInfo.isOK) {
- [self setErrorResponseInfo:responseInfo errorResponse:response];
- }
- [self addRegionRequestMetricsOfOneFlow:metrics];
- completeHandler(responseInfo, response);
- };
- [self.uploadPerformer completeUpload:completeHandlerP];
- }
- - (void)complete:(QNResponseInfo *)info response:(NSDictionary *)response{
- [self.uploadSource close];
- if ([self shouldRemoveUploadInfoRecord:info]) {
- [self.uploadPerformer removeUploadInfoRecord];
- }
-
- [super complete:info response:response];
-
- [self reportBlock];
- }
- - (BOOL)shouldRemoveUploadInfoRecord:(QNResponseInfo *)info {
- return info.isOK || info.statusCode == 612 || info.statusCode == 614 || info.statusCode == 701;
- }
- //MARK:-- 统计block日志
- - (void)reportBlock{
-
- QNUploadRegionRequestMetrics *metrics = self.currentRegionRequestMetrics ?: [QNUploadRegionRequestMetrics emptyMetrics];
-
- QNReportItem *item = [QNReportItem item];
- [item setReportValue:QNReportLogTypeBlock forKey:QNReportBlockKeyLogType];
- [item setReportValue:@([[NSDate date] timeIntervalSince1970]) forKey:QNReportBlockKeyUpTime];
- [item setReportValue:self.token.bucket forKey:QNReportBlockKeyTargetBucket];
- [item setReportValue:self.key forKey:QNReportBlockKeyTargetKey];
- [item setReportValue:[self getTargetRegion].zoneInfo.regionId forKey:QNReportBlockKeyTargetRegionId];
- [item setReportValue:[self getCurrentRegion].zoneInfo.regionId forKey:QNReportBlockKeyCurrentRegionId];
- [item setReportValue:metrics.totalElapsedTime forKey:QNReportBlockKeyTotalElapsedTime];
- [item setReportValue:metrics.bytesSend forKey:QNReportBlockKeyBytesSent];
- [item setReportValue:self.uploadPerformer.recoveredFrom forKey:QNReportBlockKeyRecoveredFrom];
- [item setReportValue:@([self.uploadSource getSize]) forKey:QNReportBlockKeyFileSize];
- [item setReportValue:@([QNUtils getCurrentProcessID]) forKey:QNReportBlockKeyPid];
- [item setReportValue:@([QNUtils getCurrentThreadID]) forKey:QNReportBlockKeyTid];
-
- [item setReportValue:metrics.metricsList.lastObject.hijacked forKey:QNReportBlockKeyHijacking];
-
- // 统计当前 region 上传速度 文件大小 / 总耗时
- if (self.uploadDataErrorResponseInfo == nil && [self.uploadSource getSize] > 0 && [metrics totalElapsedTime] > 0) {
- NSNumber *speed = [QNUtils calculateSpeed:[self.uploadSource getSize] totalTime:[metrics totalElapsedTime].longLongValue];
- [item setReportValue:speed forKey:QNReportBlockKeyPerceptiveSpeed];
- }
- if (self.config.resumeUploadVersion == QNResumeUploadVersionV1) {
- [item setReportValue:@(1) forKey:QNReportBlockKeyUpApiVersion];
- } else {
- [item setReportValue:@(2) forKey:QNReportBlockKeyUpApiVersion];
- }
-
- [item setReportValue:[QNUtils getCurrentNetworkType] forKey:QNReportBlockKeyClientTime];
- [item setReportValue:[QNUtils systemName] forKey:QNReportBlockKeyOsName];
- [item setReportValue:[QNUtils systemVersion] forKey:QNReportBlockKeyOsVersion];
- [item setReportValue:[QNUtils sdkLanguage] forKey:QNReportBlockKeySDKName];
- [item setReportValue:[QNUtils sdkVersion] forKey:QNReportBlockKeySDKVersion];
-
- [kQNReporter reportItem:item token:self.token.token];
- }
- - (NSString *)upType {
- if (self.config == nil) {
- return nil;
- }
-
- NSString *sourceType = @"";
- if ([self.uploadSource respondsToSelector:@selector(sourceType)]) {
- sourceType = [self.uploadSource sourceType];
- }
- if (self.config.resumeUploadVersion == QNResumeUploadVersionV1) {
- return [NSString stringWithFormat:@"%@<%@>",QNUploadUpTypeResumableV1, sourceType];
- } else {
- return [NSString stringWithFormat:@"%@<%@>",QNUploadUpTypeResumableV2, sourceType];
- }
- }
- @end
|