QNRequestTransaction.m 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. //
  2. // QNRequestTransaction.m
  3. // QiniuSDK
  4. //
  5. // Created by yangsen on 2020/4/30.
  6. // Copyright © 2020 Qiniu. All rights reserved.
  7. //
  8. #import "QNRequestTransaction.h"
  9. #import "QNDefine.h"
  10. #import "QNUtils.h"
  11. #import "QNCrc32.h"
  12. #import "NSData+QNMD5.h"
  13. #import "QNUrlSafeBase64.h"
  14. #import "QNUpToken.h"
  15. #import "QNConfiguration.h"
  16. #import "QNUploadOption.h"
  17. #import "QNZoneInfo.h"
  18. #import "QNUserAgent.h"
  19. #import "QNResponseInfo.h"
  20. #import "QNUploadRequestState.h"
  21. #import "QNUploadRequestMetrics.h"
  22. #import "QNUploadDomainRegion.h"
  23. #import "QNHttpRegionRequest.h"
  24. @interface QNRequestTransaction()
  25. @property(nonatomic, strong)QNConfiguration *config;
  26. @property(nonatomic, strong)QNUploadOption *uploadOption;
  27. @property(nonatomic, copy)NSString *key;
  28. @property(nonatomic, strong)QNUpToken *token;
  29. @property(nonatomic, strong)QNUploadRequestInfo *requestInfo;
  30. @property(nonatomic, strong)QNUploadRequestState *requestState;
  31. @property(nonatomic, strong)QNHttpRegionRequest *regionRequest;
  32. @end
  33. @implementation QNRequestTransaction
  34. - (instancetype)initWithHosts:(NSArray <NSString *> *)hosts
  35. regionId:(NSString * _Nullable)regionId
  36. token:(QNUpToken *)token{
  37. return [self initWithConfig:[QNConfiguration defaultConfiguration]
  38. uploadOption:[QNUploadOption defaultOptions]
  39. hosts:hosts
  40. regionId:regionId
  41. key:nil
  42. token:token];
  43. }
  44. - (instancetype)initWithConfig:(QNConfiguration *)config
  45. uploadOption:(QNUploadOption *)uploadOption
  46. hosts:(NSArray <NSString *> *)hosts
  47. regionId:(NSString * _Nullable)regionId
  48. key:(NSString * _Nullable)key
  49. token:(nonnull QNUpToken *)token{
  50. QNUploadDomainRegion *region = [[QNUploadDomainRegion alloc] init];
  51. [region setupRegionData:[QNZoneInfo zoneInfoWithMainHosts:hosts regionId:regionId]];
  52. return [self initWithConfig:config
  53. uploadOption:uploadOption
  54. targetRegion:region
  55. currentRegion:region
  56. key:key
  57. token:token];
  58. }
  59. - (instancetype)initWithConfig:(QNConfiguration *)config
  60. uploadOption:(QNUploadOption *)uploadOption
  61. targetRegion:(id <QNUploadRegion>)targetRegion
  62. currentRegion:(id <QNUploadRegion>)currentRegion
  63. key:(NSString *)key
  64. token:(QNUpToken *)token{
  65. if (self = [super init]) {
  66. _config = config;
  67. _uploadOption = uploadOption;
  68. _requestState = [[QNUploadRequestState alloc] init];
  69. _key = key;
  70. _token = token;
  71. _requestInfo = [[QNUploadRequestInfo alloc] init];
  72. _requestInfo.targetRegionId = targetRegion.zoneInfo.regionId;
  73. _requestInfo.currentRegionId = currentRegion.zoneInfo.regionId;
  74. _requestInfo.bucket = token.bucket;
  75. _requestInfo.key = key;
  76. _regionRequest = [[QNHttpRegionRequest alloc] initWithConfig:config
  77. uploadOption:uploadOption
  78. token:token
  79. region:currentRegion
  80. requestInfo:_requestInfo
  81. requestState:_requestState];
  82. }
  83. return self;
  84. }
  85. //MARK: -- uc query
  86. - (void)queryUploadHosts:(QNRequestTransactionCompleteHandler)complete{
  87. self.requestInfo.requestType = QNUploadRequestTypeUCQuery;
  88. BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
  89. return (BOOL)!responseInfo.isOK;
  90. };
  91. NSDictionary *header = @{@"User-Agent" : [kQNUserAgent getUserAgent:self.token.token]};
  92. NSString *action = [NSString stringWithFormat:@"/v4/query?ak=%@&bucket=%@&sdk_name=%@&sdk_version=%@", self.token.access, self.token.bucket, [QNUtils sdkLanguage], [QNUtils sdkVersion]];
  93. [self.regionRequest get:action
  94. headers:header
  95. shouldRetry:shouldRetry
  96. complete:complete];
  97. }
  98. //MARK: -- upload form
  99. - (void)uploadFormData:(NSData *)data
  100. fileName:(NSString *)fileName
  101. progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
  102. complete:(QNRequestTransactionCompleteHandler)complete{
  103. self.requestInfo.requestType = QNUploadRequestTypeForm;
  104. NSMutableDictionary *param = [NSMutableDictionary dictionary];
  105. if (self.uploadOption.params) {
  106. [param addEntriesFromDictionary:self.uploadOption.params];
  107. }
  108. if (self.uploadOption.metaDataParam) {
  109. [param addEntriesFromDictionary:self.uploadOption.metaDataParam];
  110. }
  111. if (self.key && self.key.length > 0) {
  112. param[@"key"] = self.key;
  113. }
  114. param[@"token"] = self.token.token ?: @"";
  115. if (self.uploadOption.checkCrc) {
  116. param[@"crc32"] = [NSString stringWithFormat:@"%u", (unsigned int)[QNCrc32 data:data]];
  117. }
  118. NSString *boundary = @"werghnvt54wef654rjuhgb56trtg34tweuyrgf";
  119. NSString *disposition = @"Content-Disposition: form-data";
  120. NSMutableData *body = [NSMutableData data];
  121. @try {
  122. for (NSString *paramsKey in param) {
  123. NSString *pair = [NSString stringWithFormat:@"--%@\r\n%@; name=\"%@\"\r\n\r\n", boundary, disposition, paramsKey];
  124. [body appendData:[pair dataUsingEncoding:NSUTF8StringEncoding]];
  125. id value = [param objectForKey:paramsKey];
  126. if ([value isKindOfClass:[NSString class]]) {
  127. [body appendData:[value dataUsingEncoding:NSUTF8StringEncoding]];
  128. } else if ([value isKindOfClass:[NSData class]]) {
  129. [body appendData:value];
  130. }
  131. [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
  132. }
  133. fileName = [QNUtils formEscape:fileName];
  134. NSString *filePair = [NSString stringWithFormat:@"--%@\r\n%@; name=\"%@\"; filename=\"%@\"\nContent-Type:%@\r\n\r\n", boundary, disposition, @"file", fileName, self.uploadOption.mimeType];
  135. [body appendData:[filePair dataUsingEncoding:NSUTF8StringEncoding]];
  136. [body appendData:data];
  137. [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
  138. } @catch (NSException *exception) {
  139. if (complete) {
  140. QNResponseInfo *info = [QNResponseInfo responseInfoWithLocalIOError:[NSString stringWithFormat:@"%@", exception]];
  141. QNUploadRegionRequestMetrics *metrics = [QNUploadRegionRequestMetrics emptyMetrics];
  142. complete(info, metrics, nil);
  143. }
  144. return;
  145. }
  146. NSMutableDictionary *header = [NSMutableDictionary dictionary];
  147. header[@"Content-Type"] = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
  148. header[@"Content-Length"] = [NSString stringWithFormat:@"%lu", (unsigned long)body.length];
  149. header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
  150. BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
  151. return (BOOL)!responseInfo.isOK;
  152. };
  153. [self.regionRequest post:nil
  154. headers:header
  155. body:body
  156. shouldRetry:shouldRetry
  157. progress:progress
  158. complete:complete];
  159. }
  160. //MARK: -- 分块上传
  161. - (void)makeBlock:(long long)blockOffset
  162. blockSize:(long long)blockSize
  163. firstChunkData:(NSData *)firstChunkData
  164. progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
  165. complete:(QNRequestTransactionCompleteHandler)complete{
  166. self.requestInfo.requestType = QNUploadRequestTypeMkblk;
  167. self.requestInfo.fileOffset = @(blockOffset);
  168. NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
  169. NSMutableDictionary *header = [NSMutableDictionary dictionary];
  170. header[@"Authorization"] = token;
  171. header[@"Content-Type"] = @"application/octet-stream";
  172. header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
  173. NSString *action = [NSString stringWithFormat:@"/mkblk/%u", (unsigned int)blockSize];
  174. NSString *chunkCrc = [NSString stringWithFormat:@"%u", (unsigned int)[QNCrc32 data:firstChunkData]];
  175. kQNWeakSelf;
  176. BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
  177. kQNStrongSelf;
  178. NSString *ctx = response[@"ctx"];
  179. NSString *crcServer = [NSString stringWithFormat:@"%@", response[@"crc32"]];
  180. return (BOOL)(responseInfo.isOK == false || (responseInfo.isOK && (!ctx || (self.uploadOption.checkCrc && ![chunkCrc isEqualToString:crcServer]))));
  181. };
  182. [self.regionRequest post:action
  183. headers:header
  184. body:firstChunkData
  185. shouldRetry:shouldRetry
  186. progress:progress
  187. complete:complete];
  188. }
  189. - (void)uploadChunk:(NSString *)blockContext
  190. blockOffset:(long long)blockOffset
  191. chunkData:(NSData *)chunkData
  192. chunkOffset:(long long)chunkOffset
  193. progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
  194. complete:(QNRequestTransactionCompleteHandler)complete{
  195. self.requestInfo.requestType = QNUploadRequestTypeBput;
  196. self.requestInfo.fileOffset = @(blockOffset + chunkOffset);
  197. NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
  198. NSMutableDictionary *header = [NSMutableDictionary dictionary];
  199. header[@"Authorization"] = token;
  200. header[@"Content-Type"] = @"application/octet-stream";
  201. header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
  202. NSString *action = [NSString stringWithFormat:@"/bput/%@/%lld", blockContext, chunkOffset];
  203. NSString *chunkCrc = [NSString stringWithFormat:@"%u", (unsigned int)[QNCrc32 data:chunkData]];
  204. kQNWeakSelf;
  205. BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
  206. kQNStrongSelf;
  207. NSString *ctx = response[@"ctx"];
  208. NSString *crcServer = [NSString stringWithFormat:@"%@", response[@"crc32"]];
  209. return (BOOL)(responseInfo.isOK == false || (responseInfo.isOK && (!ctx || (self.uploadOption.checkCrc && ![chunkCrc isEqualToString:crcServer]))));
  210. };
  211. [self.regionRequest post:action
  212. headers:header
  213. body:chunkData
  214. shouldRetry:shouldRetry
  215. progress:progress
  216. complete:complete];
  217. }
  218. - (void)makeFile:(long long)fileSize
  219. fileName:(NSString *)fileName
  220. blockContexts:(NSArray <NSString *> *)blockContexts
  221. complete:(QNRequestTransactionCompleteHandler)complete{
  222. self.requestInfo.requestType = QNUploadRequestTypeMkfile;
  223. NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
  224. NSMutableDictionary *header = [NSMutableDictionary dictionary];
  225. header[@"Authorization"] = token;
  226. header[@"Content-Type"] = @"application/octet-stream";
  227. header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
  228. NSString *mimeType = [[NSString alloc] initWithFormat:@"/mimeType/%@", [QNUrlSafeBase64 encodeString:self.uploadOption.mimeType]];
  229. __block NSString *action = [[NSString alloc] initWithFormat:@"/mkfile/%lld%@", fileSize, mimeType];
  230. if (self.key != nil) {
  231. NSString *keyStr = [[NSString alloc] initWithFormat:@"/key/%@", [QNUrlSafeBase64 encodeString:self.key]];
  232. action = [NSString stringWithFormat:@"%@%@", action, keyStr];
  233. }
  234. [self.uploadOption.params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
  235. action = [NSString stringWithFormat:@"%@/%@/%@", action, key, [QNUrlSafeBase64 encodeString:obj]];
  236. }];
  237. [self.uploadOption.metaDataParam enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
  238. action = [NSString stringWithFormat:@"%@/%@/%@", action, key, [QNUrlSafeBase64 encodeString:obj]];
  239. }];
  240. //添加路径
  241. NSString *fname = [[NSString alloc] initWithFormat:@"/fname/%@", [QNUrlSafeBase64 encodeString:fileName]];
  242. action = [NSString stringWithFormat:@"%@%@", action, fname];
  243. NSMutableData *body = [NSMutableData data];
  244. NSString *bodyString = [blockContexts componentsJoinedByString:@","];
  245. [body appendData:[bodyString dataUsingEncoding:NSUTF8StringEncoding]];
  246. BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
  247. return (BOOL)(!responseInfo.isOK);
  248. };
  249. [self.regionRequest post:action
  250. headers:header
  251. body:body
  252. shouldRetry:shouldRetry
  253. progress:nil
  254. complete:complete];
  255. }
  256. - (void)initPart:(QNRequestTransactionCompleteHandler)complete{
  257. self.requestInfo.requestType = QNUploadRequestTypeInitParts;
  258. NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
  259. NSMutableDictionary *header = [NSMutableDictionary dictionary];
  260. header[@"Authorization"] = token;
  261. header[@"Content-Type"] = @"application/octet-stream";
  262. header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
  263. NSString *buckets = [[NSString alloc] initWithFormat:@"/buckets/%@", self.token.bucket];
  264. NSString *objects = [[NSString alloc] initWithFormat:@"/objects/%@", [self resumeV2EncodeKey:self.key]];;
  265. NSString *action = [[NSString alloc] initWithFormat:@"%@%@/uploads", buckets, objects];
  266. BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
  267. return (BOOL)(!responseInfo.isOK);
  268. };
  269. [self.regionRequest post:action
  270. headers:header
  271. body:nil
  272. shouldRetry:shouldRetry
  273. progress:nil
  274. complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
  275. complete(responseInfo, metrics, response);
  276. }];
  277. }
  278. - (void)uploadPart:(NSString *)uploadId
  279. partIndex:(NSInteger)partIndex
  280. partData:(NSData *)partData
  281. progress:(void(^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
  282. complete:(QNRequestTransactionCompleteHandler)complete{
  283. self.requestInfo.requestType = QNUploadRequestTypeUploadPart;
  284. NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
  285. NSMutableDictionary *header = [NSMutableDictionary dictionary];
  286. header[@"Authorization"] = token;
  287. header[@"Content-Type"] = @"application/octet-stream";
  288. header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
  289. if (self.uploadOption.checkCrc) {
  290. NSString *md5 = [[partData qn_md5] lowercaseString];
  291. if (md5) {
  292. header[@"Content-MD5"] = md5;
  293. }
  294. }
  295. NSString *buckets = [[NSString alloc] initWithFormat:@"/buckets/%@", self.token.bucket];
  296. NSString *objects = [[NSString alloc] initWithFormat:@"/objects/%@", [self resumeV2EncodeKey:self.key]];;
  297. NSString *uploads = [[NSString alloc] initWithFormat:@"/uploads/%@", uploadId];
  298. NSString *partNumber = [[NSString alloc] initWithFormat:@"/%ld", (long)partIndex];
  299. NSString *action = [[NSString alloc] initWithFormat:@"%@%@%@%@", buckets, objects, uploads, partNumber];
  300. BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
  301. NSString *etag = [NSString stringWithFormat:@"%@", response[@"etag"]];
  302. NSString *serverMD5 = [NSString stringWithFormat:@"%@", response[@"md5"]];
  303. return (BOOL)(!responseInfo.isOK || !etag || !serverMD5);
  304. };
  305. [self.regionRequest put:action
  306. headers:header
  307. body:partData
  308. shouldRetry:shouldRetry
  309. progress:progress
  310. complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
  311. complete(responseInfo, metrics, response);
  312. }];
  313. }
  314. - (void)completeParts:(NSString *)fileName
  315. uploadId:(NSString *)uploadId
  316. partInfoArray:(NSArray <NSDictionary *> *)partInfoArray
  317. complete:(QNRequestTransactionCompleteHandler)complete{
  318. self.requestInfo.requestType = QNUploadRequestTypeCompletePart;
  319. if (!partInfoArray || partInfoArray.count == 0) {
  320. QNResponseInfo *responseInfo = [QNResponseInfo responseInfoWithInvalidArgument:@"partInfoArray"];
  321. if (complete) {
  322. complete(responseInfo, nil, responseInfo.responseDictionary);
  323. }
  324. return;
  325. }
  326. NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
  327. NSMutableDictionary *header = [NSMutableDictionary dictionary];
  328. header[@"Authorization"] = token;
  329. header[@"Content-Type"] = @"application/json";
  330. header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
  331. NSString *buckets = [[NSString alloc] initWithFormat:@"/buckets/%@", self.token.bucket];
  332. NSString *objects = [[NSString alloc] initWithFormat:@"/objects/%@", [self resumeV2EncodeKey:self.key]];
  333. NSString *uploads = [[NSString alloc] initWithFormat:@"/uploads/%@", uploadId];
  334. NSString *action = [[NSString alloc] initWithFormat:@"%@%@%@", buckets, objects, uploads];
  335. NSMutableDictionary *bodyDictionary = [NSMutableDictionary dictionary];
  336. if (partInfoArray) {
  337. bodyDictionary[@"parts"] = partInfoArray;
  338. }
  339. if (fileName) {
  340. bodyDictionary[@"fname"] = fileName;
  341. }
  342. if (self.uploadOption.mimeType) {
  343. bodyDictionary[@"mimeType"] = self.uploadOption.mimeType;
  344. }
  345. if (self.uploadOption.params) {
  346. bodyDictionary[@"customVars"] = self.uploadOption.params;
  347. }
  348. if (self.uploadOption.metaDataParam) {
  349. bodyDictionary[@"metaData"] = self.uploadOption.metaDataParam;
  350. }
  351. NSError *error = nil;
  352. NSData *body = [NSJSONSerialization dataWithJSONObject:bodyDictionary
  353. options:NSJSONWritingPrettyPrinted
  354. error:&error];
  355. if (error) {
  356. QNResponseInfo *responseInfo = [QNResponseInfo responseInfoWithLocalIOError:error.description];
  357. if (complete) {
  358. complete(responseInfo, nil, responseInfo.responseDictionary);
  359. }
  360. return;
  361. }
  362. BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
  363. return (BOOL)(!responseInfo.isOK);
  364. };
  365. [self.regionRequest post:action
  366. headers:header
  367. body:body
  368. shouldRetry:shouldRetry
  369. progress:nil
  370. complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
  371. complete(responseInfo, metrics, response);
  372. }];
  373. }
  374. - (void)reportLog:(NSData *)logData
  375. logClientId:(NSString *)logClientId
  376. complete:(QNRequestTransactionCompleteHandler)complete {
  377. self.requestInfo.requestType = QNUploadRequestTypeUpLog;
  378. NSString *token = [NSString stringWithFormat:@"UpToken %@", self.token.token];
  379. NSMutableDictionary *header = [NSMutableDictionary dictionary];
  380. header[@"Authorization"] = token;
  381. header[@"Content-Type"] = @"application/json";
  382. header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
  383. NSString *action = @"/log/4?compressed=gzip";
  384. if (logClientId) {
  385. header[@"X-Log-Client-Id"] = logClientId;
  386. }
  387. BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
  388. return (BOOL)(!responseInfo.isOK);
  389. };
  390. [self.regionRequest post:action
  391. headers:header
  392. body:logData
  393. shouldRetry:shouldRetry
  394. progress:nil
  395. complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
  396. complete(responseInfo, metrics, response);
  397. }];
  398. }
  399. - (void)serverConfig:(QNRequestTransactionCompleteHandler)complete {
  400. self.requestInfo.requestType = QNUploadRequestTypeServerConfig;
  401. NSMutableDictionary *header = [NSMutableDictionary dictionary];
  402. header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
  403. NSString *action = [NSString stringWithFormat:@"/v1/sdk/config?sdk_name=%@&sdk_version=%@", [QNUtils sdkLanguage], [QNUtils sdkVersion]];
  404. BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
  405. return (BOOL)(!responseInfo.isOK);
  406. };
  407. [self.regionRequest post:action
  408. headers:header
  409. body:nil
  410. shouldRetry:shouldRetry
  411. progress:nil
  412. complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
  413. complete(responseInfo, metrics, response);
  414. }];
  415. }
  416. - (void)serverUserConfig:(QNRequestTransactionCompleteHandler)complete {
  417. self.requestInfo.requestType = QNUploadRequestTypeServerUserConfig;
  418. NSMutableDictionary *header = [NSMutableDictionary dictionary];
  419. header[@"User-Agent"] = [kQNUserAgent getUserAgent:self.token.token];
  420. NSString *action = [NSString stringWithFormat:@"/v1/sdk/config/user?ak=%@&sdk_name=%@&sdk_version=%@", self.token.access, [QNUtils sdkLanguage], [QNUtils sdkVersion]];
  421. BOOL (^shouldRetry)(QNResponseInfo *, NSDictionary *) = ^(QNResponseInfo * responseInfo, NSDictionary * response){
  422. return (BOOL)(!responseInfo.isOK);
  423. };
  424. [self.regionRequest post:action
  425. headers:header
  426. body:nil
  427. shouldRetry:shouldRetry
  428. progress:nil
  429. complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
  430. complete(responseInfo, metrics, response);
  431. }];
  432. }
  433. - (NSString *)resumeV2EncodeKey:(NSString *)key{
  434. NSString *encodeKey = nil;
  435. if (!self.key) {
  436. encodeKey = @"~";
  437. } else if (self.key.length == 0) {
  438. encodeKey = @"";
  439. } else {
  440. encodeKey = [QNUrlSafeBase64 encodeString:self.key];
  441. }
  442. return encodeKey;
  443. }
  444. @end