Skip to content

Commit

Permalink
Merge branch 'master' into refactor/sample
Browse files Browse the repository at this point in the history
  • Loading branch information
duan007a authored Nov 22, 2018
2 parents 80d6dfb + b156824 commit 6a3a129
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ Products/
# big Resource for test
Example/AliyunOSSSDK-iOS-Example/Resources/

# web server generated files
# Python script generated files
Scripts/*.pyc
75 changes: 53 additions & 22 deletions AliyunOSSSDK/OSSClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@
#import "OSSGetSymlinkRequest.h"
#import "OSSRestoreObjectRequest.h"

static NSString * const oss_partInfos_storage_name = @"oss_partInfos_storage_name";
static NSString * const oss_record_info_suffix_with_crc = @"-crc64";
static NSString * const oss_record_info_suffix_with_sequential = @"-sequential";
static NSUInteger const oss_multipart_max_part_number = 5000; //max part number
static NSString * const kClientRecordNameWithCommonPrefix = @"oss_partInfos_storage_name";
static NSString * const kClientRecordNameWithCRC64Suffix = @"-crc64";
static NSString * const kClientRecordNameWithSequentialSuffix = @"-sequential";
static NSUInteger const kClientMaximumOfChunks = 5000; //max part number

static NSString * const kClientErrorMessageForEmptyFile = @"the length of file should not be 0!";
static NSString * const kClientErrorMessageForCancelledTask = @"This task has been cancelled!";

/**
* extend OSSRequest to include the ref to networking request object
Expand Down Expand Up @@ -267,10 +270,10 @@ - (NSUInteger)judgePartSizeForMultipartRequest:(OSSMultipartUploadRequest *)requ
BOOL divisible = (fileSize % request.partSize == 0);
NSUInteger partCount = (fileSize / request.partSize) + (divisible? 0 : 1);

if(partCount > oss_multipart_max_part_number)
if(partCount > kClientMaximumOfChunks)
{
request.partSize = fileSize / oss_multipart_max_part_number;
partCount = oss_multipart_max_part_number;
request.partSize = fileSize / kClientMaximumOfChunks;
partCount = kClientMaximumOfChunks;
}
return partCount;
#pragma clang diagnostic pop
Expand All @@ -288,10 +291,10 @@ - (NSString *)readUploadIdForRequest:(OSSResumableUploadRequest *)request record
NSString *uploadId = nil;
NSString *record = [NSString stringWithFormat:@"%@%@%@%lu", request.md5String, request.bucketName, request.objectKey, (unsigned long)request.partSize];
if (sequential) {
record = [record stringByAppendingString:oss_record_info_suffix_with_sequential];
record = [record stringByAppendingString:kClientRecordNameWithSequentialSuffix];
}
if (request.crcFlag == OSSRequestCRCOpen) {
record = [record stringByAppendingString:oss_record_info_suffix_with_crc];
record = [record stringByAppendingString:kClientRecordNameWithCRC64Suffix];
}

NSData *data = [record dataUsingEncoding:NSUTF8StringEncoding];
Expand All @@ -313,7 +316,7 @@ - (NSString *)readUploadIdForRequest:(OSSResumableUploadRequest *)request record
- (NSMutableDictionary *)localPartInfosDictoryWithUploadId:(NSString *)uploadId
{
NSMutableDictionary *localPartInfoDict = nil;
NSString *partInfosDirectory = [[NSString oss_documentDirectory] stringByAppendingPathComponent:oss_partInfos_storage_name];
NSString *partInfosDirectory = [[NSString oss_documentDirectory] stringByAppendingPathComponent:kClientRecordNameWithCommonPrefix];
NSString *partInfosPath = [partInfosDirectory stringByAppendingPathComponent:uploadId];
BOOL isDirectory;
NSFileManager *defaultFM = [NSFileManager defaultManager];
Expand Down Expand Up @@ -341,7 +344,7 @@ - (NSMutableDictionary *)localPartInfosDictoryWithUploadId:(NSString *)uploadId

- (OSSTask *)persistencePartInfos:(NSDictionary *)partInfos withUploadId:(NSString *)uploadId
{
NSString *filePath = [[[NSString oss_documentDirectory] stringByAppendingPathComponent:oss_partInfos_storage_name] stringByAppendingPathComponent:uploadId];
NSString *filePath = [[[NSString oss_documentDirectory] stringByAppendingPathComponent:kClientRecordNameWithCommonPrefix] stringByAppendingPathComponent:uploadId];
if (![partInfos writeToFile:filePath atomically:YES])
{
NSError *error = [NSError errorWithDomain:OSSClientErrorDomain
Expand All @@ -353,6 +356,30 @@ - (OSSTask *)persistencePartInfos:(NSDictionary *)partInfos withUploadId:(NSStri
return nil;
}

- (OSSTask *)checkPutObjectFileURL:(OSSPutObjectRequest *)request {
NSError *error = nil;
if (!request.uploadingFileURL || ![request.uploadingFileURL.path oss_isNotEmpty]) {
error = [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeInvalidArgument
userInfo:@{OSSErrorMessageTOKEN: @"Please check your request's uploadingFileURL!"}];
} else {
NSFileManager *dfm = [NSFileManager defaultManager];
NSDictionary *attributes = [dfm attributesOfItemAtPath:request.uploadingFileURL.path error:&error];
unsigned long long fileSize = [attributes[NSFileSize] unsignedLongLongValue];
if (!error && fileSize == 0) {
error = [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeInvalidArgument
userInfo:@{OSSErrorMessageTOKEN: kClientErrorMessageForEmptyFile}];
}
}

if (error) {
return [OSSTask taskWithError:error];
} else {
return [OSSTask taskWithResult:nil];
}
}

- (OSSTask *)checkFileSizeWithRequest:(OSSMultipartUploadRequest *)request {
NSError *error = nil;
if (!request.uploadingFileURL || ![request.uploadingFileURL.path oss_isNotEmpty]) {
Expand All @@ -368,7 +395,7 @@ - (OSSTask *)checkFileSizeWithRequest:(OSSMultipartUploadRequest *)request {
if (!error && fileSize == 0) {
error = [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeInvalidArgument
userInfo:@{OSSErrorMessageTOKEN: @"File length must not be 0!"}];
userInfo:@{OSSErrorMessageTOKEN: kClientErrorMessageForEmptyFile}];
}
}

Expand All @@ -385,7 +412,7 @@ + (NSError *)cancelError{
dispatch_once(&onceToken, ^{
error = [NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeTaskCancelled
userInfo:@{OSSErrorMessageTOKEN: @"This task has been cancelled!"}];
userInfo:@{OSSErrorMessageTOKEN: kClientErrorMessageForCancelledTask}];
});
return error;
}
Expand Down Expand Up @@ -589,6 +616,10 @@ - (OSSTask *)putObject:(OSSPutObjectRequest *)request
}
}
if (request.uploadingFileURL) {
OSSTask *checkIfEmptyTask = [self checkPutObjectFileURL:request];
if (checkIfEmptyTask.error) {
return checkIfEmptyTask;
}
requestDelegate.uploadingFileURL = request.uploadingFileURL;
}

Expand Down Expand Up @@ -1043,17 +1074,17 @@ - (OSSTask *)abortMultipartUpload:(OSSMultipartUploadRequest *)request sequentia
OSSResumableUploadRequest *resumableRequest = (OSSResumableUploadRequest *)request;
NSString *nameInfoString = [NSString stringWithFormat:@"%@%@%@%lu",request.md5String, resumableRequest.bucketName, resumableRequest.objectKey, (unsigned long)resumableRequest.partSize];
if (sequential) {
nameInfoString = [nameInfoString stringByAppendingString:oss_record_info_suffix_with_sequential];
nameInfoString = [nameInfoString stringByAppendingString:kClientRecordNameWithSequentialSuffix];
}
if (request.crcFlag == OSSRequestCRCOpen) {
nameInfoString = [nameInfoString stringByAppendingString:oss_record_info_suffix_with_crc];
nameInfoString = [nameInfoString stringByAppendingString:kClientRecordNameWithCRC64Suffix];
}

NSData *data = [nameInfoString dataUsingEncoding:NSUTF8StringEncoding];
NSString *recordFileName = [OSSUtil dataMD5String:data];
NSString *recordFilePath = [NSString stringWithFormat:@"%@/%@",resumableRequest.recordDirectoryPath,recordFileName];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *partInfosFilePath = [[[NSString oss_documentDirectory] stringByAppendingPathComponent:oss_partInfos_storage_name] stringByAppendingPathComponent:resumableRequest.uploadId];
NSString *partInfosFilePath = [[[NSString oss_documentDirectory] stringByAppendingPathComponent:kClientRecordNameWithCommonPrefix] stringByAppendingPathComponent:resumableRequest.uploadId];

if([fileManager fileExistsAtPath:recordFilePath])
{
Expand Down Expand Up @@ -1197,7 +1228,7 @@ - (OSSTask *)processListPartsWithObjectKey:(nonnull NSString *)objectKey bucket:
{
isTruncated = NO;
[uploadedParts removeAllObjects];
if ([listPartsTask.error.domain isEqualToString: OSSServerErrorDomain] && listPartsTask.error.code == -404)
if ([listPartsTask.error.domain isEqualToString: OSSServerErrorDomain] && labs(listPartsTask.error.code) == 404)
{
OSSLogVerbose(@"local record existes but the remote record is deleted");
*uploadId = nil;
Expand Down Expand Up @@ -1406,7 +1437,7 @@ - (void)executePartUpload:(OSSMultipartUploadRequest *)request totalBytesExpecte
OSSTask * uploadPartTask = [self uploadPart:uploadPart];
[uploadPartTask waitUntilFinished];
if (uploadPartTask.error) {
if (abs(uploadPartTask.error.code) != 409) {
if (labs(uploadPartTask.error.code) != 409) {
*errorTask = uploadPartTask;
}
} else {
Expand Down Expand Up @@ -1523,7 +1554,7 @@ - (OSSTask *)multipartUpload:(OSSMultipartUploadRequest *)request resumable:(BOO

if([uploadId oss_isNotEmpty])
{
localPartInfosPath = [[[NSString oss_documentDirectory] stringByAppendingPathComponent:oss_partInfos_storage_name] stringByAppendingPathComponent:uploadId];
localPartInfosPath = [[[NSString oss_documentDirectory] stringByAppendingPathComponent:kClientRecordNameWithCommonPrefix] stringByAppendingPathComponent:uploadId];

localPartInfos = [[NSDictionary alloc] initWithContentsOfFile:localPartInfosPath];

Expand Down Expand Up @@ -1595,7 +1626,7 @@ - (OSSTask *)multipartUpload:(OSSMultipartUploadRequest *)request resumable:(BOO
}

request.uploadId = uploadId;
localPartInfosPath = [[[NSString oss_documentDirectory] stringByAppendingPathComponent:oss_partInfos_storage_name] stringByAppendingPathComponent:uploadId];
localPartInfosPath = [[[NSString oss_documentDirectory] stringByAppendingPathComponent:kClientRecordNameWithCommonPrefix] stringByAppendingPathComponent:uploadId];

if (request.isCancelled)
{
Expand Down Expand Up @@ -1742,7 +1773,7 @@ - (OSSTask *)sequentialUpload:(OSSMultipartUploadRequest *)request
[uploadPartTask waitUntilFinished];

if (uploadPartTask.error) {
if (abs(uploadPartTask.error.code) != 409) {
if (labs(uploadPartTask.error.code) != 409) {
errorTask = uploadPartTask;
break;
} else {
Expand Down Expand Up @@ -1951,7 +1982,7 @@ - (BOOL)doesObjectExistInBucket:(NSString *)bucketName
if (!headError) {
return YES;
} else {
if ([headError.domain isEqualToString: OSSServerErrorDomain] && headError.code == -404) {
if ([headError.domain isEqualToString: OSSServerErrorDomain] && labs(headError.code) == 404) {
return NO;
} else {
if (error != nil) {
Expand Down
14 changes: 13 additions & 1 deletion AliyunOSSSDK/OSSModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ TODOTODO
/**
The STS token's credential provider.
*/
__attribute__((deprecated("Please use OSSAuthCredentialProvider or its subClass instead!")))
@interface OSSStsTokenCredentialProvider : NSObject <OSSCredentialProvider>
@property (nonatomic, copy) NSString * accessKeyId;
@property (nonatomic, copy) NSString * secretKeyId;
Expand All @@ -127,8 +128,19 @@ TODOTODO
@end

