add .gitignore
This commit is contained in:
205
msext/QiniuSDK/Storage/QNConfiguration.h
Executable file
205
msext/QiniuSDK/Storage/QNConfiguration.h
Executable file
@@ -0,0 +1,205 @@
|
||||
//
|
||||
// QNConfiguration.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 15/5/21.
|
||||
// Copyright (c) 2015年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "QNRecorderDelegate.h"
|
||||
|
||||
/**
|
||||
* 断点上传时的分块大小
|
||||
*/
|
||||
extern const UInt32 kQNBlockSize;
|
||||
|
||||
/**
|
||||
* 转换为用户需要的url
|
||||
*
|
||||
* @param url 上传url
|
||||
*
|
||||
* @return 根据上传url算出代理url
|
||||
*/
|
||||
typedef NSString * (^QNUrlConvert)(NSString *url);
|
||||
|
||||
@class QNConfigurationBuilder;
|
||||
@class QNDnsManager;
|
||||
@class QNServiceAddress;
|
||||
@class QNZone;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 上传失败的重试次数
|
||||
*/
|
||||
@property (readonly) UInt32 retryMax;
|
||||
|
||||
/**
|
||||
* 超时时间 单位 秒
|
||||
*/
|
||||
@property (readonly) UInt32 timeoutInterval;
|
||||
|
||||
@property (nonatomic, readonly) id<QNRecorderDelegate> recorder;
|
||||
|
||||
@property (nonatomic, readonly) QNRecorderKeyGenerator recorderKeyGen;
|
||||
|
||||
@property (nonatomic, readonly) NSDictionary *proxy;
|
||||
|
||||
@property (nonatomic, readonly) QNUrlConvert converter;
|
||||
|
||||
@property (nonatomic, readonly) QNDnsManager *dns;
|
||||
|
||||
@property (readonly) BOOL disableATS;
|
||||
|
||||
+ (instancetype)build:(QNConfigurationBuilderBlock)block;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* 上传服务地址
|
||||
*/
|
||||
@interface QNServiceAddress : NSObject
|
||||
|
||||
- (instancetype)init:(NSString *)address ips:(NSArray *)ips;
|
||||
|
||||
@property (nonatomic, readonly) NSString *address;
|
||||
@property (nonatomic, readonly) NSArray *ips;
|
||||
|
||||
@end
|
||||
|
||||
typedef void (^QNPrequeryReturn)(int code);
|
||||
|
||||
@class QNUpToken;
|
||||
|
||||
@interface QNZone : NSObject
|
||||
|
||||
/**
|
||||
* 默认上传服务器地址
|
||||
*/
|
||||
- (QNServiceAddress *)up:(QNUpToken *)token;
|
||||
|
||||
/**
|
||||
* 备用上传服务器地址
|
||||
*/
|
||||
- (QNServiceAddress *)upBackup:(QNUpToken *)token;
|
||||
|
||||
/**
|
||||
* zone 0 华东
|
||||
*
|
||||
* @return 实例
|
||||
*/
|
||||
+ (instancetype)zone0;
|
||||
|
||||
/**
|
||||
* zone 1 华北
|
||||
*
|
||||
* @return 实例
|
||||
*/
|
||||
+ (instancetype)zone1;
|
||||
|
||||
/**
|
||||
* zone 2 华南
|
||||
*
|
||||
* @return 实例
|
||||
*/
|
||||
+ (instancetype)zone2;
|
||||
|
||||
/**
|
||||
* zone Na0 北美
|
||||
*
|
||||
* @return 实例
|
||||
*/
|
||||
+ (instancetype)zoneNa0;
|
||||
|
||||
- (void)preQuery:(QNUpToken *)token
|
||||
on:(QNPrequeryReturn)ret;
|
||||
|
||||
+ (void)addIpToDns:(QNDnsManager *)dns;
|
||||
|
||||
@end
|
||||
|
||||
@interface QNFixedZone : QNZone
|
||||
/**
|
||||
* Zone初始化方法
|
||||
*
|
||||
* @param upHost 默认上传服务器地址
|
||||
* @param upHostBackup 备用上传服务器地址
|
||||
* @param upIp 备用上传IP
|
||||
*
|
||||
* @return Zone实例
|
||||
*/
|
||||
- (instancetype)initWithUp:(QNServiceAddress *)up
|
||||
upBackup:(QNServiceAddress *)upBackup;
|
||||
|
||||
@end
|
||||
|
||||
@interface QNAutoZone : QNZone
|
||||
|
||||
- (instancetype)initWithHttps:(BOOL)flag
|
||||
dns:(QNDnsManager *)dns;
|
||||
|
||||
@end
|
||||
|
||||
@interface QNConfigurationBuilder : NSObject
|
||||
|
||||
/**
|
||||
* 默认上传服务器地址
|
||||
*/
|
||||
@property (nonatomic, strong) QNZone *zone;
|
||||
|
||||
/**
|
||||
* 断点上传时的分片大小
|
||||
*/
|
||||
@property (assign) UInt32 chunkSize;
|
||||
|
||||
/**
|
||||
* 如果大于此值就使用断点上传,否则使用form上传
|
||||
*/
|
||||
@property (assign) UInt32 putThreshold;
|
||||
|
||||
/**
|
||||
* 上传失败的重试次数
|
||||
*/
|
||||
@property (assign) UInt32 retryMax;
|
||||
|
||||
/**
|
||||
* 超时时间 单位 秒
|
||||
*/
|
||||
@property (assign) UInt32 timeoutInterval;
|
||||
|
||||
@property (nonatomic, strong) id<QNRecorderDelegate> recorder;
|
||||
|
||||
@property (nonatomic, strong) QNRecorderKeyGenerator recorderKeyGen;
|
||||
|
||||
@property (nonatomic, strong) NSDictionary *proxy;
|
||||
|
||||
@property (nonatomic, strong) QNUrlConvert converter;
|
||||
|
||||
@property (nonatomic, strong) QNDnsManager *dns;
|
||||
|
||||
@property (assign) BOOL disableATS;
|
||||
|
||||
@end
|
||||
360
msext/QiniuSDK/Storage/QNConfiguration.m
Executable file
360
msext/QiniuSDK/Storage/QNConfiguration.m
Executable file
@@ -0,0 +1,360 @@
|
||||
//
|
||||
// QNConfiguration.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 15/5/21.
|
||||
// Copyright (c) 2015年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNConfiguration.h"
|
||||
#import "HappyDNS.h"
|
||||
#import "QNNetworkInfo.h"
|
||||
#import "QNResponseInfo.h"
|
||||
#import "QNSessionManager.h"
|
||||
#import "QNSystem.h"
|
||||
#import "QNUpToken.h"
|
||||
|
||||
const UInt32 kQNBlockSize = 4 * 1024 * 1024;
|
||||
|
||||
static void addServiceToDns(QNServiceAddress *address, QNDnsManager *dns) {
|
||||
NSArray *ips = address.ips;
|
||||
if (ips == nil) {
|
||||
return;
|
||||
}
|
||||
NSURL *u = [[NSURL alloc] initWithString:address.address];
|
||||
NSString *host = u.host;
|
||||
for (int i = 0; i < ips.count; i++) {
|
||||
[dns putHosts:host ip:ips[i]];
|
||||
}
|
||||
}
|
||||
|
||||
static void addZoneToDns(QNZone *zone, QNDnsManager *dns) {
|
||||
addServiceToDns([zone up:nil], dns);
|
||||
addServiceToDns([zone upBackup:nil], dns);
|
||||
}
|
||||
|
||||
static QNDnsManager *initDns(QNConfigurationBuilder *builder) {
|
||||
QNDnsManager *d = builder.dns;
|
||||
if (d == nil) {
|
||||
id<QNResolverDelegate> r1 = [QNResolver systemResolver];
|
||||
id<QNResolverDelegate> r2 = [[QNResolver alloc] initWithAddress:@"119.29.29.29"];
|
||||
id<QNResolverDelegate> r3 = [[QNResolver alloc] initWithAddress:@"114.114.115.115"];
|
||||
d = [[QNDnsManager alloc] init:[NSArray arrayWithObjects:r1, r2, r3, nil] networkInfo:[QNNetworkInfo normal]];
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
@implementation QNConfiguration
|
||||
|
||||
+ (instancetype)build:(QNConfigurationBuilderBlock)block {
|
||||
QNConfigurationBuilder *builder = [[QNConfigurationBuilder alloc] init];
|
||||
block(builder);
|
||||
return [[QNConfiguration alloc] initWithBuilder:builder];
|
||||
}
|
||||
|
||||
- (instancetype)initWithBuilder:(QNConfigurationBuilder *)builder {
|
||||
if (self = [super init]) {
|
||||
|
||||
_chunkSize = builder.chunkSize;
|
||||
_putThreshold = builder.putThreshold;
|
||||
_retryMax = builder.retryMax;
|
||||
_timeoutInterval = builder.timeoutInterval;
|
||||
|
||||
_recorder = builder.recorder;
|
||||
_recorderKeyGen = builder.recorderKeyGen;
|
||||
|
||||
_proxy = builder.proxy;
|
||||
|
||||
_converter = builder.converter;
|
||||
|
||||
_disableATS = builder.disableATS;
|
||||
if (_disableATS) {
|
||||
_dns = initDns(builder);
|
||||
[QNZone addIpToDns:_dns];
|
||||
} else {
|
||||
_dns = nil;
|
||||
}
|
||||
_zone = builder.zone;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNConfigurationBuilder
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_zone = [QNZone zone0];
|
||||
_chunkSize = 256 * 1024;
|
||||
_putThreshold = 512 * 1024;
|
||||
_retryMax = 2;
|
||||
_timeoutInterval = 60;
|
||||
|
||||
_recorder = nil;
|
||||
_recorderKeyGen = nil;
|
||||
|
||||
_proxy = nil;
|
||||
_converter = nil;
|
||||
|
||||
if (hasAts() && !allowsArbitraryLoads()) {
|
||||
_disableATS = NO;
|
||||
} else {
|
||||
_disableATS = YES;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNServiceAddress : NSObject
|
||||
|
||||
- (instancetype)init:(NSString *)address ips:(NSArray *)ips {
|
||||
if (self = [super init]) {
|
||||
_address = address;
|
||||
_ips = ips;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNFixedZone {
|
||||
QNServiceAddress *up;
|
||||
QNServiceAddress *upBackup;
|
||||
}
|
||||
|
||||
/**
|
||||
* 备用上传服务器地址
|
||||
*/
|
||||
- (QNServiceAddress *)upBackup:(NSString *)token {
|
||||
return upBackup;
|
||||
}
|
||||
|
||||
- (QNServiceAddress *)up:(NSString *)token {
|
||||
return up;
|
||||
}
|
||||
|
||||
- (instancetype)initWithUp:(QNServiceAddress *)up1
|
||||
upBackup:(QNServiceAddress *)upBackup1 {
|
||||
if (self = [super init]) {
|
||||
up = up1;
|
||||
upBackup = upBackup1;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface QNAutoZoneInfo : NSObject
|
||||
@property (readonly, nonatomic) NSString *upHost;
|
||||
@property (readonly, nonatomic) NSString *upIp;
|
||||
@property (readonly, nonatomic) NSString *upBackup;
|
||||
@property (readonly, nonatomic) NSString *upHttps;
|
||||
|
||||
- (instancetype)init:(NSString *)uphost
|
||||
upIp:(NSString *)upip
|
||||
upBackup:(NSString *)upbackup
|
||||
upHttps:(NSString *)uphttps;
|
||||
@end
|
||||
|
||||
@implementation QNAutoZoneInfo
|
||||
|
||||
- (instancetype)init:(NSString *)uphost
|
||||
upIp:(NSString *)upip
|
||||
upBackup:(NSString *)upbackup
|
||||
upHttps:(NSString *)uphttps {
|
||||
if (self = [super init]) {
|
||||
_upHost = uphost;
|
||||
_upIp = upip;
|
||||
_upBackup = upbackup;
|
||||
_upHttps = uphttps;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNAutoZone {
|
||||
NSString *server;
|
||||
BOOL https;
|
||||
NSMutableDictionary *cache;
|
||||
NSLock *lock;
|
||||
QNSessionManager *sesionManager;
|
||||
QNDnsManager *dns;
|
||||
}
|
||||
|
||||
- (instancetype)initWithHttps:(BOOL)flag
|
||||
dns:(QNDnsManager *)dns1 {
|
||||
if (self = [super init]) {
|
||||
dns = dns1;
|
||||
server = @"https://uc.qbox.me";
|
||||
https = flag;
|
||||
cache = [NSMutableDictionary new];
|
||||
lock = [NSLock new];
|
||||
sesionManager = [[QNSessionManager alloc] initWithProxy:nil timeout:10 urlConverter:nil dns:dns];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (QNServiceAddress *)upBackup:(QNUpToken *)token {
|
||||
NSString *index = [token index];
|
||||
[lock lock];
|
||||
QNAutoZoneInfo *info = [cache objectForKey:index];
|
||||
[lock unlock];
|
||||
if (info == nil) {
|
||||
return nil;
|
||||
}
|
||||
if (https) {
|
||||
return [[QNServiceAddress alloc] init:info.upHttps ips:@[ info.upIp ]];
|
||||
}
|
||||
return [[QNServiceAddress alloc] init:info.upBackup ips:@[ info.upIp ]];
|
||||
}
|
||||
|
||||
- (QNServiceAddress *)up:(QNUpToken *)token {
|
||||
NSString *index = [token index];
|
||||
[lock lock];
|
||||
QNAutoZoneInfo *info = [cache objectForKey:index];
|
||||
[lock unlock];
|
||||
if (info == nil) {
|
||||
return nil;
|
||||
}
|
||||
if (https) {
|
||||
return [[QNServiceAddress alloc] init:info.upHttps ips:@[ info.upIp ]];
|
||||
}
|
||||
return [[QNServiceAddress alloc] init:info.upHost ips:@[ info.upIp ]];
|
||||
}
|
||||
|
||||
- (QNAutoZoneInfo *)buildInfoFromJson:(NSDictionary *)resp {
|
||||
NSDictionary *http = [resp objectForKey:@"http"];
|
||||
NSArray *up = [http objectForKey:@"up"];
|
||||
NSString *upHost = [up objectAtIndex:1];
|
||||
NSString *upBackup = [up objectAtIndex:0];
|
||||
NSString *ipTemp = [up objectAtIndex:2];
|
||||
NSArray *a1 = [ipTemp componentsSeparatedByString:@" "];
|
||||
NSString *ip1 = [a1 objectAtIndex:2];
|
||||
NSArray *a2 = [ip1 componentsSeparatedByString:@"//"];
|
||||
NSString *upIp = [a2 objectAtIndex:1];
|
||||
NSDictionary *https_ = [resp objectForKey:@"https"];
|
||||
NSArray *a3 = [https_ objectForKey:@"up"];
|
||||
NSString *upHttps = [a3 objectAtIndex:0];
|
||||
return [[QNAutoZoneInfo alloc] init:upHost upIp:upIp upBackup:upBackup upHttps:upHttps];
|
||||
}
|
||||
|
||||
- (void)preQuery:(QNUpToken *)token
|
||||
on:(QNPrequeryReturn)ret {
|
||||
if (token == nil) {
|
||||
ret(-1);
|
||||
}
|
||||
[lock lock];
|
||||
QNAutoZoneInfo *info = [cache objectForKey:[token index]];
|
||||
[lock unlock];
|
||||
if (info != nil) {
|
||||
ret(0);
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *url = [NSString stringWithFormat:@"%@/v1/query?ak=%@&bucket=%@", server, token.access, token.bucket];
|
||||
[sesionManager get:url withHeaders:nil withCompleteBlock:^(QNResponseInfo *info, NSDictionary *resp) {
|
||||
if ([info isOK]) {
|
||||
QNAutoZoneInfo *info = [self buildInfoFromJson:resp];
|
||||
if (info == nil) {
|
||||
ret(kQNInvalidToken);
|
||||
} else {
|
||||
ret(0);
|
||||
[lock lock];
|
||||
[cache setValue:info forKey:[token index]];
|
||||
[lock unlock];
|
||||
if (dns != nil) {
|
||||
QNServiceAddress *address = [[QNServiceAddress alloc] init:info.upHttps ips:@[ info.upIp ]];
|
||||
addServiceToDns(address, dns);
|
||||
address = [[QNServiceAddress alloc] init:info.upHost ips:@[ info.upIp ]];
|
||||
addServiceToDns(address, dns);
|
||||
address = [[QNServiceAddress alloc] init:info.upBackup ips:@[ info.upIp ]];
|
||||
addServiceToDns(address, dns);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret(kQNNetworkError);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNZone
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* 备用上传服务器地址
|
||||
*/
|
||||
- (QNServiceAddress *)upBackup:(QNUpToken *)token {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (QNServiceAddress *)up:(QNUpToken *)token {
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (instancetype)createWithHost:(NSString *)up backupHost:(NSString *)backup ip1:(NSString *)ip1 ip2:(NSString *)ip2 {
|
||||
NSArray *ips = [NSArray arrayWithObjects:ip1, ip2, nil];
|
||||
NSString *a = [NSString stringWithFormat:@"http://%@", up];
|
||||
QNServiceAddress *s1 = [[QNServiceAddress alloc] init:a ips:ips];
|
||||
NSString *b = [NSString stringWithFormat:@"http://%@", backup];
|
||||
QNServiceAddress *s2 = [[QNServiceAddress alloc] init:b ips:ips];
|
||||
return [[QNFixedZone alloc] initWithUp:s1 upBackup:s2];
|
||||
}
|
||||
|
||||
+ (instancetype)zone0 {
|
||||
static QNZone *z0 = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
z0 = [QNZone createWithHost:@"upload.qiniu.com" backupHost:@"up.qiniu.com" ip1:@"183.136.139.10" ip2:@"115.231.182.136"];
|
||||
});
|
||||
return z0;
|
||||
}
|
||||
|
||||
+ (instancetype)zone1 {
|
||||
static QNZone *z1 = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
z1 = [QNZone createWithHost:@"upload-z1.qiniu.com" backupHost:@"up-z1.qiniu.com" ip1:@"106.38.227.28" ip2:@"106.38.227.27"];
|
||||
});
|
||||
return z1;
|
||||
}
|
||||
|
||||
+ (instancetype)zone2 {
|
||||
static QNZone *z2 = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
z2 = [QNZone createWithHost:@"upload-z2.qiniu.com" backupHost:@"up-z2.qiniu.com" ip1:@"14.152.37.7" ip2:@"183.60.214.199"];
|
||||
});
|
||||
return z2;
|
||||
}
|
||||
|
||||
+ (instancetype)zoneNa0 {
|
||||
static QNZone *zNa0 = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
zNa0 = [QNZone createWithHost:@"upload-na0.qiniu.com" backupHost:@"up-na0.qiniu.com" ip1:@"14.152.37.7" ip2:@"183.60.214.199"];
|
||||
});
|
||||
return zNa0;
|
||||
}
|
||||
|
||||
+ (void)addIpToDns:(QNDnsManager *)dns {
|
||||
addZoneToDns([QNZone zone0], dns);
|
||||
addZoneToDns([QNZone zone1], dns);
|
||||
addZoneToDns([QNZone zone2], dns);
|
||||
}
|
||||
|
||||
- (void)preQuery:(QNUpToken *)token
|
||||
on:(QNPrequeryReturn)ret {
|
||||
ret(0);
|
||||
}
|
||||
|
||||
@end
|
||||
26
msext/QiniuSDK/Storage/QNFormUpload.h
Executable file
26
msext/QiniuSDK/Storage/QNFormUpload.h
Executable file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// QNFormUpload.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 15/1/4.
|
||||
// Copyright (c) 2015年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNHttpDelegate.h"
|
||||
#import "QNUpToken.h"
|
||||
#import "QNUploadManager.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface QNFormUpload : NSObject
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data
|
||||
withKey:(NSString *)key
|
||||
withToken:(QNUpToken *)token
|
||||
withCompletionHandler:(QNUpCompletionHandler)block
|
||||
withOption:(QNUploadOption *)option
|
||||
withHttpManager:(id<QNHttpDelegate>)http
|
||||
withConfiguration:(QNConfiguration *)config;
|
||||
|
||||
- (void)put;
|
||||
|
||||
@end
|
||||
133
msext/QiniuSDK/Storage/QNFormUpload.m
Executable file
133
msext/QiniuSDK/Storage/QNFormUpload.m
Executable file
@@ -0,0 +1,133 @@
|
||||
//
|
||||
// QNFormUpload.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 15/1/4.
|
||||
// Copyright (c) 2015年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNFormUpload.h"
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNCrc32.h"
|
||||
#import "QNRecorderDelegate.h"
|
||||
#import "QNResponseInfo.h"
|
||||
#import "QNUploadManager.h"
|
||||
#import "QNUploadOption+Private.h"
|
||||
#import "QNUrlSafeBase64.h"
|
||||
|
||||
@interface QNFormUpload ()
|
||||
|
||||
@property (nonatomic, strong) NSData *data;
|
||||
@property (nonatomic, strong) id<QNHttpDelegate> httpManager;
|
||||
@property (nonatomic) int retryTimes;
|
||||
@property (nonatomic, strong) NSString *key;
|
||||
@property (nonatomic, strong) QNUpToken *token;
|
||||
@property (nonatomic, strong) QNUploadOption *option;
|
||||
@property (nonatomic, strong) QNUpCompletionHandler complete;
|
||||
@property (nonatomic, strong) QNConfiguration *config;
|
||||
@property (nonatomic) float previousPercent;
|
||||
|
||||
@property (nonatomic, strong) NSString *access; //AK
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNFormUpload
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data
|
||||
withKey:(NSString *)key
|
||||
withToken:(QNUpToken *)token
|
||||
withCompletionHandler:(QNUpCompletionHandler)block
|
||||
withOption:(QNUploadOption *)option
|
||||
withHttpManager:(id<QNHttpDelegate>)http
|
||||
withConfiguration:(QNConfiguration *)config {
|
||||
if (self = [super init]) {
|
||||
_data = data;
|
||||
_key = key;
|
||||
_token = token;
|
||||
_option = option != nil ? option : [QNUploadOption defaultOptions];
|
||||
_complete = block;
|
||||
_httpManager = http;
|
||||
_config = config;
|
||||
_previousPercent = 0;
|
||||
_access = token.access;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)put {
|
||||
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
|
||||
NSString *fileName = _key;
|
||||
if (_key) {
|
||||
parameters[@"key"] = _key;
|
||||
} else {
|
||||
fileName = @"?";
|
||||
}
|
||||
|
||||
parameters[@"token"] = _token.token;
|
||||
|
||||
[parameters addEntriesFromDictionary:_option.params];
|
||||
|
||||
if (_option.checkCrc) {
|
||||
parameters[@"crc32"] = [NSString stringWithFormat:@"%u", (unsigned int)[QNCrc32 data:_data]];
|
||||
}
|
||||
|
||||
QNInternalProgressBlock p = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) {
|
||||
float percent = (float)totalBytesWritten / (float)totalBytesExpectedToWrite;
|
||||
if (percent > 0.95) {
|
||||
percent = 0.95;
|
||||
}
|
||||
if (percent > _previousPercent) {
|
||||
_previousPercent = percent;
|
||||
} else {
|
||||
percent = _previousPercent;
|
||||
}
|
||||
_option.progressHandler(_key, percent);
|
||||
};
|
||||
|
||||
QNCompleteBlock complete = ^(QNResponseInfo *info, NSDictionary *resp) {
|
||||
if (info.isOK) {
|
||||
_option.progressHandler(_key, 1.0);
|
||||
}
|
||||
if (info.isOK || !info.couldRetry) {
|
||||
_complete(info, _key, resp);
|
||||
return;
|
||||
}
|
||||
if (_option.cancellationSignal()) {
|
||||
_complete([QNResponseInfo cancel], _key, nil);
|
||||
return;
|
||||
}
|
||||
NSString *nextHost = [_config.zone up:_token].address;
|
||||
if (info.isConnectionBroken || info.needSwitchServer) {
|
||||
nextHost = [_config.zone upBackup:_token].address;
|
||||
}
|
||||
|
||||
QNCompleteBlock retriedComplete = ^(QNResponseInfo *info, NSDictionary *resp) {
|
||||
if (info.isOK) {
|
||||
_option.progressHandler(_key, 1.0);
|
||||
}
|
||||
_complete(info, _key, resp);
|
||||
};
|
||||
|
||||
[_httpManager multipartPost:nextHost
|
||||
withData:_data
|
||||
withParams:parameters
|
||||
withFileName:fileName
|
||||
withMimeType:_option.mimeType
|
||||
withCompleteBlock:retriedComplete
|
||||
withProgressBlock:p
|
||||
withCancelBlock:_option.cancellationSignal
|
||||
withAccess:_access];
|
||||
};
|
||||
|
||||
[_httpManager multipartPost:[_config.zone up:_token].address
|
||||
withData:_data
|
||||
withParams:parameters
|
||||
withFileName:fileName
|
||||
withMimeType:_option.mimeType
|
||||
withCompleteBlock:complete
|
||||
withProgressBlock:p
|
||||
withCancelBlock:_option.cancellationSignal
|
||||
withAccess:_access];
|
||||
}
|
||||
|
||||
@end
|
||||
29
msext/QiniuSDK/Storage/QNResumeUpload.h
Executable file
29
msext/QiniuSDK/Storage/QNResumeUpload.h
Executable file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// QNResumeUpload.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14/10/1.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNFileDelegate.h"
|
||||
#import "QNHttpDelegate.h"
|
||||
#import "QNUpToken.h"
|
||||
#import "QNUploadManager.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface QNResumeUpload : NSObject
|
||||
|
||||
- (instancetype)initWithFile:(id<QNFileDelegate>)file
|
||||
withKey:(NSString *)key
|
||||
withToken:(QNUpToken *)token
|
||||
withCompletionHandler:(QNUpCompletionHandler)block
|
||||
withOption:(QNUploadOption *)option
|
||||
withRecorder:(id<QNRecorderDelegate>)recorder
|
||||
withRecorderKey:(NSString *)recorderKey
|
||||
withHttpManager:(id<QNHttpDelegate>)http
|
||||
withConfiguration:(QNConfiguration *)config;
|
||||
|
||||
- (void)run;
|
||||
|
||||
@end
|
||||
337
msext/QiniuSDK/Storage/QNResumeUpload.m
Executable file
337
msext/QiniuSDK/Storage/QNResumeUpload.m
Executable file
@@ -0,0 +1,337 @@
|
||||
//
|
||||
// QNResumeUpload.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14/10/1.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNResumeUpload.h"
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNCrc32.h"
|
||||
#import "QNRecorderDelegate.h"
|
||||
#import "QNResponseInfo.h"
|
||||
#import "QNUploadManager.h"
|
||||
#import "QNUploadOption+Private.h"
|
||||
#import "QNUrlSafeBase64.h"
|
||||
|
||||
typedef void (^task)(void);
|
||||
|
||||
@interface QNResumeUpload ()
|
||||
|
||||
@property (nonatomic, strong) id<QNHttpDelegate> httpManager;
|
||||
@property UInt32 size;
|
||||
@property (nonatomic) int retryTimes;
|
||||
@property (nonatomic, strong) NSString *key;
|
||||
@property (nonatomic, strong) NSString *recorderKey;
|
||||
@property (nonatomic) NSDictionary *headers;
|
||||
@property (nonatomic, strong) QNUploadOption *option;
|
||||
@property (nonatomic, strong) QNUpToken *token;
|
||||
@property (nonatomic, strong) QNUpCompletionHandler complete;
|
||||
@property (nonatomic, strong) NSMutableArray *contexts;
|
||||
|
||||
@property int64_t modifyTime;
|
||||
@property (nonatomic, strong) id<QNRecorderDelegate> recorder;
|
||||
|
||||
@property (nonatomic, strong) QNConfiguration *config;
|
||||
|
||||
@property UInt32 chunkCrc;
|
||||
|
||||
@property (nonatomic, strong) id<QNFileDelegate> file;
|
||||
|
||||
//@property (nonatomic, strong) NSArray *fileAry;
|
||||
|
||||
@property (nonatomic) float previousPercent;
|
||||
|
||||
@property (nonatomic, strong) NSString *access; //AK
|
||||
|
||||
- (void)makeBlock:(NSString *)uphost
|
||||
offset:(UInt32)offset
|
||||
blockSize:(UInt32)blockSize
|
||||
chunkSize:(UInt32)chunkSize
|
||||
progress:(QNInternalProgressBlock)progressBlock
|
||||
complete:(QNCompleteBlock)complete;
|
||||
|
||||
- (void)putChunk:(NSString *)uphost
|
||||
offset:(UInt32)offset
|
||||
size:(UInt32)size
|
||||
context:(NSString *)context
|
||||
progress:(QNInternalProgressBlock)progressBlock
|
||||
complete:(QNCompleteBlock)complete;
|
||||
|
||||
- (void)makeFile:(NSString *)uphost
|
||||
complete:(QNCompleteBlock)complete;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNResumeUpload
|
||||
|
||||
- (instancetype)initWithFile:(id<QNFileDelegate>)file
|
||||
withKey:(NSString *)key
|
||||
withToken:(QNUpToken *)token
|
||||
withCompletionHandler:(QNUpCompletionHandler)block
|
||||
withOption:(QNUploadOption *)option
|
||||
withRecorder:(id<QNRecorderDelegate>)recorder
|
||||
withRecorderKey:(NSString *)recorderKey
|
||||
withHttpManager:(id<QNHttpDelegate>)http
|
||||
withConfiguration:(QNConfiguration *)config;
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_file = file;
|
||||
_size = (UInt32)[file size];
|
||||
_key = key;
|
||||
NSString *tokenUp = [NSString stringWithFormat:@"UpToken %@", token.token];
|
||||
_option = option != nil ? option : [QNUploadOption defaultOptions];
|
||||
_complete = block;
|
||||
_headers = @{@"Authorization" : tokenUp, @"Content-Type" : @"application/octet-stream"};
|
||||
_recorder = recorder;
|
||||
_httpManager = http;
|
||||
_modifyTime = [file modifyTime];
|
||||
_recorderKey = recorderKey;
|
||||
_contexts = [[NSMutableArray alloc] initWithCapacity:(_size + kQNBlockSize - 1) / kQNBlockSize];
|
||||
_config = config;
|
||||
|
||||
_token = token;
|
||||
_previousPercent = 0;
|
||||
|
||||
_access = token.access;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// save json value
|
||||
//{
|
||||
// "size":filesize,
|
||||
// "offset":lastSuccessOffset,
|
||||
// "modify_time": lastFileModifyTime,
|
||||
// "contexts": contexts
|
||||
//}
|
||||
|
||||
- (void)record:(UInt32)offset {
|
||||
NSString *key = self.recorderKey;
|
||||
if (offset == 0 || _recorder == nil || key == nil || [key isEqualToString:@""]) {
|
||||
return;
|
||||
}
|
||||
NSNumber *n_size = @(self.size);
|
||||
NSNumber *n_offset = @(offset);
|
||||
NSNumber *n_time = [NSNumber numberWithLongLong:_modifyTime];
|
||||
NSMutableDictionary *rec = [NSMutableDictionary dictionaryWithObjectsAndKeys:n_size, @"size", n_offset, @"offset", n_time, @"modify_time", _contexts, @"contexts", nil];
|
||||
|
||||
NSError *error;
|
||||
NSData *data = [NSJSONSerialization dataWithJSONObject:rec options:NSJSONWritingPrettyPrinted error:&error];
|
||||
if (error != nil) {
|
||||
NSLog(@"up record json error %@ %@", key, error);
|
||||
return;
|
||||
}
|
||||
error = [_recorder set:key data:data];
|
||||
if (error != nil) {
|
||||
NSLog(@"up record set error %@ %@", key, error);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeRecord {
|
||||
if (_recorder == nil) {
|
||||
return;
|
||||
}
|
||||
[_recorder del:self.recorderKey];
|
||||
}
|
||||
|
||||
- (UInt32)recoveryFromRecord {
|
||||
NSString *key = self.recorderKey;
|
||||
if (_recorder == nil || key == nil || [key isEqualToString:@""]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NSData *data = [_recorder get:key];
|
||||
if (data == nil) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NSError *error;
|
||||
NSDictionary *info = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
|
||||
if (error != nil) {
|
||||
NSLog(@"recovery error %@ %@", key, error);
|
||||
[_recorder del:self.key];
|
||||
return 0;
|
||||
}
|
||||
NSNumber *n_offset = info[@"offset"];
|
||||
NSNumber *n_size = info[@"size"];
|
||||
NSNumber *time = info[@"modify_time"];
|
||||
NSArray *contexts = info[@"contexts"];
|
||||
if (n_offset == nil || n_size == nil || time == nil || contexts == nil) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
UInt32 offset = [n_offset unsignedIntValue];
|
||||
UInt32 size = [n_size unsignedIntValue];
|
||||
if (offset > size || size != self.size) {
|
||||
return 0;
|
||||
}
|
||||
UInt64 t = [time unsignedLongLongValue];
|
||||
if (t != _modifyTime) {
|
||||
NSLog(@"modify time changed %llu, %llu", t, _modifyTime);
|
||||
return 0;
|
||||
}
|
||||
_contexts = [[NSMutableArray alloc] initWithArray:contexts copyItems:true];
|
||||
return offset;
|
||||
}
|
||||
|
||||
- (void)nextTask:(UInt32)offset retriedTimes:(int)retried host:(NSString *)host {
|
||||
if (self.option.cancellationSignal()) {
|
||||
self.complete([QNResponseInfo cancel], self.key, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset == self.size) {
|
||||
QNCompleteBlock completionHandler = ^(QNResponseInfo *info, NSDictionary *resp) {
|
||||
if (info.isOK) {
|
||||
[self removeRecord];
|
||||
self.option.progressHandler(self.key, 1.0);
|
||||
} else if (info.couldRetry && retried < _config.retryMax) {
|
||||
[self nextTask:offset retriedTimes:retried + 1 host:host];
|
||||
return;
|
||||
}
|
||||
self.complete(info, self.key, resp);
|
||||
};
|
||||
[self makeFile:host complete:completionHandler];
|
||||
return;
|
||||
}
|
||||
|
||||
UInt32 chunkSize = [self calcPutSize:offset];
|
||||
QNInternalProgressBlock progressBlock = ^(long long totalBytesWritten, long long totalBytesExpectedToWrite) {
|
||||
float percent = (float)(offset + totalBytesWritten) / (float)self.size;
|
||||
if (percent > 0.95) {
|
||||
percent = 0.95;
|
||||
}
|
||||
if (percent > _previousPercent) {
|
||||
_previousPercent = percent;
|
||||
} else {
|
||||
percent = _previousPercent;
|
||||
}
|
||||
self.option.progressHandler(self.key, percent);
|
||||
};
|
||||
|
||||
QNCompleteBlock completionHandler = ^(QNResponseInfo *info, NSDictionary *resp) {
|
||||
if (info.error != nil) {
|
||||
if (info.statusCode == 701) {
|
||||
[self nextTask:(offset / kQNBlockSize) * kQNBlockSize retriedTimes:0 host:host];
|
||||
return;
|
||||
}
|
||||
if (retried >= _config.retryMax || !info.couldRetry) {
|
||||
self.complete(info, self.key, resp);
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *nextHost = host;
|
||||
if (info.isConnectionBroken || info.needSwitchServer) {
|
||||
nextHost = [_config.zone upBackup:_token].address;
|
||||
}
|
||||
|
||||
[self nextTask:offset retriedTimes:retried + 1 host:nextHost];
|
||||
return;
|
||||
}
|
||||
|
||||
if (resp == nil) {
|
||||
[self nextTask:offset retriedTimes:retried host:host];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *ctx = resp[@"ctx"];
|
||||
NSNumber *crc = resp[@"crc32"];
|
||||
if (ctx == nil || crc == nil || [crc unsignedLongValue] != _chunkCrc) {
|
||||
[self nextTask:offset retriedTimes:retried host:host];
|
||||
return;
|
||||
}
|
||||
_contexts[offset / kQNBlockSize] = ctx;
|
||||
[self record:offset + chunkSize];
|
||||
[self nextTask:offset + chunkSize retriedTimes:retried host:host];
|
||||
};
|
||||
if (offset % kQNBlockSize == 0) {
|
||||
UInt32 blockSize = [self calcBlockSize:offset];
|
||||
[self makeBlock:host offset:offset blockSize:blockSize chunkSize:chunkSize progress:progressBlock complete:completionHandler];
|
||||
return;
|
||||
}
|
||||
NSString *context = _contexts[offset / kQNBlockSize];
|
||||
[self putChunk:host offset:offset size:chunkSize context:context progress:progressBlock complete:completionHandler];
|
||||
}
|
||||
|
||||
- (UInt32)calcPutSize:(UInt32)offset {
|
||||
UInt32 left = self.size - offset;
|
||||
return left < _config.chunkSize ? left : _config.chunkSize;
|
||||
}
|
||||
|
||||
- (UInt32)calcBlockSize:(UInt32)offset {
|
||||
UInt32 left = self.size - offset;
|
||||
return left < kQNBlockSize ? left : kQNBlockSize;
|
||||
}
|
||||
|
||||
- (void)makeBlock:(NSString *)uphost
|
||||
offset:(UInt32)offset
|
||||
blockSize:(UInt32)blockSize
|
||||
chunkSize:(UInt32)chunkSize
|
||||
progress:(QNInternalProgressBlock)progressBlock
|
||||
complete:(QNCompleteBlock)complete {
|
||||
NSData *data = [self.file read:offset size:chunkSize];
|
||||
NSString *url = [[NSString alloc] initWithFormat:@"%@/mkblk/%u", uphost, (unsigned int)blockSize];
|
||||
_chunkCrc = [QNCrc32 data:data];
|
||||
[self post:url withData:data withCompleteBlock:complete withProgressBlock:progressBlock];
|
||||
}
|
||||
|
||||
- (void)putChunk:(NSString *)uphost
|
||||
offset:(UInt32)offset
|
||||
size:(UInt32)size
|
||||
context:(NSString *)context
|
||||
progress:(QNInternalProgressBlock)progressBlock
|
||||
complete:(QNCompleteBlock)complete {
|
||||
NSData *data = [self.file read:offset size:size];
|
||||
UInt32 chunkOffset = offset % kQNBlockSize;
|
||||
NSString *url = [[NSString alloc] initWithFormat:@"%@/bput/%@/%u", uphost, context, (unsigned int)chunkOffset];
|
||||
_chunkCrc = [QNCrc32 data:data];
|
||||
[self post:url withData:data withCompleteBlock:complete withProgressBlock:progressBlock];
|
||||
}
|
||||
|
||||
- (void)makeFile:(NSString *)uphost
|
||||
complete:(QNCompleteBlock)complete {
|
||||
NSString *mime = [[NSString alloc] initWithFormat:@"/mimeType/%@", [QNUrlSafeBase64 encodeString:self.option.mimeType]];
|
||||
|
||||
__block NSString *url = [[NSString alloc] initWithFormat:@"%@/mkfile/%u%@", uphost, (unsigned int)self.size, mime];
|
||||
|
||||
if (self.key != nil) {
|
||||
NSString *keyStr = [[NSString alloc] initWithFormat:@"/key/%@", [QNUrlSafeBase64 encodeString:self.key]];
|
||||
url = [NSString stringWithFormat:@"%@%@", url, keyStr];
|
||||
}
|
||||
|
||||
[self.option.params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
|
||||
url = [NSString stringWithFormat:@"%@/%@/%@", url, key, [QNUrlSafeBase64 encodeString:obj]];
|
||||
}];
|
||||
|
||||
//添加路径
|
||||
NSString *fname = [[NSString alloc] initWithFormat:@"/fname/%@", [QNUrlSafeBase64 encodeString:[self fileBaseName]]];
|
||||
url = [NSString stringWithFormat:@"%@%@", url, fname];
|
||||
|
||||
NSMutableData *postData = [NSMutableData data];
|
||||
NSString *bodyStr = [self.contexts componentsJoinedByString:@","];
|
||||
[postData appendData:[bodyStr dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[self post:url withData:postData withCompleteBlock:complete withProgressBlock:nil];
|
||||
}
|
||||
|
||||
#pragma mark - 处理文件路径
|
||||
- (NSString *)fileBaseName {
|
||||
return [[_file path] lastPathComponent];
|
||||
}
|
||||
|
||||
- (void)post:(NSString *)url
|
||||
withData:(NSData *)data
|
||||
withCompleteBlock:(QNCompleteBlock)completeBlock
|
||||
withProgressBlock:(QNInternalProgressBlock)progressBlock {
|
||||
[_httpManager post:url withData:data withParams:nil withHeaders:_headers withCompleteBlock:completeBlock withProgressBlock:progressBlock withCancelBlock:_option.cancellationSignal withAccess:_access];
|
||||
}
|
||||
|
||||
- (void)run {
|
||||
@autoreleasepool {
|
||||
UInt32 offset = [self recoveryFromRecord];
|
||||
[self nextTask:offset retriedTimes:0 host:[_config.zone up:_token].address];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
23
msext/QiniuSDK/Storage/QNUpToken.h
Executable file
23
msext/QiniuSDK/Storage/QNUpToken.h
Executable file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// 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 (copy, nonatomic, readonly) NSString *access;
|
||||
@property (copy, nonatomic, readonly) NSString *bucket;
|
||||
@property (copy, nonatomic, readonly) NSString *token;
|
||||
|
||||
@property (readonly) BOOL hasReturnUrl;
|
||||
|
||||
- (NSString *)index;
|
||||
|
||||
@end
|
||||
73
msext/QiniuSDK/Storage/QNUpToken.m
Executable file
73
msext/QiniuSDK/Storage/QNUpToken.m
Executable file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// QNUpToken.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 15/6/7.
|
||||
// Copyright (c) 2015年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUrlSafeBase64.h"
|
||||
#import "QNUpToken.h"
|
||||
|
||||
@interface QNUpToken ()
|
||||
|
||||
- (instancetype)init:(NSDictionary *)policy token:(NSString *)token;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNUpToken
|
||||
|
||||
- (instancetype)init:(NSDictionary *)policy token:(NSString *)token {
|
||||
if (self = [super init]) {
|
||||
_token = token;
|
||||
_access = [self getAccess];
|
||||
_bucket = [self getBucket:policy];
|
||||
_hasReturnUrl = (policy[@"returnUrl"] != nil);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)getAccess {
|
||||
|
||||
NSRange range = [_token rangeOfString:@":" options:NSCaseInsensitiveSearch];
|
||||
return [_token substringToIndex:range.location];
|
||||
}
|
||||
|
||||
- (NSString *)getBucket:(NSDictionary *)info {
|
||||
|
||||
NSString *scope = [info objectForKey:@"scope"];
|
||||
if (!scope) {
|
||||
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]];
|
||||
NSError *tmp = nil;
|
||||
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&tmp];
|
||||
if (tmp != nil || dict[@"scope"] == nil || dict[@"deadline"] == nil) {
|
||||
return nil;
|
||||
}
|
||||
return [[QNUpToken alloc] init:dict token:token];
|
||||
}
|
||||
|
||||
- (NSString *)index {
|
||||
return [NSString stringWithFormat:@"%@:%@", _access, _bucket];
|
||||
}
|
||||
|
||||
@end
|
||||
155
msext/QiniuSDK/Storage/QNUploadManager.h
Executable file
155
msext/QiniuSDK/Storage/QNUploadManager.h
Executable file
@@ -0,0 +1,155 @@
|
||||
//
|
||||
// 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 ALAsset;
|
||||
@class PHAsset;
|
||||
@class PHAssetResource;
|
||||
|
||||
/**
|
||||
* 上传完成后的回调函数
|
||||
*
|
||||
* @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 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;
|
||||
|
||||
/**
|
||||
* 上传ALAsset文件
|
||||
*
|
||||
* @param alasset 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;
|
||||
|
||||
/**
|
||||
* 上传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;
|
||||
|
||||
/**
|
||||
* 上传PHAssetResource文件(IOS9.1 andLater)
|
||||
*
|
||||
* @param asset 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;
|
||||
|
||||
@end
|
||||
321
msext/QiniuSDK/Storage/QNUploadManager.m
Executable file
321
msext/QiniuSDK/Storage/QNUploadManager.m
Executable file
@@ -0,0 +1,321 @@
|
||||
//
|
||||
// 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 "QNALAssetFile.h"
|
||||
#import <AssetsLibrary/AssetsLibrary.h>
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
|
||||
#import "QNPHAssetFile.h"
|
||||
#import <Photos/Photos.h>
|
||||
#endif
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90100
|
||||
#import "QNPHAssetResource.h"
|
||||
#endif
|
||||
|
||||
#else
|
||||
#import <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
#import "QNAsyncRun.h"
|
||||
#import "QNConfiguration.h"
|
||||
#import "QNCrc32.h"
|
||||
#import "QNFile.h"
|
||||
#import "QNFormUpload.h"
|
||||
#import "QNResponseInfo.h"
|
||||
#import "QNResumeUpload.h"
|
||||
#import "QNSessionManager.h"
|
||||
#import "QNSystem.h"
|
||||
#import "QNUpToken.h"
|
||||
#import "QNUploadManager.h"
|
||||
#import "QNUploadOption+Private.h"
|
||||
|
||||
@interface QNUploadManager ()
|
||||
@property (nonatomic) id<QNHttpDelegate> httpManager;
|
||||
@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;
|
||||
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
|
||||
_httpManager = [[QNSessionManager alloc] initWithProxy:config.proxy timeout:config.timeoutInterval urlConverter:config.converter dns:config.dns];
|
||||
#endif
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
+ (BOOL)checkAndNotifyError:(NSString *)key
|
||||
token:(NSString *)token
|
||||
input:(NSObject *)input
|
||||
complete:(QNUpCompletionHandler)completionHandler {
|
||||
NSString *desc = nil;
|
||||
if (completionHandler == nil) {
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException
|
||||
reason:@"no completionHandler"
|
||||
userInfo:nil];
|
||||
return YES;
|
||||
}
|
||||
if (input == nil) {
|
||||
desc = @"no input data";
|
||||
} else if (token == nil || [token isEqualToString:@""]) {
|
||||
desc = @"no token";
|
||||
}
|
||||
if (desc != nil) {
|
||||
QNAsyncRunInMain(^{
|
||||
completionHandler([QNResponseInfo responseInfoWithInvalidArgument:desc], key, nil);
|
||||
});
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)putData:(NSData *)data
|
||||
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) {
|
||||
QNAsyncRunInMain(^{
|
||||
completionHandler([QNResponseInfo responseInfoWithInvalidToken:@"invalid token"], key, nil);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
[_config.zone preQuery:t on:^(int code) {
|
||||
if (code != 0) {
|
||||
QNAsyncRunInMain(^{
|
||||
completionHandler([QNResponseInfo responseInfoWithInvalidToken:@"get zone failed"], key, nil);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if ([data length] == 0) {
|
||||
QNAsyncRunInMain(^{
|
||||
completionHandler([QNResponseInfo responseInfoOfZeroData:nil], key, nil);
|
||||
});
|
||||
return;
|
||||
}
|
||||
QNUpCompletionHandler complete = ^(QNResponseInfo *info, NSString *key, NSDictionary *resp) {
|
||||
QNAsyncRunInMain(^{
|
||||
completionHandler(info, key, resp);
|
||||
});
|
||||
};
|
||||
QNFormUpload *up = [[QNFormUpload alloc]
|
||||
initWithData:data
|
||||
withKey:key
|
||||
withToken:t
|
||||
withCompletionHandler:complete
|
||||
withOption:option
|
||||
withHttpManager:_httpManager
|
||||
withConfiguration:_config];
|
||||
QNAsyncRun(^{
|
||||
[up put];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)putFileInternal:(id<QNFileDelegate>)file
|
||||
key:(NSString *)key
|
||||
token:(NSString *)token
|
||||
complete:(QNUpCompletionHandler)completionHandler
|
||||
option:(QNUploadOption *)option {
|
||||
@autoreleasepool {
|
||||
QNUpToken *t = [QNUpToken parse:token];
|
||||
if (t == nil) {
|
||||
QNAsyncRunInMain(^{
|
||||
completionHandler([QNResponseInfo responseInfoWithInvalidToken:@"invalid token"], key, nil);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
[_config.zone preQuery:t on:^(int code) {
|
||||
if (code != 0) {
|
||||
QNAsyncRunInMain(^{
|
||||
completionHandler([QNResponseInfo responseInfoWithInvalidToken:@"get zone failed"], key, nil);
|
||||
});
|
||||
return;
|
||||
}
|
||||
QNUpCompletionHandler complete = ^(QNResponseInfo *info, NSString *key, NSDictionary *resp) {
|
||||
[file close];
|
||||
QNAsyncRunInMain(^{
|
||||
completionHandler(info, key, resp);
|
||||
});
|
||||
};
|
||||
|
||||
if ([file size] <= _config.putThreshold) {
|
||||
NSData *data = [file readAll];
|
||||
[self putData:data key:key token:token complete:complete option:option];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *recorderKey = key;
|
||||
if (_config.recorder != nil && _config.recorderKeyGen != nil) {
|
||||
recorderKey = _config.recorderKeyGen(key, [file path]);
|
||||
}
|
||||
|
||||
NSLog(@"recorder %@", _config.recorder);
|
||||
|
||||
QNResumeUpload *up = [[QNResumeUpload alloc]
|
||||
initWithFile:file
|
||||
withKey:key
|
||||
withToken:t
|
||||
withCompletionHandler:complete
|
||||
withOption:option
|
||||
withRecorder:_config.recorder
|
||||
withRecorderKey:recorderKey
|
||||
withHttpManager:_httpManager
|
||||
withConfiguration:_config];
|
||||
QNAsyncRun(^{
|
||||
[up run];
|
||||
});
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (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) {
|
||||
QNAsyncRunInMain(^{
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error];
|
||||
completionHandler(info, key, nil);
|
||||
});
|
||||
return;
|
||||
}
|
||||
[self putFileInternal:file key:key token:token complete:completionHandler option:option];
|
||||
}
|
||||
}
|
||||
|
||||
- (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) {
|
||||
QNAsyncRunInMain(^{
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error];
|
||||
completionHandler(info, key, nil);
|
||||
});
|
||||
return;
|
||||
}
|
||||
[self putFileInternal:file key:key token:token complete:completionHandler option:option];
|
||||
}
|
||||
#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 >= 80000)
|
||||
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) {
|
||||
QNAsyncRunInMain(^{
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error];
|
||||
completionHandler(info, key, nil);
|
||||
});
|
||||
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 >= 90100)
|
||||
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) {
|
||||
QNAsyncRunInMain(^{
|
||||
QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error];
|
||||
completionHandler(info, key, nil);
|
||||
});
|
||||
return;
|
||||
}
|
||||
[self putFileInternal:file key:key token:token complete:completionHandler option:option];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
14
msext/QiniuSDK/Storage/QNUploadOption+Private.h
Executable file
14
msext/QiniuSDK/Storage/QNUploadOption+Private.h
Executable file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// QNUploadOption+Private.h
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14/10/5.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUploadOption.h"
|
||||
|
||||
@interface QNUploadOption (Private)
|
||||
|
||||
@property (nonatomic, getter=priv_isCancelled, readonly) BOOL cancelled;
|
||||
@end
|
||||
83
msext/QiniuSDK/Storage/QNUploadOption.h
Executable file
83
msext/QiniuSDK/Storage/QNUploadOption.h
Executable file
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// 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);
|
||||
|
||||
/**
|
||||
* 上传中途取消函数
|
||||
*
|
||||
* @return 如果想取消,返回True, 否则返回No
|
||||
*/
|
||||
typedef BOOL (^QNUpCancellationSignal)(void);
|
||||
|
||||
/**
|
||||
* 可选参数集合,此类初始化后sdk上传使用时 不会对此进行改变;如果参数没有变化以及没有使用依赖,可以重复使用。
|
||||
*/
|
||||
@interface QNUploadOption : NSObject
|
||||
|
||||
/**
|
||||
* 用于服务器上传回调通知的自定义参数,参数的key必须以x: 开头
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSDictionary *params;
|
||||
|
||||
/**
|
||||
* 指定文件的mime类型
|
||||
*/
|
||||
@property (copy, nonatomic, readonly) NSString *mimeType;
|
||||
|
||||
/**
|
||||
* 是否进行crc校验
|
||||
*/
|
||||
@property (readonly) BOOL checkCrc;
|
||||
|
||||
/**
|
||||
* 进度回调函数
|
||||
*/
|
||||
@property (copy, readonly) QNUpProgressHandler progressHandler;
|
||||
|
||||
/**
|
||||
* 中途取消函数
|
||||
*/
|
||||
@property (copy, readonly) QNUpCancellationSignal cancellationSignal;
|
||||
|
||||
/**
|
||||
* 可选参数的初始化方法
|
||||
*
|
||||
* @param mimeType mime类型
|
||||
* @param progress 进度函数
|
||||
* @param params 自定义服务器回调参数
|
||||
* @param check 是否进行crc检查
|
||||
* @param cancellation 中途取消函数
|
||||
*
|
||||
* @return 可选参数类实例
|
||||
*/
|
||||
- (instancetype)initWithMime:(NSString *)mimeType
|
||||
progressHandler:(QNUpProgressHandler)progress
|
||||
params:(NSDictionary *)params
|
||||
checkCrc:(BOOL)check
|
||||
cancellationSignal:(QNUpCancellationSignal)cancellation;
|
||||
|
||||
- (instancetype)initWithProgessHandler:(QNUpProgressHandler)progress DEPRECATED_ATTRIBUTE;
|
||||
- (instancetype)initWithProgressHandler:(QNUpProgressHandler)progress;
|
||||
|
||||
/**
|
||||
* 内部使用,默认的参数实例
|
||||
*
|
||||
* @return 可选参数类实例
|
||||
*/
|
||||
+ (instancetype)defaultOptions;
|
||||
|
||||
@end
|
||||
67
msext/QiniuSDK/Storage/QNUploadOption.m
Executable file
67
msext/QiniuSDK/Storage/QNUploadOption.m
Executable file
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// QNUploadOption.m
|
||||
// QiniuSDK
|
||||
//
|
||||
// Created by bailong on 14/10/4.
|
||||
// Copyright (c) 2014年 Qiniu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNUploadOption+Private.h"
|
||||
#import "QNUploadManager.h"
|
||||
|
||||
static NSString *mime(NSString *mimeType) {
|
||||
if (mimeType == nil || [mimeType isEqualToString:@""]) {
|
||||
return @"application/octet-stream";
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
@implementation QNUploadOption
|
||||
|
||||
+ (NSDictionary *)filteParam:(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;
|
||||
}
|
||||
}];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (instancetype)initWithProgessHandler:(QNUpProgressHandler)progress {
|
||||
return [self initWithMime:nil progressHandler:progress params:nil checkCrc:NO cancellationSignal:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithProgressHandler:(QNUpProgressHandler)progress {
|
||||
return [self initWithMime:nil progressHandler:progress params:nil checkCrc:NO cancellationSignal:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithMime:(NSString *)mimeType
|
||||
progressHandler:(QNUpProgressHandler)progress
|
||||
params:(NSDictionary *)params
|
||||
checkCrc:(BOOL)check
|
||||
cancellationSignal:(QNUpCancellationSignal)cancel {
|
||||
if (self = [super init]) {
|
||||
_mimeType = mime(mimeType);
|
||||
_progressHandler = progress != nil ? progress : ^(NSString *key, float percent) {
|
||||
};
|
||||
_params = [QNUploadOption filteParam:params];
|
||||
_checkCrc = check;
|
||||
_cancellationSignal = cancel != nil ? cancel : ^BOOL() {
|
||||
return NO;
|
||||
};
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)defaultOptions {
|
||||
return [[QNUploadOption alloc] initWithMime:nil progressHandler:nil params:nil checkCrc:NO cancellationSignal:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user