解决了语音上传到问题,接下来要解决下载播放问题
This commit is contained in:
126
Pods/Qiniu/QiniuSDK/Storage/QNBaseUpload.h
generated
Normal file
126
Pods/Qiniu/QiniuSDK/Storage/QNBaseUpload.h
generated
Normal file
@@ -0,0 +1,126 @@
|
||||
//
|
||||
// QNBaseUpload.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by WorkSpace_Sun on 2020/4/19.
|
||||
// Copyright © 2020 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNCrc32.h"
|
||||
#import "QNRecorderDelegate.h"
|
||||
#import "QNUpToken.h"
|
||||
#import "QNUrlSafeBase64.h"
|
||||
#import "QNAsyncRun.h"
|
||||
#import "QNUploadManager.h"
|
||||
#import "QNUploadOption.h"
|
||||
#import "QNZone.h"
|
||||
#import "QNUploadSource.h"
|
||||
#import "QNUploadRequestMetrics.h"
|
||||
|
||||
extern NSString *const QNUploadUpTypeForm;
|
||||
extern NSString *const QNUploadUpTypeResumableV1;
|
||||
extern NSString *const QNUploadUpTypeResumableV2;
|
||||
|
||||
typedef void (^QNUpTaskCompletionHandler)(QNResponseInfo *info, NSString *key, QNUploadTaskMetrics *metrics, NSDictionary *resp);
|
||||
|
||||
@interface QNBaseUpload : NSObject
|
||||
|
||||
@property (nonatomic, copy, readonly) NSString *upType;
|
||||
@property (nonatomic, copy, readonly) NSString *key;
|
||||
@property (nonatomic, copy, readonly) NSString *fileName;
|
||||
@property (nonatomic, strong, readonly) NSData *data;
|
||||
@property (nonatomic, strong, readonly) id <QNUploadSource> uploadSource;
|
||||
@property (nonatomic, strong, readonly) QNUpToken *token;
|
||||
@property (nonatomic, strong, readonly) QNUploadOption *option;
|
||||
@property (nonatomic, strong, readonly) QNConfiguration *config;
|
||||
@property (nonatomic, strong, readonly) id <QNRecorderDelegate> recorder;
|
||||
@property (nonatomic, copy, readonly) NSString *recorderKey;
|
||||
@property (nonatomic, strong, readonly) QNUpTaskCompletionHandler completionHandler;
|
||||
|
||||
@property (nonatomic, strong, readonly) QNUploadRegionRequestMetrics *currentRegionRequestMetrics;
|
||||
@property (nonatomic, strong, readonly) QNUploadTaskMetrics *metrics;
|
||||
|
||||
|
||||
//MARK:-- 构造函数
|
||||
|
||||
/// file构造函数
|
||||
/// @param uploadSource 文件源
|
||||
/// @param key 上传key
|
||||
/// @param token 上传token
|
||||
/// @param option 上传option
|
||||
/// @param config 上传config
|
||||
/// @param recorder 断点续传记录信息
|
||||
/// @param recorderKey 断电上传信息保存的key值,需确保唯一性
|
||||
/// @param completionHandler 上传完成回调
|
||||
- (instancetype)initWithSource:(id<QNUploadSource>)uploadSource
|
||||
key:(NSString *)key
|
||||
token:(QNUpToken *)token
|
||||
option:(QNUploadOption *)option
|
||||
configuration:(QNConfiguration *)config
|
||||
recorder:(id<QNRecorderDelegate>)recorder
|
||||
recorderKey:(NSString *)recorderKey
|
||||
completionHandler:(QNUpTaskCompletionHandler)completionHandler;
|
||||
|
||||
/// data 构造函数
|
||||
/// @param data 上传data流
|
||||
/// @param key 上传key
|
||||
/// @param fileName 上传fileName
|
||||
/// @param token 上传token
|
||||
/// @param option 上传option
|
||||
/// @param config 上传config
|
||||
/// @param completionHandler 上传完成回调
|
||||
- (instancetype)initWithData:(NSData *)data
|
||||
key:(NSString *)key
|
||||
fileName:(NSString *)fileName
|
||||
token:(QNUpToken *)token
|
||||
option:(QNUploadOption *)option
|
||||
configuration:(QNConfiguration *)config
|
||||
completionHandler:(QNUpTaskCompletionHandler)completionHandler;
|
||||
|
||||
/// 初始化数据
|
||||
- (void)initData;
|
||||
|
||||
//MARK: -- 上传
|
||||
|
||||
/// 开始上传流程
|
||||
- (void)run;
|
||||
|
||||
/// 准备上传
|
||||
- (int)prepareToUpload;
|
||||
|
||||
/// 重新加载上传数据
|
||||
- (BOOL)reloadUploadInfo;
|
||||
|
||||
/// 开始上传
|
||||
- (void)startToUpload;
|
||||
|
||||
/// 切换区域
|
||||
- (BOOL)switchRegionAndUpload;
|
||||
// 根据错误信息进行切换region并上传,return:是否切换region并上传
|
||||
- (BOOL)switchRegionAndUploadIfNeededWithErrorResponse:(QNResponseInfo *)errorResponseInfo;
|
||||
|
||||
/// 上传结束调用回调方法,在上传结束时调用,该方法内部会调用回调,已通知上层上传结束
|
||||
/// @param info 上传返回信息
|
||||
/// @param response 上传字典信息
|
||||
- (void)complete:(QNResponseInfo *)info
|
||||
response:(NSDictionary *)response;
|
||||
|
||||
//MARK: -- 机房管理
|
||||
|
||||
/// 在区域列表头部插入一个区域
|
||||
- (void)insertRegionAtFirst:(id <QNUploadRegion>)region;
|
||||
/// 切换区域
|
||||
- (BOOL)switchRegion;
|
||||
/// 获取目标区域
|
||||
- (id <QNUploadRegion>)getTargetRegion;
|
||||
/// 获取当前区域
|
||||
- (id <QNUploadRegion>)getCurrentRegion;
|
||||
|
||||
//MARK: -- upLog
|
||||
|
||||
// 一个上传流程可能会发起多个上传操作(如:上传多个分片),每个上传操作均是以一个Region的host做重试操作
|
||||
- (void)addRegionRequestMetricsOfOneFlow:(QNUploadRegionRequestMetrics *)metrics;
|
||||
|
||||
@end
|
||||
295
Pods/Qiniu/QiniuSDK/Storage/QNBaseUpload.m
generated
Normal file
295
Pods/Qiniu/QiniuSDK/Storage/QNBaseUpload.m
generated
Normal file
@@ -0,0 +1,295 @@
|
||||
//
|
||||
// QNBaseUpload.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by WorkSpace_Sun on 2020/4/19.
|
||||
// Copyright © 2020 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNAutoZone.h"
|
||||
#import "QNZoneInfo.h"
|
||||
#import "QNResponseInfo.h"
|
||||
#import "QNDefine.h"
|
||||
#import "QNBaseUpload.h"
|
||||
#import "QNUploadDomainRegion.h"
|
||||
|
||||
NSString *const QNUploadUpTypeForm = @"form";
|
||||
NSString *const QNUploadUpTypeResumableV1 = @"resumable_v1";
|
||||
NSString *const QNUploadUpTypeResumableV2 = @"resumable_v2";
|
||||
|
||||
@interface QNBaseUpload ()
|
||||
|
||||
@property (nonatomic, strong) QNBaseUpload *strongSelf;
|
||||
|
||||
@property (nonatomic, copy) NSString *key;
|
||||
@property (nonatomic, copy) NSString *fileName;
|
||||
@property (nonatomic, strong) NSData *data;
|
||||
@property (nonatomic, strong) id <QNUploadSource> uploadSource;
|
||||
@property (nonatomic, strong) QNUpToken *token;
|
||||
@property (nonatomic, copy) NSString *identifier;
|
||||
@property (nonatomic, strong) QNUploadOption *option;
|
||||
@property (nonatomic, strong) QNConfiguration *config;
|
||||
@property (nonatomic, strong) id <QNRecorderDelegate> recorder;
|
||||
@property (nonatomic, copy) NSString *recorderKey;
|
||||
@property (nonatomic, strong) QNUpTaskCompletionHandler completionHandler;
|
||||
|
||||
@property (nonatomic, assign)NSInteger currentRegionIndex;
|
||||
@property (nonatomic, strong)NSMutableArray <id <QNUploadRegion> > *regions;
|
||||
|
||||
@property (nonatomic, strong)QNUploadRegionRequestMetrics *currentRegionRequestMetrics;
|
||||
@property (nonatomic, strong) QNUploadTaskMetrics *metrics;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNBaseUpload
|
||||
|
||||
- (instancetype)initWithSource:(id<QNUploadSource>)uploadSource
|
||||
key:(NSString *)key
|
||||
token:(QNUpToken *)token
|
||||
option:(QNUploadOption *)option
|
||||
configuration:(QNConfiguration *)config
|
||||
recorder:(id<QNRecorderDelegate>)recorder
|
||||
recorderKey:(NSString *)recorderKey
|
||||
completionHandler:(QNUpTaskCompletionHandler)completionHandler{
|
||||
return [self initWithSource:uploadSource data:nil fileName:[uploadSource getFileName] key:key token:token option:option configuration:config recorder:recorder recorderKey:recorderKey completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data
|
||||
key:(NSString *)key
|
||||
fileName:(NSString *)fileName
|
||||
token:(QNUpToken *)token
|
||||
option:(QNUploadOption *)option
|
||||
configuration:(QNConfiguration *)config
|
||||
completionHandler:(QNUpTaskCompletionHandler)completionHandler{
|
||||
return [self initWithSource:nil data:data fileName:fileName key:key token:token option:option configuration:config recorder:nil recorderKey:nil completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSource:(id<QNUploadSource>)uploadSource
|
||||
data:(NSData *)data
|
||||
fileName:(NSString *)fileName
|
||||
key:(NSString *)key
|
||||
token:(QNUpToken *)token
|
||||
option:(QNUploadOption *)option
|
||||
configuration:(QNConfiguration *)config
|
||||
recorder:(id<QNRecorderDelegate>)recorder
|
||||
recorderKey:(NSString *)recorderKey
|
||||
completionHandler:(QNUpTaskCompletionHandler)completionHandler{
|
||||
if (self = [super init]) {
|
||||
_uploadSource = uploadSource;
|
||||
_data = data;
|
||||
_fileName = fileName ?: @"?";
|
||||
_key = key;
|
||||
_token = token;
|
||||
_config = config;
|
||||
_option = option ?: [QNUploadOption defaultOptions];
|
||||
_recorder = recorder;
|
||||
_recorderKey = recorderKey;
|
||||
_completionHandler = completionHandler;
|
||||
[self initData];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init{
|
||||
if (self = [super init]) {
|
||||
[self initData];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initData{
|
||||
_strongSelf = self;
|
||||
_currentRegionIndex = 0;
|
||||
}
|
||||
|
||||
- (void)run {
|
||||
[self.metrics start];
|
||||
|
||||
kQNWeakSelf;
|
||||
[_config.zone query:self.config token:self.token on:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, QNZonesInfo * _Nullable zonesInfo) {
|
||||
|
||||
kQNStrongSelf;
|
||||
self.metrics.ucQueryMetrics = metrics;
|
||||
|
||||
if (responseInfo != nil && responseInfo.isOK && zonesInfo) {
|
||||
if (![self setupRegions:zonesInfo]) {
|
||||
responseInfo = [QNResponseInfo responseInfoWithInvalidArgument:[NSString stringWithFormat:@"setup regions host fail, origin response:%@", responseInfo]];
|
||||
[self complete:responseInfo response:responseInfo.responseDictionary];
|
||||
return;
|
||||
}
|
||||
|
||||
int prepareCode = [self prepareToUpload];
|
||||
if (prepareCode == 0) {
|
||||
[self startToUpload];
|
||||
} else {
|
||||
QNResponseInfo *responseInfoP = [QNResponseInfo errorResponseInfo:prepareCode errorDesc:nil];
|
||||
[self complete:responseInfoP response:responseInfoP.responseDictionary];
|
||||
}
|
||||
} else {
|
||||
if (responseInfo == nil) {
|
||||
// responseInfo 一定会有值
|
||||
responseInfo = [QNResponseInfo responseInfoWithSDKInteriorError:@"can't get regions"];
|
||||
}
|
||||
|
||||
[self complete:responseInfo response:responseInfo.responseDictionary];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (BOOL)reloadUploadInfo {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (int)prepareToUpload{
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)startToUpload{
|
||||
self.currentRegionRequestMetrics = [[QNUploadRegionRequestMetrics alloc] initWithRegion:[self getCurrentRegion]];
|
||||
[self.currentRegionRequestMetrics start];
|
||||
}
|
||||
|
||||
// 内部不再调用
|
||||
- (BOOL)switchRegionAndUpload{
|
||||
if (self.currentRegionRequestMetrics) {
|
||||
[self.currentRegionRequestMetrics end];
|
||||
[self.metrics addMetrics:self.currentRegionRequestMetrics];
|
||||
self.currentRegionRequestMetrics = nil;
|
||||
}
|
||||
|
||||
BOOL isSwitched = [self switchRegion];
|
||||
if (isSwitched) {
|
||||
[self startToUpload];
|
||||
}
|
||||
return isSwitched;
|
||||
}
|
||||
|
||||
// 根据错误信息进行切换region并上传,return:是否切换region并上传
|
||||
- (BOOL)switchRegionAndUploadIfNeededWithErrorResponse:(QNResponseInfo *)errorResponseInfo {
|
||||
if (errorResponseInfo.statusCode == 400 && [errorResponseInfo.message containsString:@"incorrect region"]) {
|
||||
[QNAutoZone clearCache];
|
||||
}
|
||||
|
||||
if (!errorResponseInfo || errorResponseInfo.isOK || // 不存在 || 成功 不需要重试
|
||||
![errorResponseInfo couldRetry] || ![self.config allowBackupHost]) { // 不能重试
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self.currentRegionRequestMetrics) {
|
||||
[self.currentRegionRequestMetrics end];
|
||||
[self.metrics addMetrics:self.currentRegionRequestMetrics];
|
||||
self.currentRegionRequestMetrics = nil;
|
||||
}
|
||||
|
||||
// 重新加载上传数据,上传记录 & Resource index 归零
|
||||
if (![self reloadUploadInfo]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 切换区域,当为 context 过期错误不需要切换区域
|
||||
if (!errorResponseInfo.isCtxExpiedError && ![self switchRegion]) {
|
||||
// 非 context 过期错误,但是切换 region 失败
|
||||
return false;
|
||||
}
|
||||
|
||||
[self startToUpload];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)complete:(QNResponseInfo *)info
|
||||
response:(NSDictionary *)response{
|
||||
|
||||
[self.metrics end];
|
||||
[self.currentRegionRequestMetrics end];
|
||||
|
||||
if (self.currentRegionRequestMetrics) {
|
||||
[self.metrics addMetrics:self.currentRegionRequestMetrics];
|
||||
}
|
||||
if (self.completionHandler) {
|
||||
self.completionHandler(info, _key, _metrics, response);
|
||||
}
|
||||
self.strongSelf = nil;
|
||||
}
|
||||
|
||||
//MARK:-- region
|
||||
- (BOOL)setupRegions:(QNZonesInfo *)zonesInfo{
|
||||
if (zonesInfo == nil || zonesInfo.zonesInfo == nil || zonesInfo.zonesInfo.count == 0) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSMutableArray *defaultRegions = [NSMutableArray array];
|
||||
NSArray *zoneInfos = zonesInfo.zonesInfo;
|
||||
for (QNZoneInfo *zoneInfo in zoneInfos) {
|
||||
QNUploadDomainRegion *region = [[QNUploadDomainRegion alloc] initWithConfig:self.config];
|
||||
[region setupRegionData:zoneInfo];
|
||||
if (region.isValid) {
|
||||
[defaultRegions addObject:region];
|
||||
}
|
||||
}
|
||||
self.regions = defaultRegions;
|
||||
self.metrics.regions = defaultRegions;
|
||||
return defaultRegions.count > 0;
|
||||
}
|
||||
|
||||
- (void)insertRegionAtFirst:(id <QNUploadRegion>)region{
|
||||
BOOL hasRegion = NO;
|
||||
for (id <QNUploadRegion> regionP in self.regions) {
|
||||
if ([regionP.zoneInfo.regionId isEqualToString:region.zoneInfo.regionId]) {
|
||||
hasRegion = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasRegion) {
|
||||
[self.regions insertObject:region atIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)switchRegion{
|
||||
BOOL ret = NO;
|
||||
@synchronized (self) {
|
||||
NSInteger regionIndex = _currentRegionIndex + 1;
|
||||
if (regionIndex < self.regions.count) {
|
||||
_currentRegionIndex = regionIndex;
|
||||
ret = YES;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (id <QNUploadRegion>)getTargetRegion{
|
||||
return self.regions.firstObject;
|
||||
}
|
||||
|
||||
- (id <QNUploadRegion>)getCurrentRegion{
|
||||
id <QNUploadRegion> region = nil;
|
||||
@synchronized (self) {
|
||||
if (self.currentRegionIndex < self.regions.count) {
|
||||
region = self.regions[self.currentRegionIndex];
|
||||
}
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
- (void)addRegionRequestMetricsOfOneFlow:(QNUploadRegionRequestMetrics *)metrics{
|
||||
if (metrics == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
@synchronized (self) {
|
||||
if (self.currentRegionRequestMetrics == nil) {
|
||||
self.currentRegionRequestMetrics = metrics;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[self.currentRegionRequestMetrics addMetrics:metrics];
|
||||
}
|
||||
|
||||
- (QNUploadTaskMetrics *)metrics {
|
||||
if (_metrics == nil) {
|
||||
_metrics = [QNUploadTaskMetrics taskMetrics:self.upType];
|
||||
}
|
||||
return _metrics;
|
||||
}
|
||||
@end
|
||||
14
Pods/Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.h
generated
Normal file
14
Pods/Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.h
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// QNConcurrentResumeUpload.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by WorkSpace_Sun on 2019/7/15.
|
||||
// Copyright © 2019 Qiniu. All rights reserved.
|
||||
//
|
||||
/// 并发分片上传
|
||||
|
||||
#import "QNPartsUpload.h"
|
||||
|
||||
@interface QNConcurrentResumeUpload : QNPartsUpload
|
||||
|
||||
@end
|
||||
43
Pods/Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.m
generated
Normal file
43
Pods/Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.m
generated
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// QNConcurrentResumeUpload.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by WorkSpace_Sun on 2019/7/15.
|
||||
// Copyright © 2019 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNLogUtil.h"
|
||||
#import "QNConcurrentResumeUpload.h"
|
||||
|
||||
@interface QNConcurrentResumeUpload()
|
||||
|
||||
@property(nonatomic, strong) dispatch_group_t uploadGroup;
|
||||
@property(nonatomic, strong) dispatch_queue_t uploadQueue;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNConcurrentResumeUpload
|
||||
|
||||
- (int)prepareToUpload{
|
||||
self.uploadGroup = dispatch_group_create();
|
||||
self.uploadQueue = dispatch_queue_create("com.qiniu.concurrentUpload", DISPATCH_QUEUE_SERIAL);
|
||||
return [super prepareToUpload];
|
||||
}
|
||||
|
||||
- (void)uploadRestData:(dispatch_block_t)completeHandler {
|
||||
QNLogInfo(@"key:%@ 并发分片", self.key);
|
||||
|
||||
for (int i = 0; i < self.config.concurrentTaskCount; i++) {
|
||||
dispatch_group_enter(self.uploadGroup);
|
||||
dispatch_group_async(self.uploadGroup, self.uploadQueue, ^{
|
||||
[super performUploadRestData:^{
|
||||
dispatch_group_leave(self.uploadGroup);
|
||||
}];
|
||||
});
|
||||
}
|
||||
dispatch_group_notify(self.uploadGroup, self.uploadQueue, ^{
|
||||
completeHandler();
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
346
Pods/Qiniu/QiniuSDK/Storage/QNConfiguration.h
generated
Normal file
346
Pods/Qiniu/QiniuSDK/Storage/QNConfiguration.h
generated
Normal file
@@ -0,0 +1,346 @@
|
||||
//
|
||||
// QNConfiguration.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 15/5/21.
|
||||
// Copyright (c) 2015年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "QNRecorderDelegate.h"
|
||||
#import "QNDns.h"
|
||||
|
||||
/**
|
||||
* 断点上传时的分块大小
|
||||
*/
|
||||
extern const UInt32 kQNBlockSize;
|
||||
|
||||
/**
|
||||
* DNS默认缓存时间
|
||||
*/
|
||||
extern const UInt32 kQNDefaultDnsCacheTime;
|
||||
|
||||
/**
|
||||
* 转换为用户需要的url
|
||||
*
|
||||
* @param url 上传url
|
||||
*
|
||||
* @return 根据上传url算出代理url
|
||||
*/
|
||||
typedef NSString * (^QNUrlConvert)(NSString *url);
|
||||
|
||||
typedef NS_ENUM(NSInteger, QNResumeUploadVersion){
|
||||
QNResumeUploadVersionV1, // 分片v1
|
||||
QNResumeUploadVersionV2 // 分片v2
|
||||
};
|
||||
|
||||
@class QNConfigurationBuilder;
|
||||
@class QNZone;
|
||||
@class QNReportConfig;
|
||||
|
||||
/**
|
||||
* Builder block
|
||||
*
|
||||
* @param builder builder实例
|
||||
*/
|
||||
typedef void (^QNConfigurationBuilderBlock)(QNConfigurationBuilder *builder);
|
||||
|
||||
@interface QNConfiguration : NSObject
|
||||
|
||||
/**
|
||||
* 存储区域
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) QNZone *zone;
|
||||
|
||||
/**
|
||||
* 断点上传时的分片大小
|
||||
*/
|
||||
@property (readonly) UInt32 chunkSize;
|
||||
|
||||
/**
|
||||
* 如果大于此值就使用断点上传,否则使用form上传
|
||||
*/
|
||||
@property (readonly) UInt32 putThreshold;
|
||||
|
||||
/**
|
||||
* 上传失败时每个上传域名的重试次数,默认重试1次
|
||||
*/
|
||||
@property (readonly) UInt32 retryMax;
|
||||
|
||||
/**
|
||||
* 重试前等待时长,默认0.5s
|
||||
*/
|
||||
@property (readonly) NSTimeInterval retryInterval;
|
||||
|
||||
/**
|
||||
* 单个请求超时时间 单位 秒
|
||||
* 注:每个文件上传肯能存在多个操作,当每个操作失败时,可能存在多个请求重试。
|
||||
*/
|
||||
@property (readonly) UInt32 timeoutInterval;
|
||||
|
||||
/**
|
||||
* 是否使用 https,默认为 YES
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) BOOL useHttps;
|
||||
|
||||
/**
|
||||
* 单个文件是否开启并发分片上传,默认为NO
|
||||
* 单个文件大小大于4M时,会采用分片上传,每个分片会已单独的请求进行上传操作,多个上传操作可以使用并发,
|
||||
* 也可以采用串行,采用并发时,可以设置并发的个数(对concurrentTaskCount进行设置)。
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) BOOL useConcurrentResumeUpload;
|
||||
|
||||
/**
|
||||
* 分片上传版本
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) QNResumeUploadVersion resumeUploadVersion;
|
||||
|
||||
/**
|
||||
* 并发分片上传的并发任务个数,在concurrentResumeUpload为YES时有效,默认为3个
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) UInt32 concurrentTaskCount;
|
||||
|
||||
/**
|
||||
* 重试时是否允许使用备用上传域名,默认为YES
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL allowBackupHost;
|
||||
|
||||
/**
|
||||
* 是否允许使用加速域名,默认为 false
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) BOOL accelerateUploading;
|
||||
|
||||
/**
|
||||
* 持久化记录接口,可以实现将记录持久化到文件,数据库等
|
||||
*/
|
||||
@property (nonatomic, readonly) id<QNRecorderDelegate> recorder;
|
||||
|
||||
/**
|
||||
* 为持久化上传记录,根据上传的key以及文件名 生成持久化的记录key
|
||||
*/
|
||||
@property (nonatomic, readonly) QNRecorderKeyGenerator recorderKeyGen;
|
||||
|
||||
/**
|
||||
* 上传请求代理配置信息
|
||||
*/
|
||||
@property (nonatomic, readonly) NSDictionary *proxy;
|
||||
|
||||
/**
|
||||
* 上传URL转换,使url转换为用户需要的url
|
||||
*/
|
||||
@property (nonatomic, readonly) QNUrlConvert converter;
|
||||
|
||||
/**
|
||||
* 默认配置
|
||||
*/
|
||||
+ (instancetype)defaultConfiguration;
|
||||
|
||||
/**
|
||||
* 使用 QNConfigurationBuilder 进行配置
|
||||
* @param block 配置block
|
||||
*/
|
||||
+ (instancetype)build:(QNConfigurationBuilderBlock)block;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#define kQNGlobalConfiguration [QNGlobalConfiguration shared]
|
||||
@interface QNGlobalConfiguration : NSObject
|
||||
|
||||
/**
|
||||
* 是否开启dns预解析 默认开启
|
||||
*/
|
||||
@property(nonatomic, assign)BOOL isDnsOpen;
|
||||
|
||||
/**
|
||||
* dns 预取失败后 会进行重新预取 dnsRepreHostNum为最多尝试次数
|
||||
*/
|
||||
@property(nonatomic, assign)UInt32 dnsRepreHostNum;
|
||||
|
||||
/**
|
||||
* dns 预取超时,单位:秒 默认:2
|
||||
*/
|
||||
@property(nonatomic, assign)int dnsResolveTimeout;
|
||||
|
||||
/**
|
||||
* dns 预取, ip 默认有效时间 单位:秒 默认:120
|
||||
* 只有在 dns 预取未返回 ttl 时使用
|
||||
*/
|
||||
@property(nonatomic, assign)UInt32 dnsCacheTime;
|
||||
|
||||
/**
|
||||
* dns预取缓存最大有效时间 单位:秒 默认 1800
|
||||
* 当 dns 缓存 ip 过期并未刷新时,只要在 dnsCacheMaxTTL 时间内仍有效。
|
||||
*/
|
||||
@property(nonatomic, assign)UInt32 dnsCacheMaxTTL;
|
||||
|
||||
/**
|
||||
* 自定义DNS解析客户端host
|
||||
*/
|
||||
@property(nonatomic, strong) id <QNDnsDelegate> dns;
|
||||
|
||||
/**
|
||||
* dns解析结果本地缓存路径
|
||||
*/
|
||||
@property(nonatomic, copy, readonly)NSString *dnsCacheDir;
|
||||
|
||||
/**
|
||||
* 是否使用 udp 方式进行 Dns 预取,默认开启
|
||||
*/
|
||||
@property(nonatomic, assign)BOOL udpDnsEnable;
|
||||
|
||||
/**
|
||||
* 使用 udp 进行 Dns 预取时的 server ipv4 数组;当对某个 Host 使用 udp 进行 Dns 预取时,会使用 udpDnsIps 进行并发预取
|
||||
* 当 udpDnsEnable 开启时,使用 udp 进行 Dns 预取方式才会生效
|
||||
* 默认
|
||||
*/
|
||||
@property(nonatomic, copy) NSArray <NSString *> *udpDnsIpv4Servers;
|
||||
|
||||
/**
|
||||
* 使用 udp 进行 Dns 预取时的 server ipv6 数组;当对某个 Host 使用 udp 进行 Dns 预取时,会使用 udpDnsIps 进行并发预取
|
||||
* 当 udpDnsEnable 开启时,使用 udp 进行 Dns 预取方式才会生效
|
||||
* 默认:nil
|
||||
*/
|
||||
@property(nonatomic, copy) NSArray <NSString *> *udpDnsIpv6Servers;
|
||||
|
||||
/**
|
||||
* 是否使用 doh 预取,默认开启
|
||||
*/
|
||||
@property(nonatomic, assign)BOOL dohEnable;
|
||||
|
||||
/**
|
||||
* 使用 doh 预取时的 server 数组;当对某个 Host 使用 Doh 预取时,会使用 dohServers 进行并发预取
|
||||
* 当 dohEnable 开启时,doh 预取才会生效
|
||||
* 注意:如果使用 ip,需保证服务证书与 IP 绑定,避免 sni 问题
|
||||
*/
|
||||
@property(nonatomic, copy) NSArray <NSString *> *dohIpv4Servers;
|
||||
|
||||
/**
|
||||
* 使用 doh 预取时的 server 数组;当对某个 Host 使用 Doh 预取时,会使用 dohServers 进行并发预取
|
||||
* 当 dohEnable 开启时,doh 预取才会生效
|
||||
* 默认:nil
|
||||
* 注意:如果使用 ip,需保证服务证书与 IP 绑定,避免 sni 问题
|
||||
*/
|
||||
@property(nonatomic, copy) NSArray <NSString *> *dohIpv6Servers;
|
||||
|
||||
/**
|
||||
* Host全局冻结时间 单位:秒 默认:60 推荐范围:[30 ~ 120]
|
||||
* 当某个Host的上传失败后并且可能短时间无法恢复,会冻结该Host
|
||||
*/
|
||||
@property(nonatomic, assign)UInt32 globalHostFrozenTime;
|
||||
|
||||
/**
|
||||
* Host局部冻结时间,只会影响当前上传操作 单位:秒 默认:5*60 推荐范围:[60 ~ 10*60]
|
||||
* 当某个Host的上传失败后并且短时间可能会恢复,会局部冻结该Host
|
||||
*/
|
||||
@property(nonatomic, assign)UInt32 partialHostFrozenTime;
|
||||
|
||||
/**
|
||||
* 网络连接状态检测使用的connectCheckURLStrings,网络链接状态检测可能会影响重试机制,启动网络连接状态检测有助于提高上传可用性。
|
||||
* 当请求的 Response 为网络异常时,并发对 connectCheckURLStrings 中 URLString 进行 HEAD 请求,以此检测当前网络状态的链接状态,其中任意一个 URLString 链接成功则认为当前网络状态链接良好;
|
||||
* 当 connectCheckURLStrings 为 nil 或者 空数组时则弃用检测功能。
|
||||
*/
|
||||
@property(nonatomic, copy)NSArray <NSString *> *connectCheckURLStrings;
|
||||
|
||||
/**
|
||||
* 是否开启网络连接状态检测,默认:开启
|
||||
*/
|
||||
@property(nonatomic, assign)BOOL connectCheckEnable;
|
||||
|
||||
/**
|
||||
* 网络连接状态检测HEAD请求超时,默认:2s
|
||||
*/
|
||||
@property(nonatomic, assign)NSTimeInterval connectCheckTimeout;
|
||||
|
||||
|
||||
+ (instancetype)shared;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface QNConfigurationBuilder : NSObject
|
||||
|
||||
/**
|
||||
* 默认上传服务器地址
|
||||
*/
|
||||
@property (nonatomic, strong) QNZone *zone;
|
||||
|
||||
/**
|
||||
* 断点上传时的分片大小
|
||||
* 分片 v1 最小为 1024,即 1K,建议用户配置 >= 512K
|
||||
* 分片 v2 最小为 1024 * 1024,即 1M
|
||||
*/
|
||||
@property (assign) UInt32 chunkSize;
|
||||
|
||||
/**
|
||||
* 如果大于此值就使用断点上传,否则使用form上传
|
||||
*/
|
||||
@property (assign) UInt32 putThreshold;
|
||||
|
||||
/**
|
||||
* 上传失败时每个上传域名的重试次数,默认重试1次
|
||||
*/
|
||||
@property (assign) UInt32 retryMax;
|
||||
|
||||
/**
|
||||
* 重试前等待时长,默认0.5s
|
||||
*/
|
||||
@property (assign) NSTimeInterval retryInterval;
|
||||
|
||||
/**
|
||||
* 超时时间 单位 秒
|
||||
*/
|
||||
@property (assign) UInt32 timeoutInterval;
|
||||
|
||||
/**
|
||||
* 是否使用 https,默认为 YES
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL useHttps;
|
||||
|
||||
/**
|
||||
* 重试时是否允许使用备用上传域名,默认为YES
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL allowBackupHost;
|
||||
|
||||
/**
|
||||
* 是否允许使用加速域名,默认为 false
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL accelerateUploading;
|
||||
|
||||
|
||||
/**
|
||||
* 是否开启并发分片上传,默认为NO
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL useConcurrentResumeUpload;
|
||||
|
||||
/**
|
||||
* 分片上传版本
|
||||
*/
|
||||
@property (nonatomic, assign) QNResumeUploadVersion resumeUploadVersion;
|
||||
|
||||
/**
|
||||
* 并发分片上传的并发任务个数,在concurrentResumeUpload为YES时有效,默认为3个
|
||||
*/
|
||||
@property (nonatomic, assign) UInt32 concurrentTaskCount;
|
||||
|
||||
/**
|
||||
* 持久化记录接口,可以实现将记录持久化到文件,数据库等
|
||||
*/
|
||||
@property (nonatomic, strong) id<QNRecorderDelegate> recorder;
|
||||
|
||||
/**
|
||||
* 为持久化上传记录,根据上传的key以及文件名 生成持久化的记录key
|
||||
*/
|
||||
@property (nonatomic, strong) QNRecorderKeyGenerator recorderKeyGen;
|
||||
|
||||
/**
|
||||
* 上传请求代理配置信息
|
||||
*/
|
||||
@property (nonatomic, strong) NSDictionary *proxy;
|
||||
|
||||
/**
|
||||
* 上传URL转换,使url转换为用户需要的url
|
||||
*/
|
||||
@property (nonatomic, strong) QNUrlConvert converter;
|
||||
|
||||
@end
|
||||
293
Pods/Qiniu/QiniuSDK/Storage/QNConfiguration.m
generated
Normal file
293
Pods/Qiniu/QiniuSDK/Storage/QNConfiguration.m
generated
Normal file
@@ -0,0 +1,293 @@
|
||||
//
|
||||
// QNConfiguration.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 15/5/21.
|
||||
// Copyright (c) 2015年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNResponseInfo.h"
|
||||
#import "QNUpToken.h"
|
||||
#import "QNReportConfig.h"
|
||||
#import "QNAutoZone.h"
|
||||
#import "QN_GTM_Base64.h"
|
||||
|
||||
const UInt32 kQNBlockSize = 4 * 1024 * 1024;
|
||||
const UInt32 kQNDefaultDnsCacheTime = 2 * 60;
|
||||
|
||||
|
||||
@implementation QNConfiguration
|
||||
|
||||
+ (instancetype)defaultConfiguration{
|
||||
QNConfigurationBuilder *builder = [[QNConfigurationBuilder alloc] init];
|
||||
return [[QNConfiguration alloc] initWithBuilder:builder];
|
||||
}
|
||||
|
||||
+ (instancetype)build:(QNConfigurationBuilderBlock)block {
|
||||
QNConfigurationBuilder *builder = [[QNConfigurationBuilder alloc] init];
|
||||
block(builder);
|
||||
return [[QNConfiguration alloc] initWithBuilder:builder];
|
||||
}
|
||||
|
||||
- (instancetype)initWithBuilder:(QNConfigurationBuilder *)builder {
|
||||
if (self = [super init]) {
|
||||
_useConcurrentResumeUpload = builder.useConcurrentResumeUpload;
|
||||
_resumeUploadVersion = builder.resumeUploadVersion;
|
||||
_concurrentTaskCount = builder.concurrentTaskCount;
|
||||
|
||||
_chunkSize = builder.chunkSize;
|
||||
if (builder.resumeUploadVersion == QNResumeUploadVersionV1) {
|
||||
if (_chunkSize < 1024) {
|
||||
_chunkSize = 1024;
|
||||
}
|
||||
} else if (builder.resumeUploadVersion == QNResumeUploadVersionV2) {
|
||||
if (_chunkSize < 1024 * 1024) {
|
||||
_chunkSize = 1024 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
_putThreshold = builder.putThreshold;
|
||||
_retryMax = builder.retryMax;
|
||||
_retryInterval = builder.retryInterval;
|
||||
_timeoutInterval = builder.timeoutInterval;
|
||||
|
||||
_recorder = builder.recorder;
|
||||
_recorderKeyGen = builder.recorderKeyGen;
|
||||
|
||||
_proxy = builder.proxy;
|
||||
|
||||
_converter = builder.converter;
|
||||
|
||||
_zone = builder.zone;
|
||||
|
||||
_useHttps = builder.useHttps;
|
||||
|
||||
_allowBackupHost = builder.allowBackupHost;
|
||||
_accelerateUploading = builder.accelerateUploading;
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface QNGlobalConfiguration(){
|
||||
NSArray *_defaultDohIpv4Servers;
|
||||
NSArray *_defaultDohIpv6Servers;
|
||||
NSArray *_defaultUdpDnsIpv4Servers;
|
||||
NSArray *_defaultUdpDnsIpv6Servers;
|
||||
NSArray *_defaultConnectCheckUrls;
|
||||
}
|
||||
|
||||
@property(nonatomic, strong)NSArray *defaultDohIpv4Servers;
|
||||
@property(nonatomic, strong)NSArray *defaultDohIpv6Servers;
|
||||
@property(nonatomic, strong)NSArray *defaultUdpDnsIpv4Servers;
|
||||
@property(nonatomic, strong)NSArray *defaultUdpDnsIpv6Servers;
|
||||
@property(nonatomic, strong)NSArray *defaultConnectCheckUrls;
|
||||
@end
|
||||
@implementation QNGlobalConfiguration
|
||||
+ (instancetype)shared{
|
||||
static QNGlobalConfiguration *config = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
config = [[QNGlobalConfiguration alloc] init];
|
||||
[config setupData];
|
||||
});
|
||||
return config;
|
||||
}
|
||||
- (void)setupData{
|
||||
_isDnsOpen = YES;
|
||||
_dnsResolveTimeout = 2;
|
||||
_dnsCacheDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches/Dns"];
|
||||
_dnsRepreHostNum = 2;
|
||||
_dnsCacheTime = kQNDefaultDnsCacheTime;
|
||||
_dnsCacheMaxTTL = 10*60;
|
||||
|
||||
_dohEnable = true;
|
||||
_defaultDohIpv4Servers = [self parseBase64Array:@"WyJodHRwczovLzIyMy42LjYuNi9kbnMtcXVlcnkiLCAiaHR0cHM6Ly84LjguOC44L2Rucy1xdWVyeSJd"];
|
||||
|
||||
_udpDnsEnable = true;
|
||||
_defaultUdpDnsIpv4Servers = [self parseBase64Array:@"WyIyMjMuNS41LjUiLCAiMTE0LjExNC4xMTQuMTE0IiwgIjEuMS4xLjEiLCAiOC44LjguOCJd"];
|
||||
|
||||
_globalHostFrozenTime = 60;
|
||||
_partialHostFrozenTime = 5*60;
|
||||
|
||||
_connectCheckEnable = YES;
|
||||
_connectCheckTimeout = 2;
|
||||
_defaultConnectCheckUrls = [self parseBase64Array:@"WyJodHRwczovL3d3dy5xaW5pdS5jb20iLCAiaHR0cHM6Ly93d3cuYmFpZHUuY29tIiwgImh0dHBzOi8vd3d3Lmdvb2dsZS5jb20iXQ=="];
|
||||
_connectCheckURLStrings = nil;
|
||||
}
|
||||
|
||||
- (NSArray *)parseBase64Array:(NSString *)data {
|
||||
NSData *jsonData = [QN_GTM_Base64 decodeData:[data dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
NSArray *ret = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:nil];
|
||||
if (ret && [ret isKindOfClass:[NSArray class]]) {
|
||||
return ret;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)isDohEnable {
|
||||
return _dohEnable && (self.dohIpv4Servers.count > 0 || self.dohIpv6Servers.count > 0) ;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)dohIpv4Servers {
|
||||
if (_dohIpv4Servers) {
|
||||
return _dohIpv4Servers;
|
||||
} else {
|
||||
return self.defaultDohIpv4Servers;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)dohIpv6Servers {
|
||||
if (_dohIpv6Servers) {
|
||||
return _dohIpv6Servers;
|
||||
} else {
|
||||
return self.defaultDohIpv6Servers;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)udpDnsIpv4Servers {
|
||||
if (_udpDnsIpv4Servers) {
|
||||
return _udpDnsIpv4Servers;
|
||||
} else {
|
||||
return self.defaultUdpDnsIpv4Servers;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)udpDnsIpv6Servers {
|
||||
if (_udpDnsIpv6Servers) {
|
||||
return _udpDnsIpv6Servers;
|
||||
} else {
|
||||
return self.defaultUdpDnsIpv6Servers;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isUdpDnsEnable {
|
||||
return _udpDnsEnable && (self.udpDnsIpv4Servers.count > 0 || self.udpDnsIpv6Servers.count > 0) ;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)connectCheckURLStrings {
|
||||
if (_connectCheckURLStrings) {
|
||||
return _connectCheckURLStrings;
|
||||
} else {
|
||||
return self.defaultConnectCheckUrls;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)defaultDohIpv4Servers {
|
||||
NSArray *arr = nil;
|
||||
@synchronized (self) {
|
||||
if (_defaultDohIpv4Servers) {
|
||||
arr = [_defaultDohIpv4Servers copy];
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
- (void)setDefaultDohIpv4Servers:(NSArray *)defaultDohIpv4Servers {
|
||||
@synchronized (self) {
|
||||
_defaultDohIpv4Servers = defaultDohIpv4Servers;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)defaultDohIpv6Servers {
|
||||
NSArray *arr = nil;
|
||||
@synchronized (self) {
|
||||
if (_defaultDohIpv6Servers) {
|
||||
arr = [_defaultDohIpv6Servers copy];
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
- (void)setDefaultDohIpv6Servers:(NSArray *)defaultDohIpv6Servers {
|
||||
@synchronized (self) {
|
||||
_defaultDohIpv6Servers = defaultDohIpv6Servers;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *)defaultUdpDnsIpv4Servers {
|
||||
NSArray *arr = nil;
|
||||
@synchronized (self) {
|
||||
if (_defaultUdpDnsIpv4Servers) {
|
||||
arr = [_defaultUdpDnsIpv4Servers copy];
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
- (void)setDefaultUdpDnsIpv4Servers:(NSArray *)defaultUdpDnsIpv4Servers {
|
||||
@synchronized (self) {
|
||||
_defaultUdpDnsIpv4Servers = defaultUdpDnsIpv4Servers;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *)defaultUdpDnsIpv6Servers {
|
||||
NSArray *arr = nil;
|
||||
@synchronized (self) {
|
||||
if (_defaultUdpDnsIpv6Servers) {
|
||||
arr = [_defaultUdpDnsIpv6Servers copy];
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
- (void)setDefaultUdpDnsIpv6Servers:(NSArray *)defaultUdpDnsIpv6Servers {
|
||||
@synchronized (self) {
|
||||
_defaultUdpDnsIpv6Servers = defaultUdpDnsIpv6Servers;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)defaultConnectCheckUrls {
|
||||
NSArray *arr = nil;
|
||||
@synchronized (self) {
|
||||
if (_defaultConnectCheckUrls) {
|
||||
arr = [_defaultConnectCheckUrls copy];
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
- (void)setDefaultConnectCheckUrls:(NSArray *)defaultConnectCheckUrls {
|
||||
@synchronized (self) {
|
||||
_defaultConnectCheckUrls = defaultConnectCheckUrls;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNConfigurationBuilder
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_zone = [[QNAutoZone alloc] init];
|
||||
_chunkSize = 2 * 1024 * 1024;
|
||||
_putThreshold = 4 * 1024 * 1024;
|
||||
_retryMax = 1;
|
||||
_timeoutInterval = 90;
|
||||
_retryInterval = 0.5;
|
||||
|
||||
_recorder = nil;
|
||||
_recorderKeyGen = nil;
|
||||
|
||||
_proxy = nil;
|
||||
_converter = nil;
|
||||
|
||||
_useHttps = YES;
|
||||
_allowBackupHost = YES;
|
||||
_accelerateUploading = NO;
|
||||
_useConcurrentResumeUpload = NO;
|
||||
_resumeUploadVersion = QNResumeUploadVersionV1;
|
||||
_concurrentTaskCount = 3;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
13
Pods/Qiniu/QiniuSDK/Storage/QNFormUpload.h
generated
Executable file
13
Pods/Qiniu/QiniuSDK/Storage/QNFormUpload.h
generated
Executable file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// QNFormUpload.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 15/1/4.
|
||||
// Copyright (c) 2015年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNBaseUpload.h"
|
||||
|
||||
@interface QNFormUpload : QNBaseUpload
|
||||
|
||||
@end
|
||||
73
Pods/Qiniu/QiniuSDK/Storage/QNFormUpload.m
generated
Normal file
73
Pods/Qiniu/QiniuSDK/Storage/QNFormUpload.m
generated
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// QNFormUpload.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 15/1/4.
|
||||
// Copyright (c) 2015年 Qiniu. All rights reserved.
|
||||
//
|
||||
#import "QNDefine.h"
|
||||
#import "QNLogUtil.h"
|
||||
#import "QNFormUpload.h"
|
||||
#import "QNResponseInfo.h"
|
||||
#import "QNUpProgress.h"
|
||||
#import "QNRequestTransaction.h"
|
||||
|
||||
@interface QNFormUpload ()
|
||||
|
||||
@property(nonatomic, strong)QNUpProgress *progress;
|
||||
|
||||
@property(nonatomic, strong)QNRequestTransaction *uploadTransaction;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNFormUpload
|
||||
|
||||
- (void)startToUpload {
|
||||
[super startToUpload];
|
||||
|
||||
QNLogInfo(@"key:%@ form上传", self.key);
|
||||
|
||||
self.uploadTransaction = [[QNRequestTransaction alloc] initWithConfig:self.config
|
||||
uploadOption:self.option
|
||||
targetRegion:[self getTargetRegion]
|
||||
currentRegion:[self getCurrentRegion]
|
||||
key:self.key
|
||||
token:self.token];
|
||||
|
||||
kQNWeakSelf;
|
||||
void(^progressHandler)(long long totalBytesWritten, long long totalBytesExpectedToWrite) = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite){
|
||||
kQNStrongSelf;
|
||||
[self.progress progress:self.key uploadBytes:totalBytesWritten totalBytes:totalBytesExpectedToWrite];
|
||||
};
|
||||
|
||||
[self.uploadTransaction uploadFormData:self.data
|
||||
fileName:self.fileName
|
||||
progress:progressHandler
|
||||
complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
|
||||
kQNStrongSelf;
|
||||
|
||||
[self addRegionRequestMetricsOfOneFlow:metrics];
|
||||
|
||||
if (!responseInfo.isOK) {
|
||||
if (![self switchRegionAndUploadIfNeededWithErrorResponse:responseInfo]) {
|
||||
[self complete:responseInfo response:response];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
[self.progress notifyDone:self.key totalBytes:self.data.length];
|
||||
[self complete:responseInfo response:response];
|
||||
}];
|
||||
}
|
||||
|
||||
- (QNUpProgress *)progress {
|
||||
if (_progress == nil) {
|
||||
_progress = [QNUpProgress progress:self.option.progressHandler byteProgress:self.option.byteProgressHandler];
|
||||
}
|
||||
return _progress;
|
||||
}
|
||||
|
||||
- (NSString *)upType {
|
||||
return QNUploadUpTypeForm;
|
||||
}
|
||||
@end
|
||||
24
Pods/Qiniu/QiniuSDK/Storage/QNPartsUpload.h
generated
Normal file
24
Pods/Qiniu/QiniuSDK/Storage/QNPartsUpload.h
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// QNPartsUpload.h
|
||||
// QiniuSDK_Mac
|
||||
//
|
||||
// Created by yangsen on 2020/5/7.
|
||||
// Copyright © 2020 Qiniu. All rights reserved.
|
||||
//
|
||||
/// 分片上传,默认为串行
|
||||
|
||||
#import "QNBaseUpload.h"
|
||||
#import "QNUploadInfo.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class QNRequestTransaction;
|
||||
@interface QNPartsUpload : QNBaseUpload
|
||||
|
||||
/// 上传剩余的数据,此方法整合上传流程,上传操作为performUploadRestData,默认串行上传
|
||||
- (void)uploadRestData:(dispatch_block_t)completeHandler;
|
||||
- (void)performUploadRestData:(dispatch_block_t)completeHandler;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
324
Pods/Qiniu/QiniuSDK/Storage/QNPartsUpload.m
generated
Normal file
324
Pods/Qiniu/QiniuSDK/Storage/QNPartsUpload.m
generated
Normal file
@@ -0,0 +1,324 @@
|
||||
//
|
||||
// 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
|
||||
87
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.h
generated
Normal file
87
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.h
generated
Normal file
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// QNPartsUploadPerformer.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2020/12/1.
|
||||
// Copyright © 2020 Qiniu. All rights reserved.
|
||||
//
|
||||
/// 抽象类,不可以直接使用,需要使用子类
|
||||
|
||||
#import "QNFileDelegate.h"
|
||||
#import "QNUploadSource.h"
|
||||
#import "QNResponseInfo.h"
|
||||
#import "QNUploadOption.h"
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNUpToken.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol QNUploadRegion;
|
||||
@class QNUploadInfo, QNRequestTransaction, QNUploadRegionRequestMetrics;
|
||||
|
||||
@interface QNPartsUploadPerformer : NSObject
|
||||
|
||||
@property (nonatomic, copy, readonly) NSString *key;
|
||||
@property (nonatomic, copy, readonly) NSString *fileName;
|
||||
@property (nonatomic, strong, readonly) id <QNUploadSource> uploadSource;
|
||||
@property (nonatomic, strong, readonly) QNUpToken *token;
|
||||
|
||||
@property (nonatomic, strong, readonly) QNUploadOption *option;
|
||||
@property (nonatomic, strong, readonly) QNConfiguration *config;
|
||||
@property (nonatomic, strong, readonly) id <QNRecorderDelegate> recorder;
|
||||
@property (nonatomic, copy, readonly) NSString *recorderKey;
|
||||
|
||||
/// 断点续传时,起始上传偏移
|
||||
@property(nonatomic, strong, readonly)NSNumber *recoveredFrom;
|
||||
@property(nonatomic, strong, readonly)id <QNUploadRegion> currentRegion;
|
||||
@property(nonatomic, strong, readonly)QNUploadInfo *uploadInfo;
|
||||
|
||||
- (instancetype)initWithSource:(id<QNUploadSource>)uploadSource
|
||||
fileName:(NSString *)fileName
|
||||
key:(NSString *)key
|
||||
token:(QNUpToken *)token
|
||||
option:(QNUploadOption *)option
|
||||
configuration:(QNConfiguration *)config
|
||||
recorderKey:(NSString *)recorderKey;
|
||||
|
||||
// 是否可以重新加载资源
|
||||
- (BOOL)couldReloadInfo;
|
||||
|
||||
// 重新加载资源
|
||||
- (BOOL)reloadInfo;
|
||||
|
||||
- (void)switchRegion:(id <QNUploadRegion>)region;
|
||||
|
||||
/// 通知回调当前进度
|
||||
- (void)notifyProgress:(BOOL)isCompleted;
|
||||
|
||||
/// 分片信息保存本地
|
||||
- (void)recordUploadInfo;
|
||||
/// 分片信息从本地移除
|
||||
- (void)removeUploadInfoRecord;
|
||||
|
||||
/// 根据字典构造分片信息 【子类实现】
|
||||
- (QNUploadInfo *)getFileInfoWithDictionary:(NSDictionary * _Nonnull)fileInfoDictionary;
|
||||
/// 根据配置构造分片信息 【子类实现】
|
||||
- (QNUploadInfo *)getDefaultUploadInfo;
|
||||
|
||||
- (QNRequestTransaction *)createUploadRequestTransaction;
|
||||
- (void)destroyUploadRequestTransaction:(QNRequestTransaction *)transaction;
|
||||
|
||||
/// 上传前,服务端配置工作 【子类实现】
|
||||
- (void)serverInit:(void(^)(QNResponseInfo * _Nullable responseInfo,
|
||||
QNUploadRegionRequestMetrics * _Nullable metrics,
|
||||
NSDictionary * _Nullable response))completeHandler;
|
||||
/// 上传文件分片 【子类实现】
|
||||
- (void)uploadNextData:(void(^)(BOOL stop,
|
||||
QNResponseInfo * _Nullable responseInfo,
|
||||
QNUploadRegionRequestMetrics * _Nullable metrics,
|
||||
NSDictionary * _Nullable response))completeHandler;
|
||||
/// 完成上传,服务端组织文件信息 【子类实现】
|
||||
- (void)completeUpload:(void(^)(QNResponseInfo * _Nullable responseInfo,
|
||||
QNUploadRegionRequestMetrics * _Nullable metrics,
|
||||
NSDictionary * _Nullable response))completeHandler;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
237
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.m
generated
Normal file
237
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformer.m
generated
Normal file
@@ -0,0 +1,237 @@
|
||||
//
|
||||
// QNPartsUploadPerformer.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2020/12/1.
|
||||
// Copyright © 2020 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNLogUtil.h"
|
||||
#import "QNAsyncRun.h"
|
||||
#import "QNUpToken.h"
|
||||
#import "QNZoneInfo.h"
|
||||
#import "QNUploadOption.h"
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNUploadInfo.h"
|
||||
#import "QNUploadRegionInfo.h"
|
||||
#import "QNRecorderDelegate.h"
|
||||
#import "QNUploadDomainRegion.h"
|
||||
#import "QNPartsUploadPerformer.h"
|
||||
#import "QNUpProgress.h"
|
||||
#import "QNRequestTransaction.h"
|
||||
|
||||
#define kQNRecordFileInfoKey @"recordFileInfo"
|
||||
#define kQNRecordZoneInfoKey @"recordZoneInfo"
|
||||
|
||||
@interface QNPartsUploadPerformer()
|
||||
|
||||
@property (nonatomic, copy) NSString *key;
|
||||
@property (nonatomic, copy) NSString *fileName;
|
||||
@property (nonatomic, strong) id <QNUploadSource> uploadSource;
|
||||
@property (nonatomic, strong) QNUpToken *token;
|
||||
|
||||
@property (nonatomic, strong) QNUploadOption *option;
|
||||
@property (nonatomic, strong) QNConfiguration *config;
|
||||
@property (nonatomic, strong) id <QNRecorderDelegate> recorder;
|
||||
@property (nonatomic, copy) NSString *recorderKey;
|
||||
|
||||
@property (nonatomic, strong) NSNumber *recoveredFrom;
|
||||
@property (nonatomic, strong) id <QNUploadRegion> targetRegion;
|
||||
@property (nonatomic, strong) id <QNUploadRegion> currentRegion;
|
||||
@property (nonatomic, strong) QNUploadInfo *uploadInfo;
|
||||
|
||||
@property(nonatomic, strong) NSLock *progressLocker;
|
||||
@property(nonatomic, strong) QNUpProgress *progress;
|
||||
@property(nonatomic, strong) NSMutableArray <QNRequestTransaction *> *uploadTransactions;
|
||||
|
||||
@end
|
||||
@implementation QNPartsUploadPerformer
|
||||
|
||||
- (instancetype)initWithSource:(id<QNUploadSource>)uploadSource
|
||||
fileName:(NSString *)fileName
|
||||
key:(NSString *)key
|
||||
token:(QNUpToken *)token
|
||||
option:(QNUploadOption *)option
|
||||
configuration:(QNConfiguration *)config
|
||||
recorderKey:(NSString *)recorderKey {
|
||||
if (self = [super init]) {
|
||||
_uploadSource = uploadSource;
|
||||
_fileName = fileName;
|
||||
_key = key;
|
||||
_token = token;
|
||||
_option = option;
|
||||
_config = config;
|
||||
_recorder = config.recorder;
|
||||
_recorderKey = recorderKey;
|
||||
|
||||
[self initData];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initData {
|
||||
self.uploadTransactions = [NSMutableArray array];
|
||||
|
||||
if (!self.uploadInfo) {
|
||||
self.uploadInfo = [self getDefaultUploadInfo];
|
||||
}
|
||||
[self recoverUploadInfoFromRecord];
|
||||
}
|
||||
|
||||
- (BOOL)couldReloadInfo {
|
||||
return [self.uploadInfo couldReloadSource];
|
||||
}
|
||||
|
||||
- (BOOL)reloadInfo {
|
||||
self.recoveredFrom = nil;
|
||||
[self.uploadInfo clearUploadState];
|
||||
return [self.uploadInfo reloadSource];
|
||||
}
|
||||
|
||||
- (void)switchRegion:(id <QNUploadRegion>)region {
|
||||
self.currentRegion = region;
|
||||
if (!self.targetRegion) {
|
||||
self.targetRegion = region;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)notifyProgress:(BOOL)isCompleted {
|
||||
if (self.uploadInfo == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCompleted) {
|
||||
[self.progress notifyDone:self.key totalBytes:[self.uploadInfo getSourceSize]];
|
||||
} else {
|
||||
[self.progress progress:self.key uploadBytes:[self.uploadInfo uploadSize] totalBytes:[self.uploadInfo getSourceSize]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)recordUploadInfo {
|
||||
|
||||
NSString *key = self.recorderKey;
|
||||
if (self.recorder == nil || key == nil || key.length == 0) {
|
||||
return;
|
||||
}
|
||||
@synchronized (self) {
|
||||
NSDictionary *zoneInfo = [self.currentRegion zoneInfo].detailInfo;
|
||||
NSDictionary *uploadInfo = [self.uploadInfo toDictionary];
|
||||
if (zoneInfo && uploadInfo) {
|
||||
NSDictionary *info = @{kQNRecordZoneInfoKey : zoneInfo,
|
||||
kQNRecordFileInfoKey : uploadInfo};
|
||||
NSData *data = [NSJSONSerialization dataWithJSONObject:info options:NSJSONWritingPrettyPrinted error:nil];
|
||||
if (data) {
|
||||
[self.recorder set:key data:data];
|
||||
}
|
||||
}
|
||||
}
|
||||
QNLogInfo(@"key:%@ recorderKey:%@ recordUploadInfo", self.key, self.recorderKey);
|
||||
}
|
||||
|
||||
- (void)removeUploadInfoRecord {
|
||||
|
||||
self.recoveredFrom = nil;
|
||||
[self.uploadInfo clearUploadState];
|
||||
[self.recorder del:self.recorderKey];
|
||||
QNLogInfo(@"key:%@ recorderKey:%@ removeUploadInfoRecord", self.key, self.recorderKey);
|
||||
}
|
||||
|
||||
- (void)recoverUploadInfoFromRecord {
|
||||
QNLogInfo(@"key:%@ recorderKey:%@ recorder:%@ recoverUploadInfoFromRecord", self.key, self.recorderKey, self.recorder);
|
||||
|
||||
NSString *key = self.recorderKey;
|
||||
if (self.recorder == nil || key == nil || [key isEqualToString:@""]) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSData *data = [self.recorder get:key];
|
||||
if (data == nil) {
|
||||
QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord data:nil", self.key, self.recorderKey);
|
||||
return;
|
||||
}
|
||||
|
||||
NSError *error = nil;
|
||||
NSDictionary *info = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
|
||||
if (error != nil || ![info isKindOfClass:[NSDictionary class]]) {
|
||||
QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord json error", self.key, self.recorderKey);
|
||||
[self.recorder del:self.key];
|
||||
return;
|
||||
}
|
||||
|
||||
QNZoneInfo *zoneInfo = [QNZoneInfo zoneInfoFromDictionary:info[kQNRecordZoneInfoKey]];
|
||||
QNUploadInfo *recoverUploadInfo = [self getFileInfoWithDictionary:info[kQNRecordFileInfoKey]];
|
||||
|
||||
if (zoneInfo && self.uploadInfo && [recoverUploadInfo isValid]
|
||||
&& [self.uploadInfo isSameUploadInfo:recoverUploadInfo]) {
|
||||
QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord valid", self.key, self.recorderKey);
|
||||
|
||||
[recoverUploadInfo checkInfoStateAndUpdate];
|
||||
self.uploadInfo = recoverUploadInfo;
|
||||
|
||||
QNUploadDomainRegion *region = [[QNUploadDomainRegion alloc] init];
|
||||
[region setupRegionData:zoneInfo];
|
||||
self.currentRegion = region;
|
||||
self.targetRegion = region;
|
||||
self.recoveredFrom = @([recoverUploadInfo uploadSize]);
|
||||
} else {
|
||||
QNLogInfo(@"key:%@ recorderKey:%@ recoverUploadInfoFromRecord invalid", self.key, self.recorderKey);
|
||||
|
||||
[self.recorder del:self.key];
|
||||
self.currentRegion = nil;
|
||||
self.targetRegion = nil;
|
||||
self.recoveredFrom = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (QNRequestTransaction *)createUploadRequestTransaction {
|
||||
QNRequestTransaction *transaction = [[QNRequestTransaction alloc] initWithConfig:self.config
|
||||
uploadOption:self.option
|
||||
targetRegion:self.targetRegion
|
||||
currentRegion:self.currentRegion
|
||||
key:self.key
|
||||
token:self.token];
|
||||
@synchronized (self) {
|
||||
[self.uploadTransactions addObject:transaction];
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
- (void)destroyUploadRequestTransaction:(QNRequestTransaction *)transaction {
|
||||
if (transaction) {
|
||||
@synchronized (self) {
|
||||
[self.uploadTransactions removeObject:transaction];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (QNUploadInfo *)getFileInfoWithDictionary:(NSDictionary *)fileInfoDictionary {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (QNUploadInfo *)getDefaultUploadInfo {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)serverInit:(void (^)(QNResponseInfo * _Nullable,
|
||||
QNUploadRegionRequestMetrics * _Nullable,
|
||||
NSDictionary * _Nullable))completeHandler {}
|
||||
|
||||
- (void)uploadNextData:(void (^)(BOOL stop,
|
||||
QNResponseInfo * _Nullable,
|
||||
QNUploadRegionRequestMetrics * _Nullable,
|
||||
NSDictionary * _Nullable))completeHandler {}
|
||||
|
||||
- (void)completeUpload:(void (^)(QNResponseInfo * _Nullable,
|
||||
QNUploadRegionRequestMetrics * _Nullable,
|
||||
NSDictionary * _Nullable))completeHandler {}
|
||||
|
||||
- (QNUpProgress *)progress {
|
||||
[self.progressLocker lock];
|
||||
if (_progress == nil) {
|
||||
_progress = [QNUpProgress progress:self.option.progressHandler byteProgress:self.option.byteProgressHandler];
|
||||
}
|
||||
[self.progressLocker unlock];
|
||||
return _progress;
|
||||
}
|
||||
|
||||
@end
|
||||
19
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.h
generated
Normal file
19
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.h
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// QNPartsUploadApiV1.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2020/11/30.
|
||||
// Copyright © 2020 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNPartsUploadPerformer.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNPartsUploadPerformerV1 : QNPartsUploadPerformer
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
188
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.m
generated
Normal file
188
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV1.m
generated
Normal file
@@ -0,0 +1,188 @@
|
||||
//
|
||||
// QNPartsUploadApiV1.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2020/11/30.
|
||||
// Copyright © 2020 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNLogUtil.h"
|
||||
#import "QNDefine.h"
|
||||
#import "QNRequestTransaction.h"
|
||||
#import "QNUploadInfoV1.h"
|
||||
#import "QNPartsUploadPerformerV1.h"
|
||||
|
||||
@interface QNPartsUploadPerformerV1()
|
||||
@end
|
||||
@implementation QNPartsUploadPerformerV1
|
||||
+ (long long)blockSize{
|
||||
return 4 * 1024 * 1024;
|
||||
}
|
||||
|
||||
- (QNUploadInfo *)getFileInfoWithDictionary:(NSDictionary *)fileInfoDictionary {
|
||||
return [QNUploadInfoV1 info:self.uploadSource dictionary:fileInfoDictionary];
|
||||
}
|
||||
|
||||
- (QNUploadInfo *)getDefaultUploadInfo {
|
||||
return [QNUploadInfoV1 info:self.uploadSource configuration:self.config];
|
||||
}
|
||||
|
||||
- (void)serverInit:(void(^)(QNResponseInfo * _Nullable responseInfo,
|
||||
QNUploadRegionRequestMetrics * _Nullable metrics,
|
||||
NSDictionary * _Nullable response))completeHandler {
|
||||
QNResponseInfo *responseInfo = [QNResponseInfo successResponse];
|
||||
completeHandler(responseInfo, nil, nil);
|
||||
}
|
||||
|
||||
- (void)uploadNextData:(void(^)(BOOL stop,
|
||||
QNResponseInfo * _Nullable responseInfo,
|
||||
QNUploadRegionRequestMetrics * _Nullable metrics,
|
||||
NSDictionary * _Nullable response))completeHandler {
|
||||
QNUploadInfoV1 *uploadInfo = (QNUploadInfoV1 *)self.uploadInfo;
|
||||
|
||||
NSError *error;
|
||||
QNUploadBlock *block = nil;
|
||||
QNUploadData *chunk = nil;
|
||||
@synchronized (self) {
|
||||
block = [uploadInfo nextUploadBlock:&error];
|
||||
chunk = [uploadInfo nextUploadData:block];
|
||||
chunk.state = QNUploadStateUploading;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
QNResponseInfo *responseInfo = [QNResponseInfo responseInfoWithLocalIOError:[NSString stringWithFormat:@"%@", error]];
|
||||
completeHandler(YES, responseInfo, nil, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
if (block == nil || chunk == nil) {
|
||||
QNLogInfo(@"key:%@ no chunk left", self.key);
|
||||
|
||||
QNResponseInfo *responseInfo = nil;
|
||||
if (uploadInfo.getSourceSize == 0) {
|
||||
responseInfo = [QNResponseInfo responseInfoOfZeroData:@"file is empty"];
|
||||
} else {
|
||||
responseInfo = [QNResponseInfo responseInfoWithSDKInteriorError:@"no chunk left"];
|
||||
}
|
||||
completeHandler(YES, responseInfo, nil, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
if (chunk.data == nil) {
|
||||
QNLogInfo(@"key:%@ chunk data is nil", self.key);
|
||||
|
||||
QNResponseInfo *responseInfo = [QNResponseInfo responseInfoOfZeroData:@"chunk data is nil"];;
|
||||
completeHandler(YES, responseInfo, nil, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
kQNWeakSelf;
|
||||
void (^progress)(long long, long long) = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite){
|
||||
kQNStrongSelf;
|
||||
chunk.uploadSize = totalBytesWritten;
|
||||
[self notifyProgress:false];
|
||||
};
|
||||
|
||||
void (^completeHandlerP)(QNResponseInfo *, QNUploadRegionRequestMetrics *, NSDictionary *) = ^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
|
||||
kQNStrongSelf;
|
||||
|
||||
NSString *blockContext = response[@"ctx"];
|
||||
NSNumber *expiredAt = response[@"expired_at"];
|
||||
if (responseInfo.isOK && blockContext && expiredAt) {
|
||||
block.context = blockContext;
|
||||
block.expiredAt = expiredAt;
|
||||
chunk.state = QNUploadStateComplete;
|
||||
[self recordUploadInfo];
|
||||
[self notifyProgress:false];
|
||||
} else {
|
||||
chunk.state = QNUploadStateWaitToUpload;
|
||||
}
|
||||
completeHandler(NO, responseInfo, metrics, response);
|
||||
};
|
||||
|
||||
if ([uploadInfo isFirstData:chunk]) {
|
||||
QNLogInfo(@"key:%@ makeBlock", self.key);
|
||||
[self makeBlock:block firstChunk:chunk chunkData:chunk.data progress:progress completeHandler:completeHandlerP];
|
||||
} else {
|
||||
QNLogInfo(@"key:%@ uploadChunk", self.key);
|
||||
[self uploadChunk:block chunk:chunk chunkData:chunk.data progress:progress completeHandler:completeHandlerP];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)completeUpload:(void(^)(QNResponseInfo * _Nullable responseInfo,
|
||||
QNUploadRegionRequestMetrics * _Nullable metrics,
|
||||
NSDictionary * _Nullable response))completeHandler {
|
||||
QNUploadInfoV1 *uploadInfo = (QNUploadInfoV1 *)self.uploadInfo;
|
||||
|
||||
QNRequestTransaction *transaction = [self createUploadRequestTransaction];
|
||||
|
||||
kQNWeakSelf;
|
||||
kQNWeakObj(transaction);
|
||||
[transaction makeFile:[uploadInfo getSourceSize]
|
||||
fileName:self.fileName
|
||||
blockContexts:[uploadInfo allBlocksContexts]
|
||||
complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
|
||||
kQNStrongSelf;
|
||||
kQNStrongObj(transaction);
|
||||
if (responseInfo.isOK) {
|
||||
[self notifyProgress:true];
|
||||
}
|
||||
completeHandler(responseInfo, metrics, response);
|
||||
[self destroyUploadRequestTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
- (void)makeBlock:(QNUploadBlock *)block
|
||||
firstChunk:(QNUploadData *)chunk
|
||||
chunkData:(NSData *)chunkData
|
||||
progress:(void(^)(long long totalBytesWritten,
|
||||
long long totalBytesExpectedToWrite))progress
|
||||
completeHandler:(void(^)(QNResponseInfo * _Nullable responseInfo,
|
||||
QNUploadRegionRequestMetrics * _Nullable metrics,
|
||||
NSDictionary * _Nullable response))completeHandler {
|
||||
|
||||
QNRequestTransaction *transaction = [self createUploadRequestTransaction];
|
||||
kQNWeakSelf;
|
||||
kQNWeakObj(transaction);
|
||||
[transaction makeBlock:block.offset
|
||||
blockSize:block.size
|
||||
firstChunkData:chunkData
|
||||
progress:progress
|
||||
complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
|
||||
kQNStrongSelf;
|
||||
kQNStrongObj(transaction);
|
||||
|
||||
completeHandler(responseInfo, metrics, response);
|
||||
[self destroyUploadRequestTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
- (void)uploadChunk:(QNUploadBlock *)block
|
||||
chunk:(QNUploadData *)chunk
|
||||
chunkData:(NSData *)chunkData
|
||||
progress:(void(^)(long long totalBytesWritten,
|
||||
long long totalBytesExpectedToWrite))progress
|
||||
completeHandler:(void(^)(QNResponseInfo * _Nullable responseInfo,
|
||||
QNUploadRegionRequestMetrics * _Nullable metrics,
|
||||
NSDictionary * _Nullable response))completeHandler {
|
||||
|
||||
QNRequestTransaction *transaction = [self createUploadRequestTransaction];
|
||||
kQNWeakSelf;
|
||||
kQNWeakObj(transaction);
|
||||
[transaction uploadChunk:block.context
|
||||
blockOffset:block.offset
|
||||
chunkData:chunkData
|
||||
chunkOffset:chunk.offset
|
||||
progress:progress
|
||||
complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
|
||||
kQNStrongSelf;
|
||||
kQNStrongObj(transaction);
|
||||
|
||||
completeHandler(responseInfo, metrics, response);
|
||||
[self destroyUploadRequestTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
17
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.h
generated
Normal file
17
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.h
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// QNPartsUploadApiV2.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2020/11/30.
|
||||
// Copyright © 2020 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNPartsUploadPerformer.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNPartsUploadPerformerV2 : QNPartsUploadPerformer
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
148
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.m
generated
Normal file
148
Pods/Qiniu/QiniuSDK/Storage/QNPartsUploadPerformerV2.m
generated
Normal file
@@ -0,0 +1,148 @@
|
||||
//
|
||||
// QNPartsUploadApiV2.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2020/11/30.
|
||||
// Copyright © 2020 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNLogUtil.h"
|
||||
#import "QNDefine.h"
|
||||
#import "QNRequestTransaction.h"
|
||||
#import "QNUploadInfoV2.h"
|
||||
#import "QNPartsUploadPerformerV2.h"
|
||||
|
||||
@interface QNPartsUploadPerformerV2()
|
||||
@end
|
||||
@implementation QNPartsUploadPerformerV2
|
||||
|
||||
- (QNUploadInfo *)getFileInfoWithDictionary:(NSDictionary *)fileInfoDictionary {
|
||||
return [QNUploadInfoV2 info:self.uploadSource dictionary:fileInfoDictionary];
|
||||
}
|
||||
|
||||
- (QNUploadInfo *)getDefaultUploadInfo {
|
||||
return [QNUploadInfoV2 info:self.uploadSource configuration:self.config];
|
||||
}
|
||||
|
||||
- (void)serverInit:(void(^)(QNResponseInfo * _Nullable responseInfo,
|
||||
QNUploadRegionRequestMetrics * _Nullable metrics,
|
||||
NSDictionary * _Nullable response))completeHandler {
|
||||
|
||||
QNUploadInfoV2 *uploadInfo = (QNUploadInfoV2 *)self.uploadInfo;
|
||||
if (uploadInfo && [uploadInfo isValid]) {
|
||||
QNLogInfo(@"key:%@ serverInit success", self.key);
|
||||
QNResponseInfo *responseInfo = [QNResponseInfo successResponse];
|
||||
completeHandler(responseInfo, nil, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
QNRequestTransaction *transaction = [self createUploadRequestTransaction];
|
||||
|
||||
kQNWeakSelf;
|
||||
kQNWeakObj(transaction);
|
||||
[transaction initPart:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
|
||||
kQNStrongSelf;
|
||||
kQNStrongObj(transaction);
|
||||
|
||||
NSString *uploadId = response[@"uploadId"];
|
||||
NSNumber *expireAt = response[@"expireAt"];
|
||||
if (responseInfo.isOK && uploadId && expireAt) {
|
||||
uploadInfo.uploadId = uploadId;
|
||||
uploadInfo.expireAt = expireAt;
|
||||
[self recordUploadInfo];
|
||||
}
|
||||
completeHandler(responseInfo, metrics, response);
|
||||
[self destroyUploadRequestTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)uploadNextData:(void(^)(BOOL stop,
|
||||
QNResponseInfo * _Nullable responseInfo,
|
||||
QNUploadRegionRequestMetrics * _Nullable metrics,
|
||||
NSDictionary * _Nullable response))completeHandler {
|
||||
QNUploadInfoV2 *uploadInfo = (QNUploadInfoV2 *)self.uploadInfo;
|
||||
|
||||
NSError *error = nil;
|
||||
QNUploadData *data = nil;
|
||||
@synchronized (self) {
|
||||
data = [uploadInfo nextUploadData:&error];
|
||||
data.state = QNUploadStateUploading;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
QNResponseInfo *responseInfo = [QNResponseInfo responseInfoWithLocalIOError:[NSString stringWithFormat:@"%@", error]];
|
||||
completeHandler(YES, responseInfo, nil, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
// 上传完毕
|
||||
if (data == nil) {
|
||||
QNLogInfo(@"key:%@ no data left", self.key);
|
||||
|
||||
QNResponseInfo *responseInfo = nil;
|
||||
if (uploadInfo.getSourceSize == 0) {
|
||||
responseInfo = [QNResponseInfo responseInfoOfZeroData:@"file is empty"];
|
||||
} else {
|
||||
responseInfo = [QNResponseInfo responseInfoWithSDKInteriorError:@"no chunk left"];
|
||||
}
|
||||
completeHandler(YES, responseInfo, nil, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
kQNWeakSelf;
|
||||
void (^progress)(long long, long long) = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite){
|
||||
kQNStrongSelf;
|
||||
data.uploadSize = totalBytesWritten;
|
||||
[self notifyProgress:false];
|
||||
};
|
||||
|
||||
QNRequestTransaction *transaction = [self createUploadRequestTransaction];
|
||||
|
||||
kQNWeakObj(transaction);
|
||||
[transaction uploadPart:uploadInfo.uploadId
|
||||
partIndex:[uploadInfo getPartIndexOfData:data]
|
||||
partData:data.data
|
||||
progress:progress
|
||||
complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
|
||||
kQNStrongSelf;
|
||||
kQNStrongObj(transaction);
|
||||
|
||||
NSString *etag = response[@"etag"];
|
||||
NSString *md5 = response[@"md5"];
|
||||
if (responseInfo.isOK && etag && md5) {
|
||||
data.etag = etag;
|
||||
data.state = QNUploadStateComplete;
|
||||
[self recordUploadInfo];
|
||||
[self notifyProgress:false];
|
||||
} else {
|
||||
data.state = QNUploadStateWaitToUpload;
|
||||
}
|
||||
completeHandler(NO, responseInfo, metrics, response);
|
||||
[self destroyUploadRequestTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)completeUpload:(void(^)(QNResponseInfo * _Nullable responseInfo,
|
||||
QNUploadRegionRequestMetrics * _Nullable metrics,
|
||||
NSDictionary * _Nullable response))completeHandler {
|
||||
|
||||
QNUploadInfoV2 *uploadInfo = (QNUploadInfoV2 *)self.uploadInfo;
|
||||
|
||||
NSArray *partInfoArray = [uploadInfo getPartInfoArray];
|
||||
QNRequestTransaction *transaction = [self createUploadRequestTransaction];
|
||||
|
||||
kQNWeakSelf;
|
||||
kQNWeakObj(transaction);
|
||||
[transaction completeParts:self.fileName uploadId:uploadInfo.uploadId partInfoArray:partInfoArray complete:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
|
||||
kQNStrongSelf;
|
||||
kQNStrongObj(transaction);
|
||||
if (responseInfo.isOK) {
|
||||
[self notifyProgress:true];
|
||||
}
|
||||
completeHandler(responseInfo, metrics, response);
|
||||
[self destroyUploadRequestTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
23
Pods/Qiniu/QiniuSDK/Storage/QNUpProgress.h
generated
Normal file
23
Pods/Qiniu/QiniuSDK/Storage/QNUpProgress.h
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// QNUpProgress.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/21.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUploadOption.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNUpProgress : NSObject
|
||||
|
||||
+ (instancetype)progress:(QNUpProgressHandler)progress byteProgress:(QNUpByteProgressHandler)byteProgress;
|
||||
|
||||
- (void)progress:(NSString *)key uploadBytes:(long long)uploadBytes totalBytes:(long long)totalBytes;
|
||||
|
||||
- (void)notifyDone:(NSString *)key totalBytes:(long long)totalBytes;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
87
Pods/Qiniu/QiniuSDK/Storage/QNUpProgress.m
generated
Normal file
87
Pods/Qiniu/QiniuSDK/Storage/QNUpProgress.m
generated
Normal file
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// QNUpProgress.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/21.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNAsyncRun.h"
|
||||
#import "QNUpProgress.h"
|
||||
|
||||
@interface QNUpProgress()
|
||||
|
||||
@property(nonatomic, assign)long long maxProgressUploadBytes;
|
||||
@property(nonatomic, assign)long long previousUploadBytes;
|
||||
@property(nonatomic, copy)QNUpProgressHandler progress;
|
||||
@property(nonatomic, copy)QNUpByteProgressHandler byteProgress;
|
||||
|
||||
@end
|
||||
@implementation QNUpProgress
|
||||
|
||||
+ (instancetype)progress:(QNUpProgressHandler)progress byteProgress:(QNUpByteProgressHandler)byteProgress {
|
||||
QNUpProgress *upProgress = [[QNUpProgress alloc] init];
|
||||
upProgress.maxProgressUploadBytes = -1;
|
||||
upProgress.previousUploadBytes = 0;
|
||||
upProgress.progress = progress;
|
||||
upProgress.byteProgress = byteProgress;
|
||||
return upProgress;
|
||||
}
|
||||
|
||||
- (void)progress:(NSString *)key uploadBytes:(long long)uploadBytes totalBytes:(long long)totalBytes {
|
||||
if ((self.progress == nil && self.byteProgress == nil) || uploadBytes < 0 || (totalBytes > 0 && uploadBytes > totalBytes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (totalBytes > 0) {
|
||||
@synchronized (self) {
|
||||
if (self.maxProgressUploadBytes < 0) {
|
||||
self.maxProgressUploadBytes = totalBytes * 0.95;
|
||||
}
|
||||
}
|
||||
|
||||
if (uploadBytes > self.maxProgressUploadBytes) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@synchronized (self) {
|
||||
if (uploadBytes > self.previousUploadBytes) {
|
||||
self.previousUploadBytes = uploadBytes;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[self notify:key uploadBytes:uploadBytes totalBytes:totalBytes];
|
||||
}
|
||||
|
||||
- (void)notifyDone:(NSString *)key totalBytes:(long long)totalBytes {
|
||||
[self notify:key uploadBytes:totalBytes totalBytes:totalBytes];
|
||||
}
|
||||
|
||||
- (void)notify:(NSString *)key uploadBytes:(long long)uploadBytes totalBytes:(long long)totalBytes {
|
||||
if (self.progress == nil && self.byteProgress == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.byteProgress) {
|
||||
QNAsyncRunInMain(^{
|
||||
self.byteProgress(key, uploadBytes, totalBytes);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (totalBytes <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.progress) {
|
||||
QNAsyncRunInMain(^{
|
||||
double notifyPercent = (double) uploadBytes / (double) totalBytes;
|
||||
self.progress(key, notifyPercent);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
33
Pods/Qiniu/QiniuSDK/Storage/QNUpToken.h
generated
Normal file
33
Pods/Qiniu/QiniuSDK/Storage/QNUpToken.h
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// QNUpToken.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 15/6/7.
|
||||
// Copyright (c) 2015年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface QNUpToken : NSObject
|
||||
|
||||
+ (instancetype)parse:(NSString *)token;
|
||||
|
||||
@property (assign, nonatomic, readonly) long deadline;
|
||||
@property (copy , nonatomic, readonly) NSString *access;
|
||||
@property (copy , nonatomic, readonly) NSString *bucket;
|
||||
@property (copy , nonatomic, readonly) NSString *token;
|
||||
|
||||
@property (readonly) BOOL isValid;
|
||||
@property (readonly) BOOL hasReturnUrl;
|
||||
|
||||
+ (instancetype)getInvalidToken;
|
||||
|
||||
- (NSString *)index;
|
||||
|
||||
/// 是否在未来 duration 分钟内有效
|
||||
- (BOOL)isValidForDuration:(long)duration;
|
||||
|
||||
/// 在是否在 date 之前有效
|
||||
- (BOOL)isValidBeforeDate:(NSDate *)date;
|
||||
|
||||
@end
|
||||
103
Pods/Qiniu/QiniuSDK/Storage/QNUpToken.m
generated
Normal file
103
Pods/Qiniu/QiniuSDK/Storage/QNUpToken.m
generated
Normal file
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// QNUpToken.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 15/6/7.
|
||||
// Copyright (c) 2015年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUrlSafeBase64.h"
|
||||
#import "QNUpToken.h"
|
||||
|
||||
#define kQNPolicyKeyScope @"scope"
|
||||
#define kQNPolicyKeyDeadline @"deadline"
|
||||
#define kQNPolicyKeyReturnUrl @"returnUrl"
|
||||
@interface QNUpToken ()
|
||||
|
||||
- (instancetype)init:(NSDictionary *)policy token:(NSString *)token;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNUpToken
|
||||
|
||||
+ (instancetype)getInvalidToken {
|
||||
QNUpToken *token = [[QNUpToken alloc] init];
|
||||
token->_deadline = -1;
|
||||
return token;
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSDictionary *)policy token:(NSString *)token {
|
||||
if (self = [super init]) {
|
||||
_token = token;
|
||||
_access = [self getAccess];
|
||||
_bucket = [self getBucket:policy];
|
||||
_deadline = [policy[kQNPolicyKeyDeadline] longValue];
|
||||
_hasReturnUrl = (policy[kQNPolicyKeyReturnUrl] != nil);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)getAccess {
|
||||
|
||||
NSRange range = [_token rangeOfString:@":" options:NSCaseInsensitiveSearch];
|
||||
return [_token substringToIndex:range.location];
|
||||
}
|
||||
|
||||
- (NSString *)getBucket:(NSDictionary *)info {
|
||||
|
||||
NSString *scope = [info objectForKey:kQNPolicyKeyScope];
|
||||
if (!scope || [scope isKindOfClass:[NSNull class]]) {
|
||||
return @"";
|
||||
}
|
||||
|
||||
NSRange range = [scope rangeOfString:@":"];
|
||||
if (range.location == NSNotFound) {
|
||||
return scope;
|
||||
}
|
||||
return [scope substringToIndex:range.location];
|
||||
}
|
||||
|
||||
+ (instancetype)parse:(NSString *)token {
|
||||
if (token == nil) {
|
||||
return nil;
|
||||
}
|
||||
NSArray *array = [token componentsSeparatedByString:@":"];
|
||||
if (array == nil || array.count != 3) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *data = [QNUrlSafeBase64 decodeString:array[2]];
|
||||
if (!data) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSError *tmp = nil;
|
||||
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&tmp];
|
||||
if (tmp != nil || dict[kQNPolicyKeyScope] == nil || dict[kQNPolicyKeyDeadline] == nil) {
|
||||
return nil;
|
||||
}
|
||||
return [[QNUpToken alloc] init:dict token:token];
|
||||
}
|
||||
|
||||
- (NSString *)index {
|
||||
return [NSString stringWithFormat:@"%@:%@", _access, _bucket];
|
||||
}
|
||||
|
||||
- (BOOL)isValid {
|
||||
return _access && _access.length > 0 && _bucket && _bucket.length > 0;
|
||||
}
|
||||
|
||||
- (BOOL)isValidForDuration:(long)duration {
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:duration];
|
||||
return [self isValidBeforeDate:date];
|
||||
}
|
||||
|
||||
- (BOOL)isValidBeforeDate:(NSDate *)date {
|
||||
if (date == nil) {
|
||||
return NO;
|
||||
}
|
||||
return [date timeIntervalSince1970] < self.deadline;
|
||||
}
|
||||
|
||||
@end
|
||||
57
Pods/Qiniu/QiniuSDK/Storage/QNUploadBlock.h
generated
Normal file
57
Pods/Qiniu/QiniuSDK/Storage/QNUploadBlock.h
generated
Normal file
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// QNUploadBlock.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUploadData.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNUploadBlock : NSObject
|
||||
// block下标
|
||||
@property(nonatomic, assign, readonly)NSInteger index;
|
||||
// 当前data偏移量
|
||||
@property(nonatomic, assign, readonly)long long offset;
|
||||
// 块大小
|
||||
@property(nonatomic, assign, readonly)NSInteger size;
|
||||
// 需要上传的片数据
|
||||
@property(nonatomic, strong, readonly)NSArray <QNUploadData *> *uploadDataList;
|
||||
// block上传上下文信息
|
||||
@property(nonatomic, copy, nullable)NSString *context;
|
||||
// block md5
|
||||
@property(nonatomic, copy, nullable)NSString *md5;
|
||||
// 是否已完成上传【不进行离线缓存】
|
||||
@property(nonatomic, assign, readonly)BOOL isCompleted;
|
||||
// 上传大小 【不进行离线缓存】
|
||||
@property(nonatomic, assign, readonly)NSInteger uploadSize;
|
||||
// ctx 过期时间
|
||||
@property(nonatomic, strong, nullable)NSNumber *expiredAt;
|
||||
|
||||
//MARK:-- 构造
|
||||
+ (instancetype)blockFromDictionary:(NSDictionary *)dictionary;
|
||||
- (instancetype)initWithOffset:(long long)offset
|
||||
blockSize:(NSInteger)blockSize
|
||||
dataSize:(NSInteger)dataSize
|
||||
index:(NSInteger)index;
|
||||
|
||||
// 检测 block 是否有效
|
||||
- (BOOL)isValid;
|
||||
|
||||
/// 获取下一个需要上传的块
|
||||
- (QNUploadData *)nextUploadDataWithoutCheckData;
|
||||
|
||||
/// 检测 data 状态,处理出于上传状态的无 data 数据的情况,无 data 数据则状态调整为监测数据状态
|
||||
- (void)checkInfoStateAndUpdate;
|
||||
|
||||
/// 清理上传状态
|
||||
- (void)clearUploadState;
|
||||
|
||||
/// 转化字典
|
||||
- (NSDictionary *)toDictionary;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
175
Pods/Qiniu/QiniuSDK/Storage/QNUploadBlock.m
generated
Normal file
175
Pods/Qiniu/QiniuSDK/Storage/QNUploadBlock.m
generated
Normal file
@@ -0,0 +1,175 @@
|
||||
//
|
||||
// QNUploadBlock.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUploadBlock.h"
|
||||
|
||||
@interface QNUploadBlock()
|
||||
|
||||
@property(nonatomic, assign)long long offset;
|
||||
@property(nonatomic, assign)NSInteger size;
|
||||
@property(nonatomic, assign)NSInteger index;
|
||||
@property(nonatomic, strong)NSArray <QNUploadData *> *uploadDataList;
|
||||
|
||||
@end
|
||||
@implementation QNUploadBlock
|
||||
|
||||
+ (instancetype)blockFromDictionary:(NSDictionary *)dictionary{
|
||||
if (![dictionary isKindOfClass:[NSDictionary class]]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
QNUploadBlock *block = [[QNUploadBlock alloc] init];
|
||||
block.offset = [dictionary[@"offset"] longLongValue];
|
||||
block.size = [dictionary[@"size"] integerValue];
|
||||
block.index = [dictionary[@"index"] integerValue];
|
||||
block.expiredAt = dictionary[@"expired_at"];
|
||||
block.md5 = dictionary[@"md5"];
|
||||
block.context = dictionary[@"context"];
|
||||
|
||||
NSArray *uploadDataInfos = dictionary[@"uploadDataList"];
|
||||
if ([uploadDataInfos isKindOfClass:[NSArray class]]) {
|
||||
|
||||
NSMutableArray *uploadDataList = [NSMutableArray array];
|
||||
for (NSDictionary *uploadDataInfo in uploadDataInfos) {
|
||||
QNUploadData *data = [QNUploadData dataFromDictionary:uploadDataInfo];
|
||||
if (!data) {
|
||||
return nil;
|
||||
}
|
||||
[uploadDataList addObject:data];
|
||||
}
|
||||
block.uploadDataList = [uploadDataList copy];
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
- (instancetype)initWithOffset:(long long)offset
|
||||
blockSize:(NSInteger)blockSize
|
||||
dataSize:(NSInteger)dataSize
|
||||
index:(NSInteger)index {
|
||||
if (self = [super init]) {
|
||||
_offset = offset;
|
||||
_size = blockSize;
|
||||
_index = index;
|
||||
_uploadDataList = [self createDataList:dataSize];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isValid {
|
||||
if (!self.expiredAt || self.expiredAt.integerValue <= 0) {
|
||||
// 不存在时,为新创建 block: 有效
|
||||
return true;
|
||||
}
|
||||
|
||||
// 存在则有效期必须为过期
|
||||
return (self.expiredAt.doubleValue - 12*3600) > [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (BOOL)isCompleted{
|
||||
if (self.uploadDataList == nil) {
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL isCompleted = true;
|
||||
for (QNUploadData *data in self.uploadDataList) {
|
||||
if (data.isUploaded == false) {
|
||||
isCompleted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isCompleted;
|
||||
}
|
||||
|
||||
- (NSInteger)uploadSize {
|
||||
if (self.uploadDataList == nil) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NSInteger uploadSize = 0;
|
||||
for (QNUploadData *data in self.uploadDataList) {
|
||||
uploadSize += data.uploadSize;
|
||||
}
|
||||
return uploadSize;
|
||||
}
|
||||
|
||||
- (NSArray *)createDataList:(long long)dataSize{
|
||||
|
||||
long long offSize = 0;
|
||||
NSInteger dataIndex = 0;
|
||||
NSMutableArray *datas = [NSMutableArray array];
|
||||
while (offSize < self.size) {
|
||||
long long lastSize = self.size - offSize;
|
||||
long long dataSizeP = MIN(lastSize, dataSize);
|
||||
QNUploadData *data = [[QNUploadData alloc] initWithOffset:offSize
|
||||
dataSize:dataSizeP
|
||||
index:dataIndex];
|
||||
[datas addObject:data];
|
||||
offSize += dataSizeP;
|
||||
dataIndex += 1;
|
||||
}
|
||||
return [datas copy];
|
||||
}
|
||||
|
||||
- (QNUploadData *)nextUploadDataWithoutCheckData {
|
||||
if (!self.uploadDataList || self.uploadDataList.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
QNUploadData *data = nil;
|
||||
for (QNUploadData *dataP in self.uploadDataList) {
|
||||
if ([dataP needToUpload]) {
|
||||
data = dataP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
- (void)clearUploadState{
|
||||
self.md5 = nil;
|
||||
self.context = nil;
|
||||
for (QNUploadData *data in self.uploadDataList) {
|
||||
[data clearUploadState];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)checkInfoStateAndUpdate {
|
||||
for (QNUploadData *data in self.uploadDataList) {
|
||||
[data checkStateAndUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *)toDictionary{
|
||||
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
dictionary[@"offset"] = @(self.offset);
|
||||
dictionary[@"size"] = @(self.size);
|
||||
dictionary[@"index"] = @(self.index);
|
||||
dictionary[@"expired_at"] = self.expiredAt ?: @(0);
|
||||
dictionary[@"md5"] = self.md5 ?: @"";
|
||||
if (self.context) {
|
||||
dictionary[@"context"] = self.context;
|
||||
}
|
||||
|
||||
if (self.uploadDataList) {
|
||||
|
||||
NSMutableArray *uploadDataInfos = [NSMutableArray array];
|
||||
for (QNUploadData *data in self.uploadDataList) {
|
||||
|
||||
NSDictionary *uploadDataInfo = [data toDictionary];
|
||||
if (uploadDataInfo) {
|
||||
[uploadDataInfos addObject:uploadDataInfo];
|
||||
}
|
||||
}
|
||||
dictionary[@"uploadDataList"] = [uploadDataInfos copy];
|
||||
}
|
||||
|
||||
return [dictionary copy];
|
||||
}
|
||||
|
||||
@end
|
||||
60
Pods/Qiniu/QiniuSDK/Storage/QNUploadData.h
generated
Normal file
60
Pods/Qiniu/QiniuSDK/Storage/QNUploadData.h
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// QNUploadData.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
typedef NS_ENUM(NSInteger, QNUploadState) {
|
||||
QNUploadStateNeedToCheck, // 需要检测数据
|
||||
QNUploadStateWaitToUpload, // 等待上传
|
||||
QNUploadStateUploading, // 正在上传
|
||||
QNUploadStateComplete, // 上传结束
|
||||
};
|
||||
|
||||
@interface QNUploadData : NSObject
|
||||
|
||||
/// 当前data偏移量
|
||||
@property(nonatomic, assign, readonly)long long offset;
|
||||
/// 当前data大小
|
||||
@property(nonatomic, assign, readonly)long long size;
|
||||
/// data下标
|
||||
@property(nonatomic, assign, readonly)NSInteger index;
|
||||
/// data etag
|
||||
@property(nonatomic, copy, nullable)NSString *etag;
|
||||
/// data md5
|
||||
@property(nonatomic, copy, nullable)NSString *md5;
|
||||
/// 上传状态
|
||||
@property(nonatomic, assign)QNUploadState state;
|
||||
/// 上传进度 【不进行离线缓存】
|
||||
@property(nonatomic, assign)long long uploadSize;
|
||||
/// 上传数据 【不进行离线缓存】
|
||||
@property(nonatomic, strong, nullable)NSData *data;
|
||||
|
||||
//MARK:-- 构造
|
||||
+ (instancetype)dataFromDictionary:(NSDictionary *)dictionary;
|
||||
- (instancetype)initWithOffset:(long long)offset
|
||||
dataSize:(long long)dataSize
|
||||
index:(NSInteger)index;
|
||||
|
||||
//MARK:-- logic
|
||||
/// 是否需要上传
|
||||
- (BOOL)needToUpload;
|
||||
/// 是否已经上传
|
||||
- (BOOL)isUploaded;
|
||||
|
||||
/// 检测 data 状态,处理出于上传状态的无 data 数据的情况,无 data 数据则状态调整为监测数据状态
|
||||
- (void)checkStateAndUpdate;
|
||||
|
||||
/// 转化字典
|
||||
- (NSDictionary *)toDictionary;
|
||||
/// 清除状态
|
||||
- (void)clearUploadState;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
112
Pods/Qiniu/QiniuSDK/Storage/QNUploadData.m
generated
Normal file
112
Pods/Qiniu/QiniuSDK/Storage/QNUploadData.m
generated
Normal file
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// QNUploadData.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUploadData.h"
|
||||
|
||||
@interface QNUploadData()
|
||||
|
||||
@property(nonatomic, assign)long long offset;
|
||||
@property(nonatomic, assign)long long size;
|
||||
@property(nonatomic, assign)NSInteger index;
|
||||
|
||||
@end
|
||||
@implementation QNUploadData
|
||||
|
||||
+ (instancetype)dataFromDictionary:(NSDictionary *)dictionary{
|
||||
if (![dictionary isKindOfClass:[NSDictionary class]]) {
|
||||
return nil;
|
||||
}
|
||||
QNUploadData *data = [[QNUploadData alloc] init];
|
||||
data.offset = [dictionary[@"offset"] longLongValue];
|
||||
data.size = [dictionary[@"size"] longLongValue];
|
||||
data.index = [dictionary[@"index"] integerValue];
|
||||
data.etag = dictionary[@"etag"];
|
||||
data.md5 = dictionary[@"md5"];
|
||||
data.state = [dictionary[@"state"] intValue];
|
||||
return data;
|
||||
}
|
||||
|
||||
- (instancetype)initWithOffset:(long long)offset
|
||||
dataSize:(long long)dataSize
|
||||
index:(NSInteger)index {
|
||||
if (self = [super init]) {
|
||||
_offset = offset;
|
||||
_size = dataSize;
|
||||
_index = index;
|
||||
_etag = @"";
|
||||
_md5 = @"";
|
||||
_state = QNUploadStateNeedToCheck;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)needToUpload {
|
||||
BOOL needToUpload = false;
|
||||
switch (self.state) {
|
||||
case QNUploadStateNeedToCheck:
|
||||
case QNUploadStateWaitToUpload:
|
||||
needToUpload = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return needToUpload;
|
||||
}
|
||||
|
||||
- (BOOL)isUploaded {
|
||||
return self.state == QNUploadStateComplete;
|
||||
}
|
||||
|
||||
- (void)setState:(QNUploadState)state {
|
||||
switch (state) {
|
||||
case QNUploadStateNeedToCheck:
|
||||
case QNUploadStateWaitToUpload:
|
||||
case QNUploadStateUploading:
|
||||
self.uploadSize = 0;
|
||||
self.etag = @"";
|
||||
break;
|
||||
default:
|
||||
self.data = nil;
|
||||
break;
|
||||
}
|
||||
_state = state;
|
||||
}
|
||||
|
||||
- (long long)uploadSize {
|
||||
if (self.state == QNUploadStateComplete) {
|
||||
return _size;
|
||||
} else {
|
||||
return _uploadSize;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearUploadState{
|
||||
self.state = QNUploadStateNeedToCheck;
|
||||
self.etag = nil;
|
||||
self.md5 = nil;
|
||||
}
|
||||
|
||||
- (void)checkStateAndUpdate {
|
||||
if ((self.state == QNUploadStateWaitToUpload || self.state == QNUploadStateUploading) && self.data == nil) {
|
||||
self.state = QNUploadStateNeedToCheck;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *)toDictionary{
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
dictionary[@"offset"] = @(self.offset);
|
||||
dictionary[@"size"] = @(self.size);
|
||||
dictionary[@"index"] = @(self.index);
|
||||
dictionary[@"etag"] = self.etag ?: @"";
|
||||
dictionary[@"md5"] = self.md5 ?: @"";
|
||||
dictionary[@"state"] = @(self.state);
|
||||
return [dictionary copy];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
75
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfo.h
generated
Normal file
75
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfo.h
generated
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// QNUploadInfo.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUploadSource.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNUploadInfo : NSObject
|
||||
|
||||
/// 构造函数
|
||||
/// @param source 上传数据源
|
||||
+ (instancetype)info:(id <QNUploadSource>)source;
|
||||
|
||||
/// 通过字典信息进行配置
|
||||
/// @param dictionary 配置信息
|
||||
- (void)setInfoFromDictionary:(NSDictionary *)dictionary;
|
||||
|
||||
/// 信息转化为字典
|
||||
- (NSDictionary *)toDictionary;
|
||||
|
||||
/// 数据源是否有效,为空则无效
|
||||
- (BOOL)hasValidResource;
|
||||
|
||||
/// 是否有效,数据源是否有效 & 上传信息有效,比如断点续传时,UploadId是否有效
|
||||
- (BOOL)isValid;
|
||||
|
||||
/// 是否可以重新
|
||||
- (BOOL)couldReloadSource;
|
||||
|
||||
/// 重新加载数据
|
||||
- (BOOL)reloadSource;
|
||||
|
||||
/// 数据源ID
|
||||
- (NSString *)getSourceId;
|
||||
|
||||
/// 数据源大小,未知为:-1
|
||||
- (long long)getSourceSize;
|
||||
|
||||
/// 是否为同一个 UploadInfo,
|
||||
/// 同一个:source 相同,上传方式相同
|
||||
/// @param info 上传信息
|
||||
- (BOOL)isSameUploadInfo:(QNUploadInfo *)info;
|
||||
|
||||
/// 已上传大小
|
||||
- (long long)uploadSize;
|
||||
|
||||
/// 资源是否已全部上传
|
||||
/// 子类重写
|
||||
- (BOOL)isAllUploaded;
|
||||
|
||||
/// 清除上传状态信息
|
||||
/// 子类重写
|
||||
- (void)clearUploadState;
|
||||
|
||||
/// 检查文件状态, 主要处理没有 data 但处于上传状态
|
||||
- (void)checkInfoStateAndUpdate;
|
||||
|
||||
/// 读取数据
|
||||
/// @param dataSize 读取数据大小
|
||||
/// @param dataOffset 数据偏移量
|
||||
/// @param error 读取时的错误信息
|
||||
- (NSData *)readData:(NSInteger)dataSize dataOffset:(long long)dataOffset error:(NSError **)error;
|
||||
|
||||
/// 关闭流
|
||||
- (void)close;
|
||||
|
||||
@end
|
||||
|
||||
#define kQNUploadInfoTypeKey @"infoType"
|
||||
NS_ASSUME_NONNULL_END
|
||||
115
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfo.m
generated
Normal file
115
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfo.m
generated
Normal file
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// QNUploadInfo.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNErrorCode.h"
|
||||
#import "QNUploadInfo.h"
|
||||
|
||||
@interface QNUploadInfo()
|
||||
|
||||
@property(nonatomic, copy)NSString *sourceId;
|
||||
@property(nonatomic, assign)long long sourceSize;
|
||||
@property(nonatomic, copy)NSString *fileName;
|
||||
|
||||
@property(nonatomic, strong)id <QNUploadSource> source;
|
||||
|
||||
@end
|
||||
@implementation QNUploadInfo
|
||||
|
||||
+ (instancetype)info:(id <QNUploadSource>)source {
|
||||
QNUploadInfo *info = [[self alloc] init];
|
||||
info.source = source;
|
||||
info.sourceSize = [source getSize];
|
||||
info.fileName = [source getFileName];
|
||||
return info;
|
||||
}
|
||||
|
||||
- (void)setInfoFromDictionary:(NSDictionary *)dictionary {
|
||||
self.sourceSize = [dictionary[@"sourceSize"] longValue];
|
||||
self.sourceId = dictionary[@"sourceId"];
|
||||
}
|
||||
|
||||
- (NSDictionary *)toDictionary {
|
||||
return @{@"sourceSize" : @([self getSourceSize]),
|
||||
@"sourceId" : self.sourceId ?: @""};
|
||||
}
|
||||
|
||||
- (BOOL)hasValidResource {
|
||||
return self.source != nil;
|
||||
}
|
||||
|
||||
- (BOOL)isValid {
|
||||
return [self hasValidResource];
|
||||
}
|
||||
|
||||
- (BOOL)couldReloadSource {
|
||||
return [self.source couldReloadSource];
|
||||
}
|
||||
|
||||
- (BOOL)reloadSource {
|
||||
return [self.source reloadSource];
|
||||
}
|
||||
|
||||
- (NSString *)getSourceId {
|
||||
return [self.source getId];
|
||||
}
|
||||
|
||||
- (long long)getSourceSize {
|
||||
return [self.source getSize];
|
||||
}
|
||||
|
||||
- (BOOL)isSameUploadInfo:(QNUploadInfo *)info {
|
||||
if (info == nil || ((self.sourceId.length > 0 || info.sourceId.length > 0) && ![self.sourceId isEqualToString:info.sourceId])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检测文件大小,如果能获取到文件大小的话,就进行检测
|
||||
if (info.sourceSize > kQNUnknownSourceSize &&
|
||||
self.sourceSize > kQNUnknownSourceSize &&
|
||||
info.sourceSize != self.sourceSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
- (long long)uploadSize {
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (BOOL)isAllUploaded {
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)clearUploadState {
|
||||
}
|
||||
|
||||
- (void)checkInfoStateAndUpdate {
|
||||
}
|
||||
|
||||
- (NSData *)readData:(NSInteger)dataSize dataOffset:(long long)dataOffset error:(NSError **)error {
|
||||
if (!self.source) {
|
||||
*error = [NSError errorWithDomain:NSStreamSOCKSErrorDomain code:kQNLocalIOError userInfo:@{NSLocalizedDescriptionKey : @"file is not exist"}];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *data = nil;
|
||||
@synchronized (self.source) {
|
||||
data = [self.source readData:dataSize dataOffset:dataOffset error:error];
|
||||
}
|
||||
if (*error == nil && data != nil && (data.length == 0 || data.length != dataSize)) {
|
||||
self.sourceSize = data.length + dataOffset;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
- (void)close {
|
||||
[self.source close];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
35
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV1.h
generated
Normal file
35
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV1.h
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// QNUploadInfoV1.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNUploadData.h"
|
||||
#import "QNUploadBlock.h"
|
||||
#import "QNUploadInfo.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNUploadInfoV1 : QNUploadInfo
|
||||
|
||||
+ (instancetype)info:(id <QNUploadSource>)source
|
||||
configuration:(QNConfiguration *)configuration;
|
||||
|
||||
|
||||
+ (instancetype)info:(id <QNUploadSource>)source
|
||||
dictionary:(NSDictionary *)dictionary;
|
||||
|
||||
- (BOOL)isFirstData:(QNUploadData *)data;
|
||||
|
||||
- (QNUploadBlock *)nextUploadBlock:(NSError **)error;
|
||||
|
||||
- (QNUploadData *)nextUploadData:(QNUploadBlock *)block;
|
||||
|
||||
- (NSArray <NSString *> *)allBlocksContexts;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
327
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV1.m
generated
Normal file
327
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV1.m
generated
Normal file
@@ -0,0 +1,327 @@
|
||||
//
|
||||
// QNUploadInfoV1.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSData+QNMD5.h"
|
||||
#import "QNMutableArray.h"
|
||||
#import "QNUploadInfoV1.h"
|
||||
|
||||
#define kTypeValue @"UploadInfoV1"
|
||||
#define kBlockSize (4 * 1024 * 1024)
|
||||
|
||||
@interface QNUploadInfoV1()
|
||||
|
||||
@property(nonatomic, assign)int dataSize;
|
||||
@property(nonatomic, strong)QNMutableArray *blockList;
|
||||
|
||||
@property(nonatomic, assign)BOOL isEOF;
|
||||
@property(nonatomic, strong, nullable)NSError *readError;
|
||||
@end
|
||||
@implementation QNUploadInfoV1
|
||||
|
||||
+ (instancetype)info:(id<QNUploadSource>)source
|
||||
configuration:(nonnull QNConfiguration *)configuration {
|
||||
|
||||
QNUploadInfoV1 *info = [QNUploadInfoV1 info:source];
|
||||
if (configuration.useConcurrentResumeUpload || configuration.chunkSize > kBlockSize) {
|
||||
info.dataSize = kBlockSize;
|
||||
} else {
|
||||
info.dataSize = configuration.chunkSize;
|
||||
}
|
||||
info.blockList = [QNMutableArray array];
|
||||
return info;
|
||||
}
|
||||
|
||||
+ (instancetype)info:(id <QNUploadSource>)source
|
||||
dictionary:(NSDictionary *)dictionary {
|
||||
if (dictionary == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
int dataSize = [dictionary[@"dataSize"] intValue];
|
||||
NSString *type = dictionary[kQNUploadInfoTypeKey];
|
||||
NSArray *blockInfoList = dictionary[@"blockList"];
|
||||
|
||||
QNMutableArray *blockList = [QNMutableArray array];
|
||||
if ([blockInfoList isKindOfClass:[NSArray class]]) {
|
||||
for (int i = 0; i < blockInfoList.count; i++) {
|
||||
NSDictionary *blockInfo = blockInfoList[i];
|
||||
if ([blockInfo isKindOfClass:[NSDictionary class]]) {
|
||||
QNUploadBlock *block = [QNUploadBlock blockFromDictionary:blockInfo];
|
||||
if (block == nil) {
|
||||
return nil;
|
||||
}
|
||||
[blockList addObject:block];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QNUploadInfoV1 *info = [QNUploadInfoV1 info:source];
|
||||
[info setInfoFromDictionary:dictionary];
|
||||
info.dataSize = dataSize;
|
||||
info.blockList = blockList;
|
||||
|
||||
if (![type isEqualToString:kTypeValue] || ![[source getId] isEqualToString:[info getSourceId]]) {
|
||||
return nil;
|
||||
} else {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isFirstData:(QNUploadData *)data {
|
||||
return data.index == 0;
|
||||
}
|
||||
|
||||
- (BOOL)isValid {
|
||||
if (![super isValid]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
__block BOOL valid = true;
|
||||
[self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
valid = [block isValid];
|
||||
if (!valid) {
|
||||
*stop = true;
|
||||
}
|
||||
}];
|
||||
return valid;
|
||||
}
|
||||
|
||||
- (BOOL)reloadSource {
|
||||
self.isEOF = false;
|
||||
self.readError = nil;
|
||||
return [super reloadSource];
|
||||
}
|
||||
|
||||
- (BOOL)isSameUploadInfo:(QNUploadInfo *)info {
|
||||
if (![super isSameUploadInfo:info]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (![info isKindOfClass:[QNUploadInfoV1 class]]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return self.dataSize == [(QNUploadInfoV1 *)info dataSize];
|
||||
}
|
||||
|
||||
- (void)clearUploadState {
|
||||
if (self.blockList == nil || self.blockList.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[block clearUploadState];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)checkInfoStateAndUpdate {
|
||||
[self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[block checkInfoStateAndUpdate];
|
||||
}];
|
||||
}
|
||||
|
||||
- (long long)uploadSize {
|
||||
if (self.blockList == nil || self.blockList.count == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
__block long long uploadSize = 0;
|
||||
[self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
uploadSize += [block uploadSize];
|
||||
}];
|
||||
return uploadSize;
|
||||
}
|
||||
|
||||
- (BOOL)isAllUploaded {
|
||||
if (!_isEOF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self.blockList == nil || self.blockList.count == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
__block BOOL isAllUploaded = true;
|
||||
[self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if (!block.isCompleted) {
|
||||
isAllUploaded = false;
|
||||
*stop = true;
|
||||
}
|
||||
}];
|
||||
return isAllUploaded;
|
||||
}
|
||||
|
||||
- (NSDictionary *)toDictionary {
|
||||
NSMutableDictionary *dictionary = [[super toDictionary] mutableCopy];
|
||||
if (dictionary == nil) {
|
||||
dictionary = [NSMutableDictionary dictionary];
|
||||
}
|
||||
[dictionary setObject:kTypeValue forKey:kQNUploadInfoTypeKey];
|
||||
[dictionary setObject:@(self.dataSize) forKey:@"dataSize"];
|
||||
|
||||
if (self.blockList != nil && self.blockList.count != 0) {
|
||||
NSMutableArray *blockInfoList = [NSMutableArray array];
|
||||
[self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[blockInfoList addObject:[block toDictionary]];
|
||||
}];
|
||||
[dictionary setObject:[blockInfoList copy] forKey:@"blockList"];
|
||||
}
|
||||
|
||||
return [dictionary copy];
|
||||
}
|
||||
|
||||
- (QNUploadBlock *)nextUploadBlock:(NSError **)error {
|
||||
// 从 blockList 中读取需要上传的 block
|
||||
QNUploadBlock *block = [self nextUploadBlockFormBlockList];
|
||||
|
||||
// 内存的 blockList 中没有可上传的数据,则从资源中读并创建 block
|
||||
if (block == nil) {
|
||||
if (self.isEOF) {
|
||||
return nil;
|
||||
} else if (self.readError) {
|
||||
*error = self.readError;
|
||||
return nil;
|
||||
}
|
||||
|
||||
// 从资源中读取新的 block 进行上传
|
||||
long long blockOffset = 0;
|
||||
if (self.blockList.count > 0) {
|
||||
QNUploadBlock *lastBlock = self.blockList[self.blockList.count - 1];
|
||||
blockOffset = lastBlock.offset + (long long)(lastBlock.size);
|
||||
}
|
||||
|
||||
block = [[QNUploadBlock alloc] initWithOffset:blockOffset blockSize:kBlockSize dataSize:self.dataSize index:self.blockList.count];
|
||||
}
|
||||
|
||||
QNUploadBlock *loadBlock = [self loadBlockData:block error:error];
|
||||
if (*error != nil) {
|
||||
self.readError = *error;
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (loadBlock == nil) {
|
||||
// 没有加在到 block, 也即数据源读取结束
|
||||
self.isEOF = true;
|
||||
// 有多余的 block 则移除,移除中包含 block
|
||||
if (self.blockList.count > block.index) {
|
||||
self.blockList = [[self.blockList subarrayWithRange:NSMakeRange(0, block.index)] mutableCopy];
|
||||
}
|
||||
} else {
|
||||
// 加在到 block
|
||||
if (loadBlock.index == self.blockList.count) {
|
||||
// 新块:block index 等于 blockList size 则为新创建 block,需要加入 blockList
|
||||
[self.blockList addObject:loadBlock];
|
||||
} else if (loadBlock != block) {
|
||||
// 更换块:重新加在了 block, 更换信息
|
||||
[self.blockList replaceObjectAtIndex:loadBlock.index withObject:loadBlock];
|
||||
}
|
||||
|
||||
// 数据源读取结束,块读取大小小于预期,读取结束
|
||||
if (loadBlock.size < kBlockSize) {
|
||||
self.isEOF = true;
|
||||
// 有多余的 block 则移除,移除中不包含 block
|
||||
if (self.blockList.count > block.index + 1) {
|
||||
self.blockList = [[self.blockList subarrayWithRange:NSMakeRange(0, block.index + 1)] mutableCopy];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loadBlock;
|
||||
}
|
||||
|
||||
- (QNUploadBlock *)nextUploadBlockFormBlockList {
|
||||
if (self.blockList == nil || self.blockList.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block QNUploadBlock *block = nil;
|
||||
[self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *blockP, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
QNUploadData *data = [blockP nextUploadDataWithoutCheckData];
|
||||
if (data != nil) {
|
||||
block = blockP;
|
||||
*stop = true;
|
||||
}
|
||||
}];
|
||||
return block;
|
||||
}
|
||||
|
||||
// 加载块中的数据
|
||||
// 1. 数据块已加载,直接返回
|
||||
// 2. 数据块未加载,读块数据
|
||||
// 2.1 如果未读到数据,则已 EOF,返回 null
|
||||
// 2.2 如果读到数据
|
||||
// 2.2.1 如果块数据符合预期,则当片未上传,则加载片数据
|
||||
// 2.2.2 如果块数据不符合预期,创建新块,加载片信息
|
||||
- (QNUploadBlock *)loadBlockData:(QNUploadBlock *)block error:(NSError **)error {
|
||||
if (block == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// 已经加载过 block 数据
|
||||
// 没有需要上传的片 或者 有需要上传片但是已加载过片数据
|
||||
QNUploadData *nextUploadData = [block nextUploadDataWithoutCheckData];
|
||||
if (nextUploadData.state == QNUploadStateWaitToUpload && nextUploadData.data != nil) {
|
||||
return block;
|
||||
}
|
||||
|
||||
// 未加载过 block 数据
|
||||
// 根据 block 信息加载 blockBytes
|
||||
NSData *blockBytes = nil;
|
||||
blockBytes = [self readData:block.size dataOffset:block.offset error:error];
|
||||
if (*error != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// 没有数据不需要上传
|
||||
if (blockBytes == nil || blockBytes.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *md5 = [blockBytes qn_md5];
|
||||
// 判断当前 block 的数据是否和实际数据吻合,不吻合则之前 block 被抛弃,重新创建 block
|
||||
if (blockBytes.length != block.size || block.md5 == nil || ![block.md5 isEqualToString:md5]) {
|
||||
block = [[QNUploadBlock alloc] initWithOffset:block.offset blockSize:blockBytes.length dataSize:self.dataSize index:block.index];
|
||||
block.md5 = md5;
|
||||
}
|
||||
|
||||
for (QNUploadData *data in block.uploadDataList) {
|
||||
if (data.state != QNUploadStateComplete) {
|
||||
// 还未上传的
|
||||
data.data = [blockBytes subdataWithRange:NSMakeRange((NSUInteger)data.offset, (NSUInteger)data.size)];
|
||||
data.state = QNUploadStateWaitToUpload;
|
||||
} else {
|
||||
// 已经上传的
|
||||
data.state = QNUploadStateComplete;
|
||||
}
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
- (QNUploadData *)nextUploadData:(QNUploadBlock *)block {
|
||||
if (block == nil) {
|
||||
return nil;
|
||||
}
|
||||
return [block nextUploadDataWithoutCheckData];
|
||||
}
|
||||
|
||||
- (NSArray <NSString *> *)allBlocksContexts {
|
||||
if (self.blockList == nil || self.blockList.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray *contexts = [NSMutableArray array];
|
||||
[self.blockList enumerateObjectsUsingBlock:^(QNUploadBlock *block, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if (block.context && block.context.length > 0) {
|
||||
[contexts addObject:block.context];
|
||||
}
|
||||
}];
|
||||
return [contexts copy];
|
||||
}
|
||||
|
||||
@end
|
||||
35
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV2.h
generated
Normal file
35
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV2.h
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// QNUploadInfoV2.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/13.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNUploadData.h"
|
||||
#import "QNUploadInfo.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNUploadInfoV2 : QNUploadInfo
|
||||
|
||||
@property(nonatomic, copy, nullable)NSString *uploadId;
|
||||
@property(nonatomic, strong, nullable)NSNumber *expireAt;
|
||||
|
||||
+ (instancetype)info:(id <QNUploadSource>)source
|
||||
configuration:(QNConfiguration *)configuration;
|
||||
|
||||
|
||||
+ (instancetype)info:(id <QNUploadSource>)source
|
||||
dictionary:(NSDictionary *)dictionary;
|
||||
|
||||
- (QNUploadData *)nextUploadData:(NSError **)error;
|
||||
|
||||
- (NSInteger)getPartIndexOfData:(QNUploadData *)data;
|
||||
|
||||
- (NSArray <NSDictionary <NSString *, NSObject *> *> *)getPartInfoArray;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
322
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV2.m
generated
Normal file
322
Pods/Qiniu/QiniuSDK/Storage/QNUploadInfoV2.m
generated
Normal file
@@ -0,0 +1,322 @@
|
||||
//
|
||||
// QNUploadInfoV2.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/13.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSData+QNMD5.h"
|
||||
#import "QNMutableArray.h"
|
||||
#import "QNUploadInfoV2.h"
|
||||
|
||||
#define kTypeValue @"UploadInfoV2"
|
||||
#define kMaxDataSize (1024 * 1024 * 1024)
|
||||
|
||||
@interface QNUploadInfoV2()
|
||||
|
||||
@property(nonatomic, assign)int dataSize;
|
||||
@property(nonatomic, strong)QNMutableArray *dataList;
|
||||
|
||||
@property(nonatomic, assign)BOOL isEOF;
|
||||
@property(nonatomic, strong, nullable)NSError *readError;
|
||||
@end
|
||||
@implementation QNUploadInfoV2
|
||||
|
||||
+ (instancetype)info:(id<QNUploadSource>)source
|
||||
configuration:(nonnull QNConfiguration *)configuration {
|
||||
|
||||
QNUploadInfoV2 *info = [QNUploadInfoV2 info:source];
|
||||
info.dataSize = MIN(configuration.chunkSize, kMaxDataSize);
|
||||
info.dataList = [QNMutableArray array];
|
||||
return info;
|
||||
}
|
||||
|
||||
+ (instancetype)info:(id <QNUploadSource>)source
|
||||
dictionary:(NSDictionary *)dictionary {
|
||||
if (dictionary == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
int dataSize = [dictionary[@"dataSize"] intValue];
|
||||
NSNumber *expireAt = dictionary[@"expireAt"];
|
||||
NSString *uploadId = dictionary[@"uploadId"];
|
||||
NSString *type = dictionary[kQNUploadInfoTypeKey];
|
||||
if (expireAt == nil || ![expireAt isKindOfClass:[NSNumber class]] ||
|
||||
uploadId == nil || ![uploadId isKindOfClass:[NSString class]] || uploadId.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *dataInfoList = dictionary[@"dataList"];
|
||||
|
||||
QNMutableArray *dataList = [QNMutableArray array];
|
||||
if ([dataInfoList isKindOfClass:[NSArray class]]) {
|
||||
for (int i = 0; i < dataInfoList.count; i++) {
|
||||
NSDictionary *dataInfo = dataInfoList[i];
|
||||
if ([dataInfo isKindOfClass:[NSDictionary class]]) {
|
||||
QNUploadData *data = [QNUploadData dataFromDictionary:dataInfo];
|
||||
if (data == nil) {
|
||||
return nil;
|
||||
}
|
||||
[dataList addObject:data];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QNUploadInfoV2 *info = [QNUploadInfoV2 info:source];
|
||||
[info setInfoFromDictionary:dictionary];
|
||||
info.expireAt = expireAt;
|
||||
info.uploadId = uploadId;
|
||||
info.dataSize = dataSize;
|
||||
info.dataList = dataList;
|
||||
|
||||
if (![type isEqualToString:kTypeValue] || ![[source getId] isEqualToString:[info getSourceId]]) {
|
||||
return nil;
|
||||
} else {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isValid {
|
||||
if (![super isValid]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!self.expireAt || !self.uploadId || self.uploadId.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (self.expireAt.doubleValue - 2*3600) > [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (BOOL)reloadSource {
|
||||
self.isEOF = false;
|
||||
self.readError = nil;
|
||||
return [super reloadSource];
|
||||
}
|
||||
|
||||
- (BOOL)isSameUploadInfo:(QNUploadInfo *)info {
|
||||
if (![super isSameUploadInfo:info]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (![info isKindOfClass:[QNUploadInfoV2 class]]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return self.dataSize == [(QNUploadInfoV2 *)info dataSize];
|
||||
}
|
||||
|
||||
- (void)clearUploadState {
|
||||
self.expireAt = nil;
|
||||
self.uploadId = nil;
|
||||
if (self.dataList == nil || self.dataList.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[data clearUploadState];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)checkInfoStateAndUpdate {
|
||||
[self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[data checkStateAndUpdate];
|
||||
}];
|
||||
}
|
||||
|
||||
- (long long)uploadSize {
|
||||
if (self.dataList == nil || self.dataList.count == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
__block long long uploadSize = 0;
|
||||
[self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
uploadSize += [data uploadSize];
|
||||
}];
|
||||
return uploadSize;
|
||||
}
|
||||
|
||||
- (BOOL)isAllUploaded {
|
||||
if (!_isEOF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self.dataList == nil || self.dataList.count == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
__block BOOL isAllUploaded = true;
|
||||
[self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if (!data.isUploaded) {
|
||||
isAllUploaded = false;
|
||||
*stop = true;
|
||||
}
|
||||
}];
|
||||
return isAllUploaded;
|
||||
}
|
||||
|
||||
- (NSDictionary *)toDictionary {
|
||||
NSMutableDictionary *dictionary = [[super toDictionary] mutableCopy];
|
||||
if (dictionary == nil) {
|
||||
dictionary = [NSMutableDictionary dictionary];
|
||||
}
|
||||
[dictionary setObject:kTypeValue forKey:kQNUploadInfoTypeKey];
|
||||
[dictionary setObject:@(self.dataSize) forKey:@"dataSize"];
|
||||
[dictionary setObject:self.expireAt ?: 0 forKey:@"expireAt"];
|
||||
[dictionary setObject:self.uploadId ?: @"" forKey:@"uploadId"];
|
||||
|
||||
if (self.dataList != nil && self.dataList.count != 0) {
|
||||
NSMutableArray *blockInfoList = [NSMutableArray array];
|
||||
[self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[blockInfoList addObject:[data toDictionary]];
|
||||
}];
|
||||
[dictionary setObject:[blockInfoList copy] forKey:@"dataList"];
|
||||
}
|
||||
|
||||
return [dictionary copy];
|
||||
}
|
||||
|
||||
- (NSInteger)getPartIndexOfData:(QNUploadData *)data {
|
||||
return data.index + 1;
|
||||
}
|
||||
|
||||
- (QNUploadData *)nextUploadData:(NSError **)error {
|
||||
|
||||
// 从 dataList 中读取需要上传的 data
|
||||
QNUploadData *data = [self nextUploadDataFormDataList];
|
||||
|
||||
// 内存的 dataList 中没有可上传的数据,则从资源中读并创建 data
|
||||
if (data == nil) {
|
||||
if (self.isEOF) {
|
||||
return nil;
|
||||
} else if (self.readError) {
|
||||
*error = self.readError;
|
||||
return nil;
|
||||
}
|
||||
|
||||
// 从资源中读取新的 block 进行上传
|
||||
long long dataOffset = 0;
|
||||
if (self.dataList.count > 0) {
|
||||
QNUploadData *lastData = self.dataList[self.dataList.count - 1];
|
||||
dataOffset = lastData.offset + lastData.size;
|
||||
}
|
||||
|
||||
data = [[QNUploadData alloc] initWithOffset:dataOffset dataSize:self.dataSize index:self.dataList.count];
|
||||
}
|
||||
|
||||
QNUploadData*loadData = [self loadData:data error:error];
|
||||
if (*error != nil) {
|
||||
self.readError = *error;
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (loadData == nil) {
|
||||
// 没有加在到 data, 也即数据源读取结束
|
||||
self.isEOF = true;
|
||||
// 有多余的 data 则移除,移除中包含 data
|
||||
if (self.dataList.count > data.index) {
|
||||
self.dataList = [[self.dataList subarrayWithRange:NSMakeRange(0, data.index)] mutableCopy];
|
||||
}
|
||||
} else {
|
||||
// 加在到 data
|
||||
if (loadData.index == self.dataList.count) {
|
||||
// 新块:data index 等于 dataList size 则为新创建 block,需要加入 dataList
|
||||
[self.dataList addObject:loadData];
|
||||
} else if (loadData != data) {
|
||||
// 更换块:重新加在了 data, 更换信息
|
||||
[self.dataList replaceObjectAtIndex:loadData.index withObject:loadData];
|
||||
}
|
||||
|
||||
// 数据源读取结束,块读取大小小于预期,读取结束
|
||||
if (loadData.size < data.size) {
|
||||
self.isEOF = true;
|
||||
// 有多余的 data 则移除,移除中不包含 data
|
||||
if (self.dataList.count > data.index + 1) {
|
||||
self.dataList = [[self.dataList subarrayWithRange:NSMakeRange(0, data.index + 1)] mutableCopy];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loadData;
|
||||
}
|
||||
|
||||
- (QNUploadData *)nextUploadDataFormDataList {
|
||||
if (self.dataList == nil || self.dataList.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block QNUploadData *data = nil;
|
||||
[self.dataList enumerateObjectsUsingBlock:^(QNUploadData *dataP, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if ([dataP needToUpload]) {
|
||||
data = dataP;
|
||||
*stop = true;
|
||||
}
|
||||
}];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// 加载块中的数据
|
||||
// 1. 数据块已加载,直接返回
|
||||
// 2. 数据块未加载,读块数据
|
||||
// 2.1 如果未读到数据,则已 EOF,返回 null
|
||||
// 2.2 如果读到数据
|
||||
// 2.2.1 如果块数据符合预期,则当片未上传,则加载片数据
|
||||
// 2.2.2 如果块数据不符合预期,创建新块,加载片信息
|
||||
- (QNUploadData *)loadData:(QNUploadData *)data error:(NSError **)error {
|
||||
if (data == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// 之前已加载并验证过数据,不必在验证
|
||||
if (data.data != nil) {
|
||||
return data;
|
||||
}
|
||||
|
||||
// 未加载过 block 数据
|
||||
// 根据 data 信息加载 dataBytes
|
||||
NSData *dataBytes = [self readData:(NSInteger)data.size dataOffset:data.offset error:error];
|
||||
if (*error != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// 没有数据不需要上传
|
||||
if (dataBytes == nil || dataBytes.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *md5 = [dataBytes qn_md5];
|
||||
// 判断当前 block 的数据是否和实际数据吻合,不吻合则之前 block 被抛弃,重新创建 block
|
||||
if (dataBytes.length != data.size || data.md5 == nil || ![data.md5 isEqualToString:md5]) {
|
||||
data = [[QNUploadData alloc] initWithOffset:data.offset dataSize:dataBytes.length index:data.index];
|
||||
data.md5 = md5;
|
||||
}
|
||||
|
||||
if (data.etag == nil || data.etag.length == 0) {
|
||||
data.data = dataBytes;
|
||||
data.state = QNUploadStateWaitToUpload;
|
||||
} else {
|
||||
data.state = QNUploadStateComplete;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSArray <NSDictionary <NSString *, NSObject *> *> *)getPartInfoArray {
|
||||
if (self.uploadId == nil || self.uploadId.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray *infoArray = [NSMutableArray array];
|
||||
[self.dataList enumerateObjectsUsingBlock:^(QNUploadData *data, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if (data.state == QNUploadStateComplete && data.etag != nil) {
|
||||
[infoArray addObject:@{@"etag" : data.etag,
|
||||
@"partNumber" : @([self getPartIndexOfData:data])}];
|
||||
}
|
||||
}];
|
||||
|
||||
return [infoArray copy];
|
||||
}
|
||||
|
||||
@end
|
||||
182
Pods/Qiniu/QiniuSDK/Storage/QNUploadManager.h
generated
Executable file
182
Pods/Qiniu/QiniuSDK/Storage/QNUploadManager.h
generated
Executable file
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// QNUploader.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14-9-28.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "QNRecorderDelegate.h"
|
||||
|
||||
@class QNResponseInfo;
|
||||
@class QNUploadOption;
|
||||
@class QNConfiguration;
|
||||
@class PHAsset;
|
||||
@class PHAssetResource;
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
@class ALAsset;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 上传完成后的回调函数
|
||||
*
|
||||
* @param info 上下文信息,包括状态码,错误值
|
||||
* @param key 上传时指定的key,原样返回
|
||||
* @param resp 上传成功会返回文件信息,失败为nil; 可以通过此值是否为nil 判断上传结果
|
||||
*/
|
||||
typedef void (^QNUpCompletionHandler)(QNResponseInfo *info, NSString *key, NSDictionary *resp);
|
||||
|
||||
/**
|
||||
管理上传的类,可以生成一次,持续使用,不必反复创建。
|
||||
*/
|
||||
@interface QNUploadManager : NSObject
|
||||
|
||||
/**
|
||||
* 默认构造方法,没有持久化记录
|
||||
*
|
||||
* @return 上传管理类实例
|
||||
*/
|
||||
- (instancetype)init;
|
||||
|
||||
/**
|
||||
* 使用一个持久化的记录接口进行记录的构造方法
|
||||
*
|
||||
* @param recorder 持久化记录接口实现
|
||||
*
|
||||
* @return 上传管理类实例
|
||||
*/
|
||||
- (instancetype)initWithRecorder:(id<QNRecorderDelegate>)recorder;
|
||||
|
||||
/**
|
||||
* 使用持久化记录接口以及持久化key生成函数的构造方法,默认情况下使用上传存储的key, 如果key为nil或者有特殊字符比如/,建议使用自己的生成函数
|
||||
*
|
||||
* @param recorder 持久化记录接口实现
|
||||
* @param recorderKeyGenerator 持久化记录key生成函数
|
||||
*
|
||||
* @return 上传管理类实例
|
||||
*/
|
||||
- (instancetype)initWithRecorder:(id<QNRecorderDelegate>)recorder
|
||||
recorderKeyGenerator:(QNRecorderKeyGenerator)recorderKeyGenerator;
|
||||
|
||||
/**
|
||||
* 使用配置信息生成上传实例
|
||||
*
|
||||
* @param config 配置信息
|
||||
*
|
||||
* @return 上传管理类实例
|
||||
*/
|
||||
- (instancetype)initWithConfiguration:(QNConfiguration *)config;
|
||||
|
||||
/**
|
||||
* 方便使用的单例方法
|
||||
*
|
||||
* @param config 配置信息
|
||||
*
|
||||
* @return 上传管理类实例
|
||||
*/
|
||||
+ (instancetype)sharedInstanceWithConfiguration:(QNConfiguration *)config;
|
||||
|
||||
/**
|
||||
* 直接上传数据
|
||||
*
|
||||
* @param data 待上传的数据
|
||||
* @param key 上传到云存储的key,为nil时表示是由七牛生成
|
||||
* @param token 上传需要的token, 由服务器生成
|
||||
* @param completionHandler 上传完成后的回调函数
|
||||
* @param option 上传时传入的可选参数
|
||||
*/
|
||||
- (void)putData:(NSData *)data
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option;
|
||||
|
||||
|
||||
/**
|
||||
* 上传数据流
|
||||
*
|
||||
* @param inputStream 数据流
|
||||
* @param sourceId 数据 id; 用于断点续传的标识
|
||||
* @param size 流大小,主要用来计算上传进度,不能预知大小传 -1
|
||||
* @param fileName 文件名
|
||||
* @param key 上传到云存储的key,为nil时表示是由七牛生成
|
||||
* @param token 上传需要的token, 由服务器生成
|
||||
* @param completionHandler 上传完成后的回调函数
|
||||
* @param option 上传时传入的可选参数
|
||||
*/
|
||||
- (void)putInputStream:(NSInputStream *)inputStream
|
||||
sourceId:(NSString *)sourceId
|
||||
size:(long long)size
|
||||
fileName:(NSString *)fileName
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option;
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param key 上传到云存储的key,为nil时表示是由七牛生成
|
||||
* @param token 上传需要的token, 由服务器生成
|
||||
* @param completionHandler 上传完成后的回调函数
|
||||
* @param option 上传时传入的可选参数
|
||||
*/
|
||||
- (void)putFile:(NSString *)filePath
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option;
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
/**
|
||||
* 上传ALAsset文件
|
||||
*
|
||||
* @param asset ALAsset文件
|
||||
* @param key 上传到云存储的key,为nil时表示是由七牛生成
|
||||
* @param token 上传需要的token, 由服务器生成
|
||||
* @param completionHandler 上传完成后的回调函数
|
||||
* @param option 上传时传入的可选参数
|
||||
*/
|
||||
- (void)putALAsset:(ALAsset *)asset
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option API_DEPRECATED("use putPHAsset instead", ios(4.0, 9.0)) API_UNAVAILABLE(macos, tvos);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 上传PHAsset文件(IOS8 andLater)
|
||||
*
|
||||
* @param asset PHAsset文件
|
||||
* @param key 上传到云存储的key,为nil时表示是由七牛生成
|
||||
* @param token 上传需要的token, 由服务器生成
|
||||
* @param completionHandler 上传完成后的回调函数
|
||||
* @param option 上传时传入的可选参数
|
||||
*/
|
||||
- (void)putPHAsset:(PHAsset *)asset
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option API_AVAILABLE(ios(9.1)) API_UNAVAILABLE(macos, tvos);
|
||||
|
||||
/**
|
||||
* 上传PHAssetResource文件(IOS9.1 andLater)
|
||||
*
|
||||
* @param assetResource PHAssetResource文件
|
||||
* @param key 上传到云存储的key,为nil时表示是由七牛生成
|
||||
* @param token 上传需要的token, 由服务器生成
|
||||
* @param completionHandler 上传完成后的回调函数
|
||||
* @param option 上传时传入的可选参数
|
||||
*/
|
||||
|
||||
- (void)putPHAssetResource:(PHAssetResource *)assetResource
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option API_AVAILABLE(ios(9)) API_UNAVAILABLE(macos, tvos);
|
||||
|
||||
@end
|
||||
505
Pods/Qiniu/QiniuSDK/Storage/QNUploadManager.m
generated
Normal file
505
Pods/Qiniu/QiniuSDK/Storage/QNUploadManager.m
generated
Normal file
@@ -0,0 +1,505 @@
|
||||
//
|
||||
// QNUploader.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14-9-28.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
#import <AssetsLibrary/AssetsLibrary.h>
|
||||
#import "QNALAssetFile.h"
|
||||
#endif
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
|
||||
#import "QNPHAssetFile.h"
|
||||
#import <Photos/Photos.h>
|
||||
#endif
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
|
||||
#import "QNPHAssetResource.h"
|
||||
#endif
|
||||
|
||||
#else
|
||||
#import <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
#import "QNUploadManager.h"
|
||||
|
||||
#import "QNAsyncRun.h"
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNCrc32.h"
|
||||
#import "QNFile.h"
|
||||
#import "QNUtils.h"
|
||||
#import "QNResponseInfo.h"
|
||||
|
||||
#import "QNFormUpload.h"
|
||||
#import "QNPartsUpload.h"
|
||||
#import "QNConcurrentResumeUpload.h"
|
||||
|
||||
#import "QNUpToken.h"
|
||||
#import "QNUploadOption.h"
|
||||
#import "QNReportItem.h"
|
||||
|
||||
#import "QNServerConfigMonitor.h"
|
||||
#import "QNDnsPrefetch.h"
|
||||
#import "QNZone.h"
|
||||
|
||||
#import "QNUploadSourceFile.h"
|
||||
#import "QNUploadSourceStream.h"
|
||||
|
||||
@interface QNUploadManager ()
|
||||
@property (nonatomic) QNConfiguration *config;
|
||||
@end
|
||||
|
||||
@implementation QNUploadManager
|
||||
|
||||
- (instancetype)init {
|
||||
return [self initWithConfiguration:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithRecorder:(id<QNRecorderDelegate>)recorder {
|
||||
return [self initWithRecorder:recorder recorderKeyGenerator:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithRecorder:(id<QNRecorderDelegate>)recorder
|
||||
recorderKeyGenerator:(QNRecorderKeyGenerator)recorderKeyGenerator {
|
||||
QNConfiguration *config = [QNConfiguration build:^(QNConfigurationBuilder *builder) {
|
||||
builder.recorder = recorder;
|
||||
builder.recorderKeyGen = recorderKeyGenerator;
|
||||
}];
|
||||
return [self initWithConfiguration:config];
|
||||
}
|
||||
|
||||
- (instancetype)initWithConfiguration:(QNConfiguration *)config {
|
||||
if (self = [super init]) {
|
||||
if (config == nil) {
|
||||
config = [QNConfiguration build:^(QNConfigurationBuilder *builder){
|
||||
}];
|
||||
}
|
||||
_config = config;
|
||||
[[QNTransactionManager shared] addDnsLocalLoadTransaction];
|
||||
[QNServerConfigMonitor startMonitor];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)sharedInstanceWithConfiguration:(QNConfiguration *)config {
|
||||
static QNUploadManager *sharedInstance = nil;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[self alloc] initWithConfiguration:config];
|
||||
});
|
||||
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (void)putData:(NSData *)data
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option {
|
||||
|
||||
[self putData:data fileName:nil key:key token:token complete:completionHandler option:option];
|
||||
}
|
||||
|
||||
- (void)putData:(NSData *)data
|
||||
fileName:(NSString *)fileName
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option {
|
||||
|
||||
if ([QNUploadManager checkAndNotifyError:key token:token input:data complete:completionHandler]) {
|
||||
return;
|
||||
}
|
||||
|
||||
QNUpToken *t = [QNUpToken parse:token];
|
||||
if (t == nil || ![t isValid]) {
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithInvalidToken:@"invalid token"];
|
||||
[QNUploadManager complete:token
|
||||
key:key
|
||||
source:data
|
||||
responseInfo:info
|
||||
response:nil
|
||||
taskMetrics:nil
|
||||
complete:completionHandler];
|
||||
return;
|
||||
}
|
||||
|
||||
QNServerConfigMonitor.token = token;
|
||||
[[QNTransactionManager shared] addDnsCheckAndPrefetchTransaction:self.config zone:self.config.zone token:t];
|
||||
|
||||
QNUpTaskCompletionHandler complete = ^(QNResponseInfo *info, NSString *key, QNUploadTaskMetrics *metrics, NSDictionary *resp) {
|
||||
[QNUploadManager complete:token
|
||||
key:key
|
||||
source:data
|
||||
responseInfo:info
|
||||
response:resp
|
||||
taskMetrics:metrics
|
||||
complete:completionHandler];
|
||||
};
|
||||
QNFormUpload *up = [[QNFormUpload alloc] initWithData:data
|
||||
key:key
|
||||
fileName:fileName
|
||||
token:t
|
||||
option:option
|
||||
configuration:self.config
|
||||
completionHandler:complete];
|
||||
QNAsyncRun(^{
|
||||
[up run];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)putInputStream:(NSInputStream *)inputStream
|
||||
sourceId:(NSString *)sourceId
|
||||
size:(long long)size
|
||||
fileName:(NSString *)fileName
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option {
|
||||
|
||||
if ([QNUploadManager checkAndNotifyError:key token:token input:inputStream complete:completionHandler]) {
|
||||
return;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
QNUploadSourceStream *source = [QNUploadSourceStream stream:inputStream sourceId:sourceId size:size fileName:fileName];
|
||||
[self putInternal:source key:key token:token complete:completionHandler option:option];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)putFile:(NSString *)filePath
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option {
|
||||
|
||||
if ([QNUploadManager checkAndNotifyError:key token:token input:filePath complete:completionHandler]) {
|
||||
return;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
NSError *error = nil;
|
||||
__block QNFile *file = [[QNFile alloc] init:filePath error:&error];
|
||||
if (error) {
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error];
|
||||
[QNUploadManager complete:token
|
||||
key:key
|
||||
source:nil
|
||||
responseInfo:info
|
||||
response:nil
|
||||
taskMetrics:nil
|
||||
complete:completionHandler];
|
||||
return;
|
||||
}
|
||||
[self putFileInternal:file key:key token:token complete:completionHandler option:option];
|
||||
}
|
||||
}
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
- (void)putALAsset:(ALAsset *)asset
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option {
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
|
||||
if ([QNUploadManager checkAndNotifyError:key token:token input:asset complete:completionHandler]) {
|
||||
return;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
NSError *error = nil;
|
||||
__block QNALAssetFile *file = [[QNALAssetFile alloc] init:asset error:&error];
|
||||
if (error) {
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error];
|
||||
[QNUploadManager complete:token
|
||||
key:key
|
||||
source:nil
|
||||
responseInfo:info
|
||||
response:nil
|
||||
taskMetrics:nil
|
||||
complete:completionHandler];
|
||||
return;
|
||||
}
|
||||
[self putFileInternal:file key:key token:token complete:completionHandler option:option];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)putPHAsset:(PHAsset *)asset
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option {
|
||||
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90100)
|
||||
|
||||
if ([QNUploadManager checkAndNotifyError:key token:token input:asset complete:completionHandler]) {
|
||||
return;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
NSError *error = nil;
|
||||
__block QNPHAssetFile *file = [[QNPHAssetFile alloc] init:asset error:&error];
|
||||
if (error) {
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error];
|
||||
[QNUploadManager complete:token
|
||||
key:key
|
||||
source:nil
|
||||
responseInfo:info
|
||||
response:nil
|
||||
taskMetrics:nil
|
||||
complete:completionHandler];
|
||||
return;
|
||||
}
|
||||
[self putFileInternal:file key:key token:token complete:completionHandler option:option];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)putPHAssetResource:(PHAssetResource *)assetResource
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option {
|
||||
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000)
|
||||
|
||||
if ([QNUploadManager checkAndNotifyError:key token:token input:assetResource complete:completionHandler]) {
|
||||
return;
|
||||
}
|
||||
@autoreleasepool {
|
||||
NSError *error = nil;
|
||||
__block QNPHAssetResource *file = [[QNPHAssetResource alloc] init:assetResource error:&error];
|
||||
if (error) {
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error];
|
||||
[QNUploadManager complete:token
|
||||
key:key
|
||||
source:nil
|
||||
responseInfo:info
|
||||
response:nil
|
||||
taskMetrics:nil
|
||||
complete:completionHandler];
|
||||
return;
|
||||
}
|
||||
[self putFileInternal:file key:key token:token complete:completionHandler option:option];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)putFileInternal:(id<QNFileDelegate>)file
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option {
|
||||
[self putInternal:[QNUploadSourceFile file:file]
|
||||
key:key token:token
|
||||
complete:completionHandler
|
||||
option:option];
|
||||
}
|
||||
|
||||
- (void)putInternal:(id<QNUploadSource>)source
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option {
|
||||
|
||||
@autoreleasepool {
|
||||
QNUpToken *t = [QNUpToken parse:token];
|
||||
if (t == nil || ![t isValid]) {
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithInvalidToken:@"invalid token"];
|
||||
[QNUploadManager complete:token
|
||||
key:key
|
||||
source:source
|
||||
responseInfo:info
|
||||
response:nil
|
||||
taskMetrics:nil
|
||||
complete:completionHandler];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QNUpTaskCompletionHandler complete = ^(QNResponseInfo *info, NSString *key, QNUploadTaskMetrics *metrics, NSDictionary *resp) {
|
||||
[QNUploadManager complete:token
|
||||
key:key
|
||||
source:source
|
||||
responseInfo:info
|
||||
response:resp
|
||||
taskMetrics:metrics
|
||||
complete:completionHandler];
|
||||
};
|
||||
|
||||
QNServerConfigMonitor.token = token;
|
||||
[[QNTransactionManager shared] addDnsCheckAndPrefetchTransaction:self.config zone:self.config.zone token:t];
|
||||
|
||||
long long sourceSize = [source getSize];
|
||||
if (sourceSize > 0 && sourceSize <= self.config.putThreshold) {
|
||||
NSError *error;
|
||||
NSData *data = [source readData:(NSInteger)sourceSize dataOffset:0 error:&error];
|
||||
[source close];
|
||||
if (error) {
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error];
|
||||
[QNUploadManager complete:token
|
||||
key:key
|
||||
source:source
|
||||
responseInfo:info
|
||||
response:nil
|
||||
taskMetrics:nil
|
||||
complete:completionHandler];
|
||||
return;
|
||||
}
|
||||
|
||||
[self putData:data
|
||||
fileName:[source getFileName]
|
||||
key:key
|
||||
token:token
|
||||
complete:completionHandler
|
||||
option:option];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *recorderKey = key;
|
||||
if (self.config.recorder != nil && self.config.recorderKeyGen != nil) {
|
||||
recorderKey = self.config.recorderKeyGen(key, [source getId]);
|
||||
}
|
||||
|
||||
if (self.config.useConcurrentResumeUpload) {
|
||||
QNConcurrentResumeUpload *up = [[QNConcurrentResumeUpload alloc]
|
||||
initWithSource:source
|
||||
key:key
|
||||
token:t
|
||||
option:option
|
||||
configuration:self.config
|
||||
recorder:self.config.recorder
|
||||
recorderKey:recorderKey
|
||||
completionHandler:complete];
|
||||
QNAsyncRun(^{
|
||||
[up run];
|
||||
});
|
||||
} else {
|
||||
QNPartsUpload *up = [[QNPartsUpload alloc]
|
||||
initWithSource:source
|
||||
key:key
|
||||
token:t
|
||||
option:option
|
||||
configuration:self.config
|
||||
recorder:self.config.recorder
|
||||
recorderKey:recorderKey
|
||||
completionHandler:complete];
|
||||
QNAsyncRun(^{
|
||||
[up run];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)checkAndNotifyError:(NSString *)key
|
||||
token:(NSString *)token
|
||||
input:(NSObject *)input
|
||||
complete:(QNUpCompletionHandler)completionHandler {
|
||||
if (completionHandler == nil) {
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException
|
||||
reason:@"no completionHandler"
|
||||
userInfo:nil];
|
||||
return YES;
|
||||
}
|
||||
|
||||
QNResponseInfo *info = nil;
|
||||
if (input == nil) {
|
||||
info = [QNResponseInfo responseInfoOfZeroData:@"no input data"];
|
||||
} else if ([input isKindOfClass:[NSData class]] && [(NSData *)input length] == 0) {
|
||||
info = [QNResponseInfo responseInfoOfZeroData:@"no input data"];
|
||||
} else if (token == nil || [token isEqual:[NSNull null]] || [token isEqualToString:@""]) {
|
||||
info = [QNResponseInfo responseInfoWithInvalidToken:@"no token"];
|
||||
}
|
||||
if (info != nil) {
|
||||
[QNUploadManager complete:token
|
||||
key:key
|
||||
source:nil
|
||||
responseInfo:info
|
||||
response:nil
|
||||
taskMetrics:nil
|
||||
complete:completionHandler];
|
||||
return YES;
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)complete:(NSString *)token
|
||||
key:(NSString *)key
|
||||
source:(NSObject *)source
|
||||
responseInfo:(QNResponseInfo *)responseInfo
|
||||
response:(NSDictionary *)response
|
||||
taskMetrics:(QNUploadTaskMetrics *)taskMetrics
|
||||
complete:(QNUpCompletionHandler)completionHandler {
|
||||
|
||||
[QNUploadManager reportQuality:key source:source responseInfo:responseInfo taskMetrics:taskMetrics token:token];
|
||||
|
||||
QNAsyncRunInMain(^{
|
||||
if (completionHandler) {
|
||||
completionHandler(responseInfo, key, response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//MARK:-- 统计quality日志
|
||||
+ (void)reportQuality:(NSString *)key
|
||||
source:(NSObject *)source
|
||||
responseInfo:(QNResponseInfo *)responseInfo
|
||||
taskMetrics:(QNUploadTaskMetrics *)taskMetrics
|
||||
token:(NSString *)token{
|
||||
|
||||
QNUpToken *upToken = [QNUpToken parse:token];
|
||||
QNUploadTaskMetrics *taskMetricsP = taskMetrics ?: [QNUploadTaskMetrics emptyMetrics];
|
||||
|
||||
QNReportItem *item = [QNReportItem item];
|
||||
[item setReportValue:QNReportLogTypeQuality forKey:QNReportQualityKeyLogType];
|
||||
[item setReportValue:taskMetricsP.upType forKey:QNReportQualityKeyUpType];
|
||||
[item setReportValue:@([[NSDate date] timeIntervalSince1970]) forKey:QNReportQualityKeyUpTime];
|
||||
[item setReportValue:responseInfo.qualityResult forKey:QNReportQualityKeyResult];
|
||||
[item setReportValue:upToken.bucket forKey:QNReportQualityKeyTargetBucket];
|
||||
[item setReportValue:key forKey:QNReportQualityKeyTargetKey];
|
||||
[item setReportValue:taskMetricsP.totalElapsedTime forKey:QNReportQualityKeyTotalElapsedTime];
|
||||
[item setReportValue:taskMetricsP.ucQueryMetrics.totalElapsedTime forKey:QNReportQualityKeyUcQueryElapsedTime];
|
||||
[item setReportValue:taskMetricsP.requestCount forKey:QNReportQualityKeyRequestsCount];
|
||||
[item setReportValue:taskMetricsP.regionCount forKey:QNReportQualityKeyRegionsCount];
|
||||
[item setReportValue:taskMetricsP.bytesSend forKey:QNReportQualityKeyBytesSent];
|
||||
|
||||
[item setReportValue:[QNUtils systemName] forKey:QNReportQualityKeyOsName];
|
||||
[item setReportValue:[QNUtils systemVersion] forKey:QNReportQualityKeyOsVersion];
|
||||
[item setReportValue:[QNUtils sdkLanguage] forKey:QNReportQualityKeySDKName];
|
||||
[item setReportValue:[QNUtils sdkVersion] forKey:QNReportQualityKeySDKVersion];
|
||||
|
||||
[item setReportValue:responseInfo.requestReportErrorType forKey:QNReportQualityKeyErrorType];
|
||||
NSString *errorDesc = responseInfo.requestReportErrorType ? responseInfo.message : nil;
|
||||
[item setReportValue:errorDesc forKey:QNReportQualityKeyErrorDescription];
|
||||
|
||||
[item setReportValue:taskMetricsP.lastMetrics.lastMetrics.hijacked forKey:QNReportBlockKeyHijacking];
|
||||
|
||||
long long fileSize = -1;
|
||||
if ([source conformsToProtocol:@protocol(QNUploadSource)]) {
|
||||
fileSize = [(id <QNUploadSource>)source getSize];
|
||||
} else if ([source isKindOfClass:[NSData class]]) {
|
||||
fileSize = [(NSData *)source length];
|
||||
}
|
||||
[item setReportValue:@(fileSize) forKey:QNReportQualityKeyFileSize];
|
||||
if (responseInfo.isOK && fileSize > 0 && taskMetrics.totalElapsedTime) {
|
||||
NSNumber *speed = [QNUtils calculateSpeed:fileSize totalTime:taskMetrics.totalElapsedTime.longLongValue];
|
||||
[item setReportValue:speed forKey:QNReportQualityKeyPerceptiveSpeed];
|
||||
}
|
||||
|
||||
[kQNReporter reportItem:item token:token];
|
||||
}
|
||||
|
||||
@end
|
||||
138
Pods/Qiniu/QiniuSDK/Storage/QNUploadOption.h
generated
Executable file
138
Pods/Qiniu/QiniuSDK/Storage/QNUploadOption.h
generated
Executable file
@@ -0,0 +1,138 @@
|
||||
//
|
||||
// QNUploadOption.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14/10/4.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* 上传进度回调函数
|
||||
*
|
||||
* @param key 上传时指定的存储key
|
||||
* @param percent 进度百分比
|
||||
*/
|
||||
typedef void (^QNUpProgressHandler)(NSString *key, float percent);
|
||||
|
||||
/**
|
||||
* 上传进度回调函数
|
||||
*
|
||||
* @param key 上传文件的保存文件名
|
||||
* @param uploadBytes 已上传大小
|
||||
* @param totalBytes 总大小;无法获取大小时为 -1
|
||||
*/
|
||||
typedef void (^QNUpByteProgressHandler)(NSString *key, long long uploadBytes, long long totalBytes);
|
||||
|
||||
/**
|
||||
* 上传中途取消函数
|
||||
*
|
||||
* @return 如果想取消,返回True, 否则返回No
|
||||
*/
|
||||
typedef BOOL (^QNUpCancellationSignal)(void);
|
||||
|
||||
/**
|
||||
* 可选参数集合,此类初始化后sdk上传使用时 不会对此进行改变;如果参数没有变化以及没有使用依赖,可以重复使用。
|
||||
*/
|
||||
@interface QNUploadOption : NSObject
|
||||
|
||||
/**
|
||||
* 用于服务器上传回调通知的自定义参数,参数的key必须以x: 开头 eg: x:foo
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSDictionary *params;
|
||||
|
||||
/**
|
||||
* 用于设置meta数据,参数的key必须以x-qn-meta- 开头 eg: x-qn-meta-key
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSDictionary *metaDataParam;
|
||||
|
||||
/**
|
||||
* 指定文件的mime类型
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSString *mimeType;
|
||||
|
||||
/**
|
||||
* 是否进行crc校验
|
||||
*/
|
||||
@property (readonly) BOOL checkCrc;
|
||||
|
||||
/**
|
||||
* 进度回调函数
|
||||
*/
|
||||
@property (copy, readonly) QNUpProgressHandler progressHandler;
|
||||
|
||||
/**
|
||||
* 进度回调函数
|
||||
* 注:
|
||||
* 使用此接口,progressHandler 会无效
|
||||
*/
|
||||
@property (copy, readonly) QNUpByteProgressHandler byteProgressHandler;
|
||||
|
||||
/**
|
||||
* 中途取消函数
|
||||
*/
|
||||
@property (copy, readonly) QNUpCancellationSignal cancellationSignal;
|
||||
|
||||
/**
|
||||
* 可选参数的初始化方法
|
||||
*
|
||||
* @param mimeType mime类型
|
||||
* @param progress 进度函数
|
||||
* @param params 自定义服务器回调参数 参数的key必须以x: 开头 eg: x:foo
|
||||
* @param check 是否进行crc检查
|
||||
* @param cancellation 中途取消函数
|
||||
*
|
||||
* @return 可选参数类实例
|
||||
*/
|
||||
- (instancetype)initWithMime:(NSString *)mimeType
|
||||
progressHandler:(QNUpProgressHandler)progress
|
||||
params:(NSDictionary *)params
|
||||
checkCrc:(BOOL)check
|
||||
cancellationSignal:(QNUpCancellationSignal)cancellation;
|
||||
|
||||
- (instancetype)initWithMime:(NSString *)mimeType
|
||||
byteProgressHandler:(QNUpByteProgressHandler)progress
|
||||
params:(NSDictionary *)params
|
||||
checkCrc:(BOOL)check
|
||||
cancellationSignal:(QNUpCancellationSignal)cancellation;
|
||||
|
||||
|
||||
/**
|
||||
* 可选参数的初始化方法
|
||||
*
|
||||
* @param mimeType mime类型
|
||||
* @param progress 进度函数
|
||||
* @param params 自定义服务器回调参数 参数的key必须以x: 开头 eg: x:foo
|
||||
* @param metaDataParams 设置meta数据,参数的key必须以x-qn-meta- 开头 eg: x-qn-meta-key
|
||||
* @param check 是否进行crc检查
|
||||
* @param cancellation 中途取消函数
|
||||
*
|
||||
* @return 可选参数类实例
|
||||
*/
|
||||
- (instancetype)initWithMime:(NSString *)mimeType
|
||||
progressHandler:(QNUpProgressHandler)progress
|
||||
params:(NSDictionary *)params
|
||||
metaDataParams:(NSDictionary *)metaDataParams
|
||||
checkCrc:(BOOL)check
|
||||
cancellationSignal:(QNUpCancellationSignal)cancellation;
|
||||
|
||||
- (instancetype)initWithMime:(NSString *)mimeType
|
||||
byteProgressHandler:(QNUpByteProgressHandler)progress
|
||||
params:(NSDictionary *)params
|
||||
metaDataParams:(NSDictionary *)metaDataParams
|
||||
checkCrc:(BOOL)check
|
||||
cancellationSignal:(QNUpCancellationSignal)cancellation;
|
||||
|
||||
- (instancetype)initWithProgressHandler:(QNUpProgressHandler)progress;
|
||||
|
||||
- (instancetype)initWithByteProgressHandler:(QNUpByteProgressHandler)progress;
|
||||
|
||||
/**
|
||||
* 内部使用,默认的参数实例
|
||||
*
|
||||
* @return 可选参数类实例
|
||||
*/
|
||||
+ (instancetype)defaultOptions;
|
||||
|
||||
@end
|
||||
134
Pods/Qiniu/QiniuSDK/Storage/QNUploadOption.m
generated
Executable file
134
Pods/Qiniu/QiniuSDK/Storage/QNUploadOption.m
generated
Executable file
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// QNUploadOption.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14/10/4.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUploadOption.h"
|
||||
#import "QNUploadManager.h"
|
||||
|
||||
static NSString *mime(NSString *mimeType) {
|
||||
if (mimeType == nil || [mimeType isEqualToString:@""]) {
|
||||
return @"application/octet-stream";
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
@implementation QNUploadOption
|
||||
|
||||
+ (NSDictionary *)filterParam:(NSDictionary *)params {
|
||||
NSMutableDictionary *ret = [NSMutableDictionary dictionary];
|
||||
if (params == nil) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
[params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
|
||||
if ([key hasPrefix:@"x:"] && ![obj isEqualToString:@""]) {
|
||||
ret[key] = obj;
|
||||
} else {
|
||||
NSLog(@"参数%@设置无效,请检查参数格式", key);
|
||||
}
|
||||
}];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ (NSDictionary *)filterMetaDataParam:(NSDictionary *)params {
|
||||
NSMutableDictionary *ret = [NSMutableDictionary dictionary];
|
||||
if (params == nil) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
[params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
|
||||
if ([key hasPrefix:@"x-qn-meta-"] && ![obj isEqualToString:@""]) {
|
||||
ret[key] = obj;
|
||||
} else {
|
||||
NSLog(@"参数%@设置无效,请检查参数格式", key);
|
||||
}
|
||||
}];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
- (instancetype)initWithProgressHandler:(QNUpProgressHandler)progress {
|
||||
return [self initWithMime:nil progressHandler:progress params:nil checkCrc:NO cancellationSignal:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithByteProgressHandler:(QNUpByteProgressHandler)progress {
|
||||
return [self initWithMime:nil byteProgressHandler:progress params:nil checkCrc:NO cancellationSignal:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithMime:(NSString *)mimeType
|
||||
progressHandler:(QNUpProgressHandler)progress
|
||||
params:(NSDictionary *)params
|
||||
checkCrc:(BOOL)check
|
||||
cancellationSignal:(QNUpCancellationSignal)cancel {
|
||||
return [self initWithMime:mimeType
|
||||
progressHandler:progress
|
||||
params:params
|
||||
metaDataParams:nil
|
||||
checkCrc:check
|
||||
cancellationSignal:cancel];
|
||||
}
|
||||
|
||||
- (instancetype)initWithMime:(NSString *)mimeType
|
||||
byteProgressHandler:(QNUpByteProgressHandler)progress
|
||||
params:(NSDictionary *)params
|
||||
checkCrc:(BOOL)check
|
||||
cancellationSignal:(QNUpCancellationSignal)cancellation {
|
||||
return [self initWithMime:mimeType
|
||||
byteProgressHandler:progress
|
||||
params:params
|
||||
metaDataParams:nil
|
||||
checkCrc:check
|
||||
cancellationSignal:cancellation];
|
||||
}
|
||||
|
||||
- (instancetype)initWithMime:(NSString *)mimeType
|
||||
progressHandler:(QNUpProgressHandler)progress
|
||||
params:(NSDictionary *)params
|
||||
metaDataParams:(NSDictionary *)metaDataParams
|
||||
checkCrc:(BOOL)check
|
||||
cancellationSignal:(QNUpCancellationSignal)cancellation{
|
||||
if (self = [super init]) {
|
||||
_mimeType = mime(mimeType);
|
||||
_progressHandler = progress != nil ? progress : ^(NSString *key, float percent) {};
|
||||
_params = [QNUploadOption filterParam:params];
|
||||
_metaDataParam = [QNUploadOption filterMetaDataParam:metaDataParams];
|
||||
_checkCrc = check;
|
||||
_cancellationSignal = cancellation != nil ? cancellation : ^BOOL() {
|
||||
return NO;
|
||||
};
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithMime:(NSString *)mimeType
|
||||
byteProgressHandler:(QNUpByteProgressHandler)progress
|
||||
params:(NSDictionary *)params
|
||||
metaDataParams:(NSDictionary *)metaDataParams
|
||||
checkCrc:(BOOL)check
|
||||
cancellationSignal:(QNUpCancellationSignal)cancellation {
|
||||
if (self = [super init]) {
|
||||
_mimeType = mime(mimeType);
|
||||
_byteProgressHandler = progress != nil ? progress : ^(NSString *key, long long uploadBytes, long long totalBytes) {};
|
||||
_params = [QNUploadOption filterParam:params];
|
||||
_metaDataParam = [QNUploadOption filterMetaDataParam:metaDataParams];
|
||||
_checkCrc = check;
|
||||
_cancellationSignal = cancellation != nil ? cancellation : ^BOOL() {
|
||||
return NO;
|
||||
};
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)defaultOptions {
|
||||
return [[QNUploadOption alloc] initWithMime:nil byteProgressHandler:nil params:nil checkCrc:NO cancellationSignal:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
83
Pods/Qiniu/QiniuSDK/Storage/QNUploadSource.h
generated
Normal file
83
Pods/Qiniu/QiniuSDK/Storage/QNUploadSource.h
generated
Normal file
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// QNUploadSource.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol QNUploadSource <NSObject>
|
||||
|
||||
/**
|
||||
* 获取资源唯一标识
|
||||
* 作为断点续传时判断是否为同一资源的依据之一;
|
||||
* 如果两个资源的 record key 和 资源唯一标识均相同则认为资源为同一资源,断点续传才会生效
|
||||
* 注:
|
||||
* 同一资源的数据必须完全相同,否则上传可能会出现异常
|
||||
*
|
||||
* @return 资源修改时间
|
||||
*/
|
||||
- (NSString *)getId;
|
||||
|
||||
/**
|
||||
* 是否可以重新加载文件信息,也即是否可以重新读取信息
|
||||
* @return return
|
||||
*/
|
||||
- (BOOL)couldReloadSource;
|
||||
|
||||
/**
|
||||
* 重新加载文件信息,以便于重新读取
|
||||
*
|
||||
* @return 重新加载是否成功
|
||||
*/
|
||||
- (BOOL)reloadSource;
|
||||
|
||||
/**
|
||||
* 获取资源文件名
|
||||
* @return 资源文件名
|
||||
*/
|
||||
- (NSString *)getFileName;
|
||||
|
||||
/**
|
||||
* 获取资源大小
|
||||
* 无法获取大小时返回 -1
|
||||
* 作用:
|
||||
* 1. 验证资源是否为同一资源
|
||||
* 2. 计算上传进度
|
||||
*
|
||||
* @return 资源大小
|
||||
*/
|
||||
- (long long)getSize;
|
||||
|
||||
/**
|
||||
* 读取数据
|
||||
* 1. 返回 NSData 可能为空,但不会为 null;
|
||||
* 2. 当 NSData 大小和 dataSize 不同时,则源数据已经读取结束
|
||||
* 3. 读取异常时抛出 error
|
||||
* 4. 仅支持串行调用,且 dataOffset 依次递增
|
||||
*
|
||||
* @param dataSize 数据大小
|
||||
* @param dataOffset 数据偏移量
|
||||
* @param error 异常时的错误信息
|
||||
* @return 数据
|
||||
*/
|
||||
- (NSData *)readData:(NSInteger)dataSize dataOffset:(long long)dataOffset error:(NSError **)error;
|
||||
|
||||
/**
|
||||
* 关闭流
|
||||
*/
|
||||
- (void)close;
|
||||
|
||||
@optional
|
||||
// 上传源类型
|
||||
- (NSString *)sourceType;
|
||||
|
||||
@end
|
||||
|
||||
#define kQNUnknownSourceSize (-1)
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
20
Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceFile.h
generated
Normal file
20
Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceFile.h
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// QNUploadSourceFile.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNFileDelegate.h"
|
||||
#import "QNUploadSource.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNUploadSourceFile : NSObject <QNUploadSource>
|
||||
|
||||
+ (instancetype)file:(id <QNFileDelegate>)file;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
60
Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceFile.m
generated
Normal file
60
Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceFile.m
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// QNUploadSourceFile.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUploadSourceFile.h"
|
||||
|
||||
@interface QNUploadSourceFile()
|
||||
|
||||
@property(nonatomic, strong)id <QNFileDelegate> file;
|
||||
|
||||
@end
|
||||
@implementation QNUploadSourceFile
|
||||
|
||||
+ (instancetype)file:(id <QNFileDelegate>)file {
|
||||
QNUploadSourceFile *sourceFile = [[QNUploadSourceFile alloc] init];
|
||||
sourceFile.file = file;
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)couldReloadSource {
|
||||
return self.file != nil;
|
||||
}
|
||||
|
||||
- (BOOL)reloadSource {
|
||||
return true;
|
||||
}
|
||||
|
||||
- (nonnull NSString *)getId {
|
||||
return [NSString stringWithFormat:@"%@_%lld", [self getFileName], [self.file modifyTime]];
|
||||
}
|
||||
|
||||
- (nonnull NSString *)getFileName {
|
||||
return [[self.file path] lastPathComponent];
|
||||
}
|
||||
|
||||
- (long long)getSize {
|
||||
return [self.file size];
|
||||
}
|
||||
|
||||
- (NSData *)readData:(NSInteger)dataSize dataOffset:(long long)dataOffset error:(NSError *__autoreleasing _Nullable *)error {
|
||||
return [self.file read:dataOffset size:dataSize error:error];
|
||||
}
|
||||
|
||||
- (void)close {
|
||||
[self.file close];
|
||||
}
|
||||
|
||||
- (NSString *)sourceType {
|
||||
if ([self.file respondsToSelector:@selector(fileType)]) {
|
||||
return self.file.fileType;
|
||||
} else {
|
||||
return @"SourceFile";
|
||||
}
|
||||
}
|
||||
@end
|
||||
22
Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceStream.h
generated
Normal file
22
Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceStream.h
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// QNUploadSourceStream.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUploadSource.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNUploadSourceStream : NSObject <QNUploadSource>
|
||||
|
||||
+ (instancetype)stream:(NSInputStream * _Nonnull)stream
|
||||
sourceId:(NSString * _Nullable)sourceId
|
||||
size:(long long)size
|
||||
fileName:(NSString * _Nullable)fileName;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
234
Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceStream.m
generated
Normal file
234
Pods/Qiniu/QiniuSDK/Storage/QNUploadSourceStream.m
generated
Normal file
@@ -0,0 +1,234 @@
|
||||
//
|
||||
// QNUploadSourceStream.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/5/10.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNErrorCode.h"
|
||||
#import "QNUploadSourceStream.h"
|
||||
|
||||
@interface QNUploadSourceStream()
|
||||
|
||||
@property(nonatomic, assign)BOOL hasSize;
|
||||
@property(nonatomic, assign)long long size;
|
||||
@property(nonatomic, assign)long long readOffset;
|
||||
@property(nonatomic, copy)NSString *sourceId;
|
||||
@property(nonatomic, copy)NSString *fileName;
|
||||
@property(nonatomic, strong)NSInputStream *stream;
|
||||
|
||||
@end
|
||||
@implementation QNUploadSourceStream
|
||||
|
||||
+ (instancetype)stream:(NSInputStream * _Nonnull)stream
|
||||
sourceId:(NSString * _Nullable)sourceId
|
||||
size:(long long)size
|
||||
fileName:(NSString * _Nullable)fileName {
|
||||
QNUploadSourceStream *sourceStream = [[QNUploadSourceStream alloc] init];
|
||||
sourceStream.stream = stream;
|
||||
sourceStream.sourceId = sourceId;
|
||||
sourceStream.fileName = fileName;
|
||||
sourceStream.size = size;
|
||||
sourceStream.hasSize = size > 0;
|
||||
sourceStream.readOffset = 0;
|
||||
return sourceStream;
|
||||
}
|
||||
|
||||
- (NSString *)getId {
|
||||
return self.sourceId;
|
||||
}
|
||||
|
||||
- (BOOL)couldReloadSource {
|
||||
return false;
|
||||
}
|
||||
|
||||
- (BOOL)reloadSource {
|
||||
return false;
|
||||
}
|
||||
|
||||
- (NSString *)getFileName {
|
||||
return self.fileName;
|
||||
}
|
||||
|
||||
- (long long)getSize {
|
||||
if (self.size > kQNUnknownSourceSize) {
|
||||
return self.size;
|
||||
} else {
|
||||
return kQNUnknownSourceSize;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSData *)readData:(NSInteger)dataSize dataOffset:(long long)dataOffset error:(NSError **)error {
|
||||
if (self.stream == nil) {
|
||||
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"inputStream is empty"}];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dataOffset < self.readOffset) {
|
||||
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"read data error: error data offset"}];
|
||||
return nil;
|
||||
}
|
||||
|
||||
// 打开流
|
||||
[self openStreamIfNeeded];
|
||||
|
||||
if (dataOffset > self.readOffset) {
|
||||
// 跳过多余的数据
|
||||
[self streamSkipSize:dataOffset - self.readOffset error:error];
|
||||
if (*error != nil) {
|
||||
return nil;
|
||||
}
|
||||
self.readOffset = dataOffset;
|
||||
}
|
||||
|
||||
// 读取数据
|
||||
BOOL isEOF = false;
|
||||
NSInteger sliceSize = 1024;
|
||||
NSInteger readSize = 0;
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
while (readSize < dataSize) {
|
||||
@autoreleasepool {
|
||||
NSData *sliceData = [self readDataFromStream:sliceSize error:error];
|
||||
if (*error != nil) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (sliceData.length > 0) {
|
||||
readSize += sliceData.length;
|
||||
[data appendData:sliceData];
|
||||
}
|
||||
|
||||
if (sliceData.length < sliceSize) {
|
||||
isEOF = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
self.readOffset += readSize;
|
||||
|
||||
if (*error != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (isEOF) {
|
||||
self.size = self.readOffset;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
- (void)openStreamIfNeeded {
|
||||
BOOL isOpening = true;
|
||||
while (true) {
|
||||
switch (self.stream.streamStatus) {
|
||||
case NSStreamStatusNotOpen:
|
||||
[self.stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
||||
[self.stream open];
|
||||
continue;
|
||||
case NSStreamStatusOpening:
|
||||
continue;
|
||||
default:
|
||||
isOpening = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isOpening) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)streamSkipSize:(long long)size error:(NSError **)error {
|
||||
BOOL isEOF = false;
|
||||
NSInteger sliceSize = 1024;
|
||||
NSInteger readSize = 0;
|
||||
while (readSize < size) {
|
||||
@autoreleasepool {
|
||||
NSData *sliceData = [self readDataFromStream:sliceSize error:error];
|
||||
if (*error != nil) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (sliceData.length > 0) {
|
||||
readSize += sliceData.length;
|
||||
}
|
||||
|
||||
if (sliceData.length < sliceSize) {
|
||||
isEOF = true;
|
||||
break;
|
||||
}
|
||||
sliceData = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read 之前必须先 open stream
|
||||
- (NSData *)readDataFromStream:(NSInteger)dataSize error:(NSError **)error {
|
||||
BOOL isEOF = false;
|
||||
NSInteger readSize = 0;
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
uint8_t buffer[dataSize];
|
||||
while (readSize < dataSize) {
|
||||
// 检查状态
|
||||
switch (self.stream.streamStatus) {
|
||||
case NSStreamStatusOpen:
|
||||
break;
|
||||
case NSStreamStatusReading:
|
||||
continue;
|
||||
case NSStreamStatusWriting:
|
||||
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"stream is writing"}];
|
||||
break;
|
||||
case NSStreamStatusAtEnd:
|
||||
isEOF = true;
|
||||
break;
|
||||
case NSStreamStatusClosed:
|
||||
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:kQNFileError userInfo:@{NSLocalizedDescriptionKey : @"stream is closed"}];
|
||||
break;
|
||||
case NSStreamStatusError:
|
||||
*error = self.stream.streamError;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (*error != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (isEOF) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查是否有数据可读
|
||||
if (!self.stream.hasBytesAvailable) {
|
||||
[NSThread sleepForTimeInterval:0.05];
|
||||
continue;
|
||||
}
|
||||
|
||||
// 读取数据
|
||||
NSInteger maxLength = dataSize;
|
||||
NSInteger length = [self.stream read:buffer maxLength:maxLength];
|
||||
*error = self.stream.streamError;
|
||||
if (*error != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
readSize += length;
|
||||
[data appendBytes:(const void *)buffer length:length];
|
||||
}
|
||||
}
|
||||
return [data copy];
|
||||
}
|
||||
|
||||
- (void)close {
|
||||
[self.stream close];
|
||||
[self.stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
|
||||
- (NSString *)sourceType {
|
||||
return [NSString stringWithFormat:@"SourceStream:%@", _hasSize?@"HasSize":@"NoSize"];
|
||||
}
|
||||
@end
|
||||
94
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.h
generated
Normal file
94
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.h
generated
Normal file
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// QNServerConfig.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/8/30.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNCache.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNServerRegionConfig : NSObject
|
||||
|
||||
@property(nonatomic, assign, readonly)long clearId;
|
||||
@property(nonatomic, assign, readonly)BOOL clearCache;
|
||||
|
||||
+ (instancetype)config:(NSDictionary *)info;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface QNServerDnsServer : NSObject
|
||||
|
||||
@property(nonatomic, assign, readonly)BOOL isOverride;
|
||||
@property(nonatomic, strong, readonly)NSArray <NSString *> *servers;
|
||||
|
||||
+ (instancetype)config:(NSDictionary *)info;
|
||||
|
||||
@end
|
||||
|
||||
@interface QNServerDohConfig : NSObject
|
||||
|
||||
@property(nonatomic, strong, readonly)NSNumber *enable;
|
||||
@property(nonatomic, strong, readonly)QNServerDnsServer *ipv4Server;
|
||||
@property(nonatomic, strong, readonly)QNServerDnsServer *ipv6Server;
|
||||
|
||||
+ (instancetype)config:(NSDictionary *)info;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface QNServerUdpDnsConfig : NSObject
|
||||
|
||||
@property(nonatomic, strong, readonly)NSNumber *enable;
|
||||
@property(nonatomic, strong, readonly)QNServerDnsServer *ipv4Server;
|
||||
@property(nonatomic, strong, readonly)QNServerDnsServer *ipv6Server;
|
||||
|
||||
+ (instancetype)config:(NSDictionary *)info;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface QNServerDnsConfig : NSObject
|
||||
|
||||
@property(nonatomic, strong, readonly)NSNumber *enable;
|
||||
@property(nonatomic, assign, readonly)long clearId;
|
||||
@property(nonatomic, assign, readonly)BOOL clearCache;
|
||||
@property(nonatomic, strong, readonly)QNServerUdpDnsConfig *udpConfig;
|
||||
@property(nonatomic, strong, readonly)QNServerDohConfig *dohConfig;
|
||||
|
||||
+ (instancetype)config:(NSDictionary *)info;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface QNConnectCheckConfig : NSObject
|
||||
|
||||
@property(nonatomic, assign, readonly)BOOL isOverride;
|
||||
@property(nonatomic, strong, readonly)NSNumber *enable;
|
||||
@property(nonatomic, strong, readonly)NSNumber *timeoutMs;
|
||||
@property(nonatomic, strong, readonly)NSArray <NSString *> *urls;
|
||||
|
||||
+ (instancetype)config:(NSDictionary *)info;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface QNServerConfig : NSObject<QNCacheObject>
|
||||
|
||||
@property(nonatomic, assign, readonly)BOOL isValid;
|
||||
@property(nonatomic, assign, readonly)long ttl;
|
||||
@property(nonatomic, strong, readonly)QNServerRegionConfig *regionConfig;
|
||||
@property(nonatomic, strong, readonly)QNServerDnsConfig *dnsConfig;
|
||||
@property(nonatomic, strong, readonly)QNConnectCheckConfig *connectCheckConfig;
|
||||
|
||||
@property(nonatomic, strong, readonly)NSDictionary *info;
|
||||
|
||||
+ (instancetype)config:(NSDictionary *)info;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
160
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.m
generated
Normal file
160
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfig.m
generated
Normal file
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// QNServerConfig.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/8/30.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNServerConfig.h"
|
||||
|
||||
@interface QNServerRegionConfig()
|
||||
@property(nonatomic, assign)long clearId;
|
||||
@property(nonatomic, assign)BOOL clearCache;
|
||||
@end
|
||||
@implementation QNServerRegionConfig
|
||||
+ (instancetype)config:(NSDictionary *)info {
|
||||
QNServerRegionConfig *config = [[QNServerRegionConfig alloc] init];
|
||||
config.clearId = [info[@"clear_id"] longValue];
|
||||
config.clearCache = [info[@"clear_cache"] longValue];
|
||||
return config;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface QNServerDnsServer()
|
||||
@property(nonatomic, assign)BOOL isOverride;
|
||||
@property(nonatomic, strong)NSArray <NSString *> *servers;
|
||||
@end
|
||||
@implementation QNServerDnsServer
|
||||
+ (instancetype)config:(NSDictionary *)info {
|
||||
QNServerDnsServer *config = [[QNServerDnsServer alloc] init];
|
||||
config.isOverride = [info[@"override_default"] boolValue];
|
||||
if (info[@"ips"] && [info[@"ips"] isKindOfClass:[NSArray class]]) {
|
||||
config.servers = info[@"ips"];
|
||||
} else if ([info[@"urls"] isKindOfClass:[NSArray class]]){
|
||||
config.servers = info[@"urls"];
|
||||
}
|
||||
return config;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface QNServerDohConfig()
|
||||
@property(nonatomic, strong)NSNumber *enable;
|
||||
@property(nonatomic, strong)QNServerDnsServer *ipv4Server;
|
||||
@property(nonatomic, strong)QNServerDnsServer *ipv6Server;
|
||||
@end
|
||||
@implementation QNServerDohConfig
|
||||
+ (instancetype)config:(NSDictionary *)info {
|
||||
QNServerDohConfig *config = [[QNServerDohConfig alloc] init];
|
||||
config.enable = info[@"enabled"];
|
||||
config.ipv4Server = [QNServerDnsServer config:info[@"ipv4"]];
|
||||
config.ipv6Server = [QNServerDnsServer config:info[@"ipv6"]];
|
||||
return config;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface QNServerUdpDnsConfig()
|
||||
@property(nonatomic, strong)NSNumber *enable;
|
||||
@property(nonatomic, strong)QNServerDnsServer *ipv4Server;
|
||||
@property(nonatomic, strong)QNServerDnsServer *ipv6Server;
|
||||
@end
|
||||
@implementation QNServerUdpDnsConfig
|
||||
+ (instancetype)config:(NSDictionary *)info {
|
||||
QNServerUdpDnsConfig *config = [[QNServerUdpDnsConfig alloc] init];
|
||||
config.enable = info[@"enabled"];
|
||||
config.ipv4Server = [QNServerDnsServer config:info[@"ipv4"]];
|
||||
config.ipv6Server = [QNServerDnsServer config:info[@"ipv6"]];
|
||||
return config;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface QNServerDnsConfig()
|
||||
@property(nonatomic, strong)NSNumber *enable;
|
||||
@property(nonatomic, assign)long clearId;
|
||||
@property(nonatomic, assign)BOOL clearCache;
|
||||
@property(nonatomic, strong)QNServerUdpDnsConfig *udpConfig;
|
||||
@property(nonatomic, strong)QNServerDohConfig *dohConfig;
|
||||
@end
|
||||
@implementation QNServerDnsConfig
|
||||
+ (instancetype)config:(NSDictionary *)info {
|
||||
QNServerDnsConfig *config = [[QNServerDnsConfig alloc] init];
|
||||
config.enable = info[@"enabled"];
|
||||
config.clearId = [info[@"clear_id"] longValue];
|
||||
config.clearCache = [info[@"clear_cache"] longValue];
|
||||
config.dohConfig = [QNServerDohConfig config:info[@"doh"]];
|
||||
config.udpConfig = [QNServerUdpDnsConfig config:info[@"udp"]];
|
||||
return config;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface QNConnectCheckConfig()
|
||||
@property(nonatomic, assign)BOOL isOverride;
|
||||
@property(nonatomic, strong)NSNumber *enable;
|
||||
@property(nonatomic, strong)NSNumber *timeoutMs;
|
||||
@property(nonatomic, strong)NSArray <NSString *> *urls;
|
||||
@end
|
||||
@implementation QNConnectCheckConfig
|
||||
+ (instancetype)config:(NSDictionary *)info {
|
||||
QNConnectCheckConfig *config = [[QNConnectCheckConfig alloc] init];
|
||||
config.isOverride = [info[@"override_default"] boolValue];
|
||||
config.enable = info[@"enabled"];
|
||||
config.timeoutMs = info[@"timeout_ms"];
|
||||
if (info[@"urls"] && [info[@"urls"] isKindOfClass:[NSArray class]]) {
|
||||
config.urls = info[@"urls"];
|
||||
}
|
||||
return config;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface QNServerConfig()
|
||||
@property(nonatomic, strong)NSDictionary *info;
|
||||
@property(nonatomic, assign)double timestamp;
|
||||
@property(nonatomic, assign)long ttl;
|
||||
@property(nonatomic, strong)QNServerRegionConfig *regionConfig;
|
||||
@property(nonatomic, strong)QNServerDnsConfig *dnsConfig;
|
||||
@property(nonatomic, strong)QNConnectCheckConfig *connectCheckConfig;
|
||||
@end
|
||||
@implementation QNServerConfig
|
||||
|
||||
+ (instancetype)config:(NSDictionary *)info {
|
||||
return [[QNServerConfig alloc] initWithDictionary:info];
|
||||
}
|
||||
|
||||
- (nonnull id<QNCacheObject>)initWithDictionary:(nullable NSDictionary *)info {
|
||||
if (self = [self init]) {
|
||||
if (info) {
|
||||
self.ttl = [info[@"ttl"] longValue];
|
||||
self.regionConfig = [QNServerRegionConfig config:info[@"region"]];
|
||||
self.dnsConfig = [QNServerDnsConfig config:info[@"dns"]];
|
||||
self.connectCheckConfig = [QNConnectCheckConfig config:info[@"connection_check"]];
|
||||
|
||||
if (self.ttl < 10) {
|
||||
self.ttl = 10;
|
||||
}
|
||||
|
||||
NSMutableDictionary *mutableInfo = [info mutableCopy];
|
||||
if (info[@"timestamp"] != nil) {
|
||||
self.timestamp = [info[@"timestamp"] doubleValue];
|
||||
}
|
||||
if (self.timestamp == 0) {
|
||||
self.timestamp = [[NSDate date] timeIntervalSince1970];
|
||||
mutableInfo[@"timestamp"] = @(self.timestamp);
|
||||
}
|
||||
self.info = [mutableInfo copy];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable NSDictionary *)toDictionary {
|
||||
return [self.info copy];
|
||||
}
|
||||
|
||||
- (BOOL)isValid {
|
||||
return [[NSDate date] timeIntervalSince1970] < (self.timestamp + self.ttl);
|
||||
}
|
||||
|
||||
@end
|
||||
29
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.h
generated
Normal file
29
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.h
generated
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// QNServerConfigCache.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/8/30.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNServerConfig.h"
|
||||
#import "QNServerUserConfig.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNServerConfigCache : NSObject
|
||||
|
||||
@property(nonatomic, strong)QNServerConfig *config;
|
||||
@property(nonatomic, strong)QNServerUserConfig *userConfig;
|
||||
|
||||
- (QNServerConfig *)getConfigFromDisk;
|
||||
- (void)saveConfigToDisk:(QNServerConfig *)config;
|
||||
|
||||
- (QNServerUserConfig *)getUserConfigFromDisk;
|
||||
- (void)saveUserConfigToDisk:(QNServerUserConfig *)config;
|
||||
|
||||
- (void)removeConfigCache;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
65
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.m
generated
Normal file
65
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigCache.m
generated
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// QNServerConfigCache.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/8/30.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNServerConfigCache.h"
|
||||
#import "QNUtils.h"
|
||||
#import "QNCache.h"
|
||||
|
||||
#define kQNServerConfigDiskKey @"config"
|
||||
#define kQNServerUserConfigDiskKey @"userConfig"
|
||||
|
||||
@interface QNServerConfigCache(){
|
||||
QNServerConfig *_config;
|
||||
QNServerUserConfig *_userConfig;
|
||||
}
|
||||
@property(nonatomic, strong) QNCache *configCache;
|
||||
@property(nonatomic, strong) QNCache *userConfigCache;
|
||||
@end
|
||||
@implementation QNServerConfigCache
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
QNCacheOption *option = [[QNCacheOption alloc] init];
|
||||
option.version = @"v1.0.0";
|
||||
self.configCache = [QNCache cache:[QNServerConfig class] option:option];
|
||||
|
||||
option = [[QNCacheOption alloc] init];
|
||||
option.version = @"v1.0.0";
|
||||
self.userConfigCache = [QNCache cache:[QNServerUserConfig class] option:option];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
//MARK: --- config
|
||||
- (QNServerConfig *)getConfigFromDisk {
|
||||
return [self.configCache cacheForKey:kQNServerConfigDiskKey];
|
||||
}
|
||||
|
||||
- (void)saveConfigToDisk:(QNServerConfig *)config {
|
||||
[self.configCache cache:config forKey:kQNServerConfigDiskKey atomically:true];
|
||||
}
|
||||
|
||||
//MARK: --- user config
|
||||
- (QNServerUserConfig *)getUserConfigFromDisk {
|
||||
return [self.userConfigCache cacheForKey:kQNServerUserConfigDiskKey];
|
||||
}
|
||||
|
||||
- (void)saveUserConfigToDisk:(QNServerUserConfig *)config {
|
||||
[self.userConfigCache cache:config forKey:kQNServerUserConfigDiskKey atomically:true];
|
||||
}
|
||||
|
||||
- (void)removeConfigCache {
|
||||
@synchronized (self) {
|
||||
[self.configCache clearMemoryCache];
|
||||
[self.configCache clearDiskCache];
|
||||
[self.userConfigCache clearMemoryCache];
|
||||
[self.userConfigCache clearDiskCache];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
33
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.h
generated
Normal file
33
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.h
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// QNServerConfiguration.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/8/25.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNServerConfigMonitor : NSObject
|
||||
|
||||
@property(nonatomic, assign, class)BOOL enable;
|
||||
|
||||
@property(class, nonatomic, strong)NSString *token;
|
||||
|
||||
// 开始监控
|
||||
+ (void)startMonitor;
|
||||
|
||||
// 停止监控
|
||||
+ (void)endMonitor;
|
||||
|
||||
// 配置 token
|
||||
+ (void)setToken:(NSString *)token;
|
||||
|
||||
// 移除缓存
|
||||
+ (void)removeConfigCache;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
237
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.m
generated
Normal file
237
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigMonitor.m
generated
Normal file
@@ -0,0 +1,237 @@
|
||||
//
|
||||
// QNServerConfiguration.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/8/25.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
#import "QNLogUtil.h"
|
||||
#import "QNDefine.h"
|
||||
#import "QNAutoZone.h"
|
||||
#import "QNDnsPrefetch.h"
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNServerConfigSynchronizer.h"
|
||||
#import "QNServerConfigCache.h"
|
||||
#import "QNServerConfigMonitor.h"
|
||||
#import "QNTransactionManager.h"
|
||||
|
||||
#define kQNServerConfigTransactionKey @"QNServerConfig"
|
||||
|
||||
@interface QNGlobalConfiguration(DnsDefaultServer)
|
||||
@property(nonatomic, strong)NSArray *defaultConnectCheckUrls;
|
||||
@property(nonatomic, strong)NSArray *defaultDohIpv4Servers;
|
||||
@property(nonatomic, strong)NSArray *defaultDohIpv6Servers;
|
||||
@property(nonatomic, strong)NSArray *defaultUdpDnsIpv4Servers;
|
||||
@property(nonatomic, strong)NSArray *defaultUdpDnsIpv6Servers;
|
||||
@end
|
||||
@implementation QNGlobalConfiguration(DnsDefaultServer)
|
||||
@dynamic defaultConnectCheckUrls;
|
||||
@dynamic defaultDohIpv4Servers;
|
||||
@dynamic defaultDohIpv6Servers;
|
||||
@dynamic defaultUdpDnsIpv4Servers;
|
||||
@dynamic defaultUdpDnsIpv6Servers;
|
||||
@end
|
||||
|
||||
@interface QNServerConfigMonitor()
|
||||
|
||||
@property(nonatomic, assign)BOOL enable;
|
||||
@property(nonatomic, strong)QNServerConfigCache *cache;
|
||||
|
||||
@end
|
||||
@implementation QNServerConfigMonitor
|
||||
+ (instancetype)share {
|
||||
static QNServerConfigMonitor *monitor = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
monitor = [[QNServerConfigMonitor alloc] init];
|
||||
});
|
||||
return monitor;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_enable = true;
|
||||
_cache = [[QNServerConfigCache alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)enable {
|
||||
return [[QNServerConfigMonitor share] enable];
|
||||
}
|
||||
|
||||
+ (void)setEnable:(BOOL)enable {
|
||||
[QNServerConfigMonitor share].enable = enable;
|
||||
}
|
||||
|
||||
+ (NSString *)token {
|
||||
return QNServerConfigSynchronizer.token;
|
||||
}
|
||||
|
||||
// 配置 token
|
||||
+ (void)setToken:(NSString *)token {
|
||||
QNServerConfigSynchronizer.token = token;
|
||||
}
|
||||
|
||||
// 开始监控
|
||||
+ (void)startMonitor {
|
||||
if (![QNServerConfigMonitor share].enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
@synchronized (self) {
|
||||
BOOL isExist = [kQNTransactionManager existTransactionsForName:kQNServerConfigTransactionKey];
|
||||
if (isExist) {
|
||||
return;
|
||||
}
|
||||
|
||||
int interval = 120 + arc4random()%240;
|
||||
QNTransaction *transaction = [QNTransaction timeTransaction:kQNServerConfigTransactionKey after:0 interval:interval action:^{
|
||||
[[QNServerConfigMonitor share] monitor];
|
||||
}];
|
||||
[kQNTransactionManager addTransaction:transaction];
|
||||
}
|
||||
}
|
||||
|
||||
// 停止监控
|
||||
+ (void)endMonitor {
|
||||
@synchronized (self) {
|
||||
NSArray *transactions = [kQNTransactionManager transactionsForName:kQNServerConfigTransactionKey];
|
||||
for (QNTransaction *transaction in transactions) {
|
||||
[kQNTransactionManager removeTransaction:transaction];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)removeConfigCache {
|
||||
[[QNServerConfigMonitor share].cache removeConfigCache];
|
||||
}
|
||||
|
||||
- (void)monitor {
|
||||
if (!self.enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.cache.config == nil) {
|
||||
QNServerConfig *config = [self.cache getConfigFromDisk];
|
||||
[self handleServerConfig:config];
|
||||
self.cache.config = config;
|
||||
}
|
||||
|
||||
if (!self.cache.config.isValid) {
|
||||
[QNServerConfigSynchronizer getServerConfigFromServer:^(QNServerConfig * _Nonnull config) {
|
||||
if (config == nil) {
|
||||
return;
|
||||
}
|
||||
[self handleServerConfig:config];
|
||||
self.cache.config = config;
|
||||
[self.cache saveConfigToDisk:config];
|
||||
}];
|
||||
}
|
||||
|
||||
if (self.cache.userConfig == nil) {
|
||||
QNServerUserConfig *config = [self.cache getUserConfigFromDisk];
|
||||
[self handleServerUserConfig:config];
|
||||
self.cache.userConfig = config;
|
||||
}
|
||||
|
||||
if (!self.cache.userConfig.isValid) {
|
||||
[QNServerConfigSynchronizer getServerUserConfigFromServer:^(QNServerUserConfig * _Nonnull config) {
|
||||
if (config == nil) {
|
||||
return;
|
||||
}
|
||||
[self handleServerUserConfig:config];
|
||||
self.cache.userConfig = config;
|
||||
[self.cache saveUserConfigToDisk:config];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleServerConfig:(QNServerConfig *)config {
|
||||
if (config == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 清理 region 缓存
|
||||
if (self.cache.config.regionConfig &&
|
||||
config.regionConfig.clearId > self.cache.config.regionConfig.clearId &&
|
||||
config.regionConfig.clearCache) {
|
||||
QNLogDebug(@"server config: clear region cache");
|
||||
[QNAutoZone clearCache];
|
||||
}
|
||||
|
||||
// dns 配置
|
||||
if (config.dnsConfig.enable) {
|
||||
QNLogDebug(@"server config: dns enable %@", config.dnsConfig.enable);
|
||||
kQNGlobalConfiguration.isDnsOpen = [config.dnsConfig.enable boolValue];
|
||||
}
|
||||
|
||||
// 清理 dns 缓存
|
||||
if (self.cache.config.dnsConfig &&
|
||||
config.dnsConfig.clearId > self.cache.config.dnsConfig.clearId &&
|
||||
config.dnsConfig.clearCache) {
|
||||
QNLogDebug(@"server config: clear dns cache");
|
||||
[kQNDnsPrefetch clearDnsCache:nil];
|
||||
}
|
||||
|
||||
// udp 配置
|
||||
if (config.dnsConfig.udpConfig.enable) {
|
||||
QNLogDebug(@"server config: udp enable %@", config.dnsConfig.udpConfig.enable);
|
||||
kQNGlobalConfiguration.udpDnsEnable = [config.dnsConfig.udpConfig.enable boolValue];
|
||||
}
|
||||
|
||||
if (config.dnsConfig.udpConfig.ipv4Server.isOverride &&
|
||||
[config.dnsConfig.udpConfig.ipv4Server.servers isKindOfClass:[NSArray class]]) {
|
||||
QNLogDebug(@"server config: udp config ipv4Server %@", config.dnsConfig.udpConfig.ipv4Server.servers);
|
||||
kQNGlobalConfiguration.defaultUdpDnsIpv4Servers = [config.dnsConfig.udpConfig.ipv4Server.servers copy];
|
||||
}
|
||||
if (config.dnsConfig.udpConfig.ipv6Server.isOverride &&
|
||||
[config.dnsConfig.udpConfig.ipv6Server.servers isKindOfClass:[NSArray class]]) {
|
||||
QNLogDebug(@"server config: udp config ipv6Server %@", config.dnsConfig.udpConfig.ipv6Server.servers);
|
||||
kQNGlobalConfiguration.defaultUdpDnsIpv6Servers = [config.dnsConfig.udpConfig.ipv6Server.servers copy];
|
||||
}
|
||||
|
||||
// doh 配置
|
||||
if (config.dnsConfig.dohConfig.enable) {
|
||||
kQNGlobalConfiguration.dohEnable = [config.dnsConfig.dohConfig.enable boolValue];
|
||||
QNLogDebug(@"server config: doh enable %@", config.dnsConfig.dohConfig.enable);
|
||||
}
|
||||
if (config.dnsConfig.dohConfig.ipv4Server.isOverride &&
|
||||
[config.dnsConfig.dohConfig.ipv4Server.servers isKindOfClass:[NSArray class]]) {
|
||||
QNLogDebug(@"server config: doh config ipv4Server %@", config.dnsConfig.dohConfig.ipv4Server.servers);
|
||||
kQNGlobalConfiguration.defaultDohIpv4Servers = [config.dnsConfig.dohConfig.ipv4Server.servers copy];
|
||||
}
|
||||
if (config.dnsConfig.dohConfig.ipv6Server.isOverride &&
|
||||
[config.dnsConfig.dohConfig.ipv6Server.servers isKindOfClass:[NSArray class]]) {
|
||||
QNLogDebug(@"server config: doh config ipv6Server %@", config.dnsConfig.dohConfig.ipv6Server.servers);
|
||||
kQNGlobalConfiguration.defaultDohIpv6Servers = [config.dnsConfig.dohConfig.ipv6Server.servers copy];
|
||||
}
|
||||
|
||||
// connect check
|
||||
if (config.connectCheckConfig.enable) {
|
||||
kQNGlobalConfiguration.connectCheckEnable = [config.connectCheckConfig.enable boolValue];
|
||||
QNLogDebug(@"server config: connect check enable %@", config.dnsConfig.dohConfig.enable);
|
||||
}
|
||||
if (config.connectCheckConfig.timeoutMs) {
|
||||
kQNGlobalConfiguration.connectCheckTimeout = [config.connectCheckConfig.timeoutMs doubleValue] / 1000;
|
||||
QNLogDebug(@"server config: connect check timeout %@", config.connectCheckConfig.timeoutMs);
|
||||
}
|
||||
if (config.connectCheckConfig.isOverride &&
|
||||
config.connectCheckConfig.urls &&
|
||||
[config.connectCheckConfig.urls isKindOfClass:[NSArray class]]) {
|
||||
kQNGlobalConfiguration.defaultConnectCheckUrls = config.connectCheckConfig.urls;
|
||||
QNLogDebug(@"server config: connect check urls %@", config.connectCheckConfig.urls);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleServerUserConfig:(QNServerUserConfig *)config {
|
||||
if (config == nil) {
|
||||
return;
|
||||
}
|
||||
if (config.networkCheckEnable) {
|
||||
QNLogDebug(@"server config: connect check enable %@", config.networkCheckEnable);
|
||||
kQNGlobalConfiguration.connectCheckEnable = [config.networkCheckEnable boolValue];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
24
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.h
generated
Normal file
24
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.h
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// QNServerConfigSynchronizer.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/8/30.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNServerConfig.h"
|
||||
#import "QNServerUserConfig.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNServerConfigSynchronizer : NSObject
|
||||
|
||||
@property(class, nonatomic, strong)NSString *token;
|
||||
@property(class, nonatomic, strong)NSArray <NSString *> *hosts;
|
||||
|
||||
+ (void)getServerConfigFromServer:(void(^)(QNServerConfig *config))complete;
|
||||
+ (void)getServerUserConfigFromServer:(void(^)(QNServerUserConfig *config))complete;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
158
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.m
generated
Normal file
158
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerConfigSynchronizer.m
generated
Normal file
@@ -0,0 +1,158 @@
|
||||
//
|
||||
// QNServerConfigSynchronizer.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/8/30.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNConfig.h"
|
||||
#import "QNUpToken.h"
|
||||
#import "QNZoneInfo.h"
|
||||
#import "QNResponseInfo.h"
|
||||
#import "QNRequestTransaction.h"
|
||||
#import "QNServerConfigSynchronizer.h"
|
||||
#import <pthread.h>
|
||||
|
||||
static NSString *Token = nil;
|
||||
static NSArray <NSString *> *Hosts = nil;
|
||||
static pthread_mutex_t TokenMutexLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t HostsMutexLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static QNRequestTransaction *serverConfigTransaction = nil;
|
||||
static QNRequestTransaction *serverUserConfigTransaction = nil;
|
||||
|
||||
@implementation QNServerConfigSynchronizer
|
||||
|
||||
//MARK: --- server config
|
||||
+ (void)getServerConfigFromServer:(void(^)(QNServerConfig *config))complete {
|
||||
if (complete == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
QNRequestTransaction *transaction = [self createServerConfigTransaction];
|
||||
if (transaction == nil) {
|
||||
complete(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
[transaction serverConfig:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
|
||||
if (responseInfo.isOK && response != nil) {
|
||||
complete([QNServerConfig config:response]);
|
||||
} else {
|
||||
complete(nil);
|
||||
}
|
||||
[self destroyServerConfigRequestTransaction];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (QNRequestTransaction *)createServerConfigTransaction {
|
||||
@synchronized (self) {
|
||||
// 上传时才会有 token,不上传不请求,避免不必要请求
|
||||
if (serverConfigTransaction != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
QNUpToken *token = [QNUpToken parse:self.token];
|
||||
if (token == nil) {
|
||||
token = [QNUpToken getInvalidToken];
|
||||
}
|
||||
|
||||
NSArray *hosts = self.hosts;
|
||||
if (hosts == nil) {
|
||||
hosts = kQNPreQueryHosts;
|
||||
}
|
||||
QNRequestTransaction *transaction = [[QNRequestTransaction alloc] initWithHosts:hosts
|
||||
regionId:QNZoneInfoEmptyRegionId
|
||||
token:token];
|
||||
serverConfigTransaction = transaction;
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)destroyServerConfigRequestTransaction {
|
||||
@synchronized (self) {
|
||||
serverConfigTransaction = nil;
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: --- server user config
|
||||
+ (void)getServerUserConfigFromServer:(void(^)(QNServerUserConfig *config))complete {
|
||||
if (complete == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
QNRequestTransaction *transaction = [self createServerUserConfigTransaction];
|
||||
if (transaction == nil) {
|
||||
complete(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
[transaction serverUserConfig:^(QNResponseInfo * _Nullable responseInfo, QNUploadRegionRequestMetrics * _Nullable metrics, NSDictionary * _Nullable response) {
|
||||
if (responseInfo.isOK && response != nil) {
|
||||
complete([QNServerUserConfig config:response]);
|
||||
} else {
|
||||
complete(nil);
|
||||
}
|
||||
[self destroyServerConfigRequestTransaction];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (QNRequestTransaction *)createServerUserConfigTransaction {
|
||||
@synchronized (self) {
|
||||
if (serverConfigTransaction != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
QNUpToken *token = [QNUpToken parse:self.token];
|
||||
if (token == nil || !token.isValid) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *hosts = self.hosts;
|
||||
if (hosts == nil) {
|
||||
hosts = kQNPreQueryHosts;
|
||||
}
|
||||
QNRequestTransaction *transaction = [[QNRequestTransaction alloc] initWithHosts:hosts
|
||||
regionId:QNZoneInfoEmptyRegionId
|
||||
token:token];
|
||||
serverUserConfigTransaction = transaction;
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)destroyServerUserConfigRequestTransaction {
|
||||
@synchronized (self) {
|
||||
serverUserConfigTransaction = nil;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)setToken:(NSString *)token {
|
||||
pthread_mutex_lock(&TokenMutexLock);
|
||||
Token = token;
|
||||
pthread_mutex_unlock(&TokenMutexLock);
|
||||
}
|
||||
|
||||
+ (NSString *)token {
|
||||
NSString *token = nil;
|
||||
pthread_mutex_lock(&TokenMutexLock);
|
||||
token = Token;
|
||||
pthread_mutex_unlock(&TokenMutexLock);
|
||||
return token;
|
||||
}
|
||||
|
||||
+ (void)setHosts:(NSArray<NSString *> *)servers {
|
||||
pthread_mutex_lock(&HostsMutexLock);
|
||||
Hosts = [servers copy];
|
||||
pthread_mutex_unlock(&HostsMutexLock);
|
||||
}
|
||||
|
||||
+ (NSArray<NSString *> *)hosts {
|
||||
NSArray<NSString *> *hosts = nil;
|
||||
pthread_mutex_lock(&HostsMutexLock);
|
||||
hosts = [Hosts copy];
|
||||
pthread_mutex_unlock(&HostsMutexLock);
|
||||
return hosts;
|
||||
}
|
||||
|
||||
@end
|
||||
27
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.h
generated
Normal file
27
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.h
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// QNServerUserConfig.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/8/30.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNCache.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNServerUserConfig : NSObject<QNCacheObject>
|
||||
|
||||
@property(nonatomic, assign, readonly)BOOL isValid;
|
||||
@property(nonatomic, assign, readonly)long ttl;
|
||||
@property(nonatomic, strong, readonly)NSNumber *http3Enable;
|
||||
@property(nonatomic, strong, readonly)NSNumber *networkCheckEnable;
|
||||
|
||||
@property(nonatomic, strong, readonly)NSDictionary *info;
|
||||
|
||||
+ (instancetype)config:(NSDictionary *)info;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
58
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.m
generated
Normal file
58
Pods/Qiniu/QiniuSDK/Storage/ServerConfig/QNServerUserConfig.m
generated
Normal file
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// QNServerUserConfig.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by yangsen on 2021/8/30.
|
||||
// Copyright © 2021 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNServerUserConfig.h"
|
||||
|
||||
@interface QNServerUserConfig()
|
||||
@property(nonatomic, strong)NSDictionary *info;
|
||||
@property(nonatomic, assign)double timestamp;
|
||||
@property(nonatomic, assign)long ttl;
|
||||
@property(nonatomic, strong)NSNumber *http3Enable;
|
||||
@property(nonatomic, strong)NSNumber *retryMax;
|
||||
@property(nonatomic, strong)NSNumber *networkCheckEnable;
|
||||
@end
|
||||
@implementation QNServerUserConfig
|
||||
|
||||
+ (instancetype)config:(NSDictionary *)info {
|
||||
return [[QNServerUserConfig alloc] initWithDictionary:info];
|
||||
}
|
||||
|
||||
- (nonnull id<QNCacheObject>)initWithDictionary:(nullable NSDictionary *)info {
|
||||
if (self = [super init]) {
|
||||
if (info) {
|
||||
self.ttl = [info[@"ttl"] longValue];
|
||||
self.http3Enable = info[@"http3"][@"enabled"];
|
||||
self.networkCheckEnable = info[@"network_check"][@"enabled"];
|
||||
|
||||
if (self.ttl < 10) {
|
||||
self.ttl = 10;
|
||||
}
|
||||
|
||||
NSMutableDictionary *mutableInfo = [info mutableCopy];
|
||||
if (info[@"timestamp"] != nil) {
|
||||
self.timestamp = [info[@"timestamp"] doubleValue];
|
||||
}
|
||||
if (self.timestamp == 0) {
|
||||
self.timestamp = [[NSDate date] timeIntervalSince1970];
|
||||
mutableInfo[@"timestamp"] = @(self.timestamp);
|
||||
}
|
||||
self.info = [mutableInfo copy];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable NSDictionary *)toDictionary {
|
||||
return [self.info copy];
|
||||
}
|
||||
|
||||
- (BOOL)isValid {
|
||||
return [[NSDate date] timeIntervalSince1970] < (self.timestamp + self.ttl);
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user