/**
auth credential provider.
Auth credential provider require a STS INFO Server URL,also you can customize a decoder block which returns json data.
OSSAuthCredentialProvider *acp = [[OSSAuthCredentialProvider alloc] initWithAuthServerUrl:@"sts_server_url" responseDecoder:^NSData * (NSData * data) {
// 1.hanle response from server.
// 2.initialize json object from step 1. json object require message like {AccessKeyId:@"xxx",AccessKeySecret:@"xxx",SecurityToken:@"xxx",Expiration:@"xxx"}
// 3.generate jsonData from step 2 and return it.
}];
*/

@interface OSSAuthCredentialProvider : OSSFederationCredentialProvider
@property (nonatomic, copy) NSString * authServerUrl;
@property (nonatomic, copy) NSData * (^responseDecoder)(NSData *);
Expand Down
2 changes: 1 addition & 1 deletion AliyunOSSSDK/OSSNetworkingRequestDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ - (OSSTask *)buildInternalHttpRequest {
urlComponents.host = [NSString stringWithFormat:@"%@.%@", self.allNeededMessage.bucketName, urlComponents.host];
headerHost = urlComponents.host;

if (self.isHttpdnsEnable) {
if ([urlComponents.scheme.lowercaseString isEqualToString:@"https"] && self.isHttpdnsEnable) {
NSString *dnsResult = [OSSUtil getIpByHost: urlComponents.host];
urlComponents.host = dnsResult;
}
Expand Down
12 changes: 12 additions & 0 deletions AliyunOSSiOSTests/OSSObjectTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -1745,4 +1745,16 @@ - (void)testAPI_multipartUploadWithPartSizeEqualToZero {
XCTAssertNotNil(task.error);
}

- (void)testAPI_putObjectWithEmptyFile {
OSSPutObjectRequest *req = [OSSPutObjectRequest new];
req.bucketName = OSS_BUCKET_PUBLIC;
req.objectKey = @"test-empty-file";
req.uploadingFileURL = [[NSBundle mainBundle] URLForResource:@"empty-file" withExtension:nil];

OSSTask *task = [_client putObject:req];
[task waitUntilFinished];

XCTAssertNotNil(task.error);
}

@end
15 changes: 9 additions & 6 deletions OSSSwiftDemo/OSSSwiftDemo/Classes/OSSRootViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,12 @@ class OSSRootViewController: UIViewController, URLSessionDelegate, URLSessionDat
}

func ossAlert(title: String?,message:String?) -> Void {
let alertCtrl = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alertCtrl.addAction(UIAlertAction(title: "confirm", style: UIAlertActionStyle.default, handler: { (action) in
print("\(action.title!) has been clicked");
alertCtrl.dismiss(animated: true, completion: nil)
}))

DispatchQueue.main.async {
let alertCtrl = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alertCtrl.addAction(UIAlertAction(title: "confirm", style: UIAlertActionStyle.default, handler: { (action) in
print("\(action.title!) has been clicked");
alertCtrl.dismiss(animated: true, completion: nil)
}))
self.present(alertCtrl, animated: true, completion: nil)
}
}
Expand Down Expand Up @@ -480,5 +479,9 @@ class OSSRootViewController: UIViewController, URLSessionDelegate, URLSessionDat
return nil
}).waitUntilFinished()
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
}

