QNFormUpload.m 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. //
  2. // QNFormUpload.m
  3. // QiniuSDK
  4. //
  5. // Created by bailong on 15/1/4.
  6. // Copyright (c) 2015年 Qiniu. All rights reserved.
  7. //
  8. #import "QNFormUpload.h"
  9. @interface QNFormUpload ()
  10. @property (nonatomic, strong) NSData *data;
  11. @property (nonatomic) int retryTimes;
  12. @property (nonatomic, strong) NSString *fileName;
  13. @property (nonatomic) float previousPercent;
  14. @end
  15. @implementation QNFormUpload
  16. - (instancetype)initWithData:(NSData *)data
  17. withKey:(NSString *)key
  18. withFileName:(NSString *)fileName
  19. withToken:(QNUpToken *)token
  20. withIdentifier:(NSString *)identifier
  21. withCompletionHandler:(QNUpCompletionHandler)block
  22. withOption:(QNUploadOption *)option
  23. withSessionManager:(QNSessionManager *)sessionManager
  24. withConfiguration:(QNConfiguration *)config {
  25. if (self = [super init]) {
  26. self.data = data;
  27. self.size = (UInt32)data.length;
  28. self.key = key;
  29. self.token = token;
  30. self.option = option != nil ? option : [QNUploadOption defaultOptions];
  31. self.complete = block;
  32. self.sessionManager = sessionManager;
  33. self.config = config;
  34. self.fileName = fileName != nil ? fileName : @"?";
  35. self.previousPercent = 0;
  36. self.access = token.access;
  37. self.currentZoneType = QNZoneInfoTypeMain;
  38. self.identifier = identifier;
  39. self.requestType = QNRequestType_form;
  40. }
  41. return self;
  42. }
  43. - (void)put {
  44. NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
  45. if (self.key) {
  46. parameters[@"key"] = self.key;
  47. }
  48. parameters[@"token"] = self.token.token;
  49. [parameters addEntriesFromDictionary:self.option.params];
  50. parameters[@"crc32"] = [NSString stringWithFormat:@"%u", (unsigned int)[QNCrc32 data:_data]];
  51. [self nextTask:0 needDelay:NO host:[self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:nil] param:parameters];
  52. }
  53. - (void)nextTask:(int)retried needDelay:(BOOL)needDelay host:(NSString *)host param:(NSDictionary *)param {
  54. if (needDelay) {
  55. QNAsyncRunAfter(self.config.retryInterval, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  56. [self nextTask:retried host:host param:param];
  57. });
  58. } else {
  59. [self nextTask:retried host:host param:param];
  60. }
  61. }
  62. - (void)nextTask:(int)retried host:(NSString *)host param:(NSDictionary *)param {
  63. if (self.option.cancellationSignal()) {
  64. [self collectUploadQualityInfo];
  65. QNResponseInfo *info = [Collector userCancel:self.identifier];
  66. self.complete(info, self.key, nil);
  67. return;
  68. }
  69. QNInternalProgressBlock p = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) {
  70. float percent = (float)totalBytesWritten / (float)totalBytesExpectedToWrite;
  71. if (percent > 0.95) {
  72. percent = 0.95;
  73. }
  74. if (percent > self.previousPercent) {
  75. self.previousPercent = percent;
  76. } else {
  77. percent = self.previousPercent;
  78. }
  79. self.option.progressHandler(self.key, percent);
  80. };
  81. QNCompleteBlock complete = ^(QNHttpResponseInfo *httpResponseInfo, NSDictionary *respBody) {
  82. [self collectHttpResponseInfo:httpResponseInfo fileOffset:QN_IntNotSet];
  83. if (httpResponseInfo.isOK) {
  84. self.option.progressHandler(self.key, 1.0);
  85. [self collectUploadQualityInfo];
  86. QNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
  87. self.complete(info, self.key, respBody);
  88. } else if (httpResponseInfo.couldRetry) {
  89. if (retried < self.config.retryMax) {
  90. [self nextTask:retried + 1 needDelay:YES host:host param:param];
  91. } else {
  92. if (self.config.allowBackupHost) {
  93. NSString *nextHost = [self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:host];
  94. if (nextHost) {
  95. [self nextTask:0 needDelay:YES host:nextHost param:param];
  96. } else {
  97. QNZonesInfo *zonesInfo = [self.config.zone getZonesInfoWithToken:self.token];
  98. if (self.currentZoneType == QNZoneInfoTypeMain && zonesInfo.hasBackupZone) {
  99. self.currentZoneType = QNZoneInfoTypeBackup;
  100. [self nextTask:0 needDelay:YES host:[self.config.zone up:self.token zoneInfoType:self.currentZoneType isHttps:self.config.useHttps frozenDomain:nil] param:param];
  101. } else {
  102. [self collectUploadQualityInfo];
  103. QNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
  104. self.complete(info, self.key, respBody);
  105. }
  106. }
  107. } else {
  108. [self collectUploadQualityInfo];
  109. QNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
  110. self.complete(info, self.key, respBody);
  111. }
  112. }
  113. } else {
  114. [self collectUploadQualityInfo];
  115. QNResponseInfo *info = [Collector completeWithHttpResponseInfo:httpResponseInfo identifier:self.identifier];
  116. self.complete(info, self.key, respBody);
  117. }
  118. };
  119. [self.sessionManager multipartPost:host
  120. withData:self.data
  121. withParams:param
  122. withFileName:self.fileName
  123. withMimeType:self.option.mimeType
  124. withIdentifier:self.identifier
  125. withCompleteBlock:complete
  126. withProgressBlock:p
  127. withCancelBlock:self.option.cancellationSignal
  128. withAccess:self.access];
  129. }
  130. @end