52 changes: 43 additions & 9 deletions README-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

需要引入OSS iOS SDK framework。

您可以在MacOS系统中直接使用在本工程生成framwork
您可以在MacOS系统中直接使用本工程,选择对应的scheme为AliyunOSSSDK OSX,然后生成framwork

```bash
# clone工程
Expand All @@ -26,16 +26,16 @@ $ git clone [email protected]:aliyun/aliyun-oss-ios-sdk.git
$ cd aliyun-oss-ios-sdk

# 执行打包脚本
$ sh ./buildFramework.sh
$ sh ./buildiOSFramework.sh

# 进入打包生成目录,AliyunOSSiOS.framework生成在该目录下
$ cd Products && ls
```

注意:buildFramework.sh脚本生成的framework是支持i386,x86_64,armv7,arm64架构的版本,所以当您需要archive product时,需要直接使用工程文件生成只支持真机的framework版本。

在Xcode中,直接把framework拖入您对应的Target下即可,在弹出框勾选`Copy items if needed`

**注意:buildiOSFramework.sh脚本生成的framework是支持i386,x86_64,armv7,arm64架构的版本,所以当您需要archive product时,需要直接使用工程文件生成只支持真机的framework版本。**

### Pod依赖

如果工程是通过pod管理依赖,那么在Podfile中加入以下依赖即可,不需要再导入framework:
Expand Down Expand Up @@ -79,8 +79,6 @@ WWDC 2016开发者大会上,苹果宣布从2017年1月1日起,苹果App Stor

### 对于OSSTask的一些说明

**注意: 建议OSSClient的生命周期和应用程序的生命周期保持一致(如果您不希望这样,也可以在调用API时增加[task waitUntilFinished]以确保在task完成之前OSSClient不被释放)。**

所有调用api的操作,都会立即获得一个OSSTask,如:

```
Expand Down Expand Up @@ -120,12 +118,48 @@ demo示例: [点击查看](https://github.com/alibaba/alicloud-ios-demo)。

在移动环境下,我们推荐STS鉴权模式来初始化OSSClient。鉴权细节详见后面链接给出的官网完整文档的`访问控制`章节。

**注意: 如果您的应用只用到一个[数据中心](https://help.aliyun.com/document_detail/31837.html)下的bucket,建议保持OSSClient实例与应用程序的生命周期一致(比如在Appdelegate.m的 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions])中进行初始化,如下所示:**

```objc
NSString *endpoint = @"https://oss-cn-hangzhou.aliyuncs.com";
@interface AppDelegate ()

@property (nonatomic, strong) OSSClient *client;

@end

/**
* 获取sts信息的url,配置在业务方自己的搭建的服务器上。详情可见https://help.aliyun.com/document_detail/31920.html
*/
#define OSS_STS_URL @"oss_sts_url"


/**
* bucket所在的region的endpoint,详情可见https://help.aliyun.com/document_detail/31837.html
*/
#define OSS_ENDPOINT @"your bucket's endpoint"

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.

// 初始化OSSClient实例
[self setupOSSClient];

return YES;
}

id<OSSCredentialProvider> credential = [[OSSStsTokenCredentialProvider alloc] initWithAccessKeyId:@"<StsToken.AccessKeyId>" secretKeyId:@"<StsToken.SecretKeyId>" securityToken:@"<StsToken.SecurityToken>"];
- (void)setupOSSClient {

client = [[OSSClient alloc] initWithEndpoint:endpoint credentialProvider:credential];
// 初始化具有自动刷新的provider
OSSAuthCredentialProvider *credentialProvider = [[OSSAuthCredentialProvider alloc] initWithAuthServerUrl:OSS_STS_URL];

// client端的配置,如超时时间,开启dns解析等等
OSSClientConfiguration *cfg = [[OSSClientConfiguration alloc] init];

_client = [[OSSClient alloc] initWithEndpoint:OSS_ENDPOINT credentialProvider:credentialProvider clientConfiguration:cfg];
}

```
Expand Down
Loading

0 comments on commit 6a3a129

Please sign in to comment.