Skip to content

Commit

Permalink
Version 2 of the AWS Mobile SDK for iOS 2.0.9.
Browse files Browse the repository at this point in the history
  • Loading branch information
Yosuke Matsuda committed Oct 23, 2014
1 parent 8012f01 commit 7e0f2a6
Show file tree
Hide file tree
Showing 58 changed files with 1,498 additions and 935 deletions.
2 changes: 2 additions & 0 deletions AWSCore/AWSCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@
#import "STS.h"
#import "CognitoIdentity.h"
#import "MobileAnalytics.h"

#import "Bolts.h"
3 changes: 2 additions & 1 deletion AWSCore/Authentication/AWSCredentialsProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

FOUNDATION_EXPORT NSString *const AWSCognitoCredentialsProviderErrorDomain;
typedef NS_ENUM(NSInteger, AWSCognitoCredentialsProviderErrorType) {
AWSCognitoCredentialsProviderErrorUnknown
AWSCognitoCredentialsProviderErrorUnknown,
AWSCognitoCredentialsProviderIdentityIdIsNil,
};

@class BFTask;
Expand Down
197 changes: 112 additions & 85 deletions AWSCore/Authentication/AWSCredentialsProvider.m

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions AWSCore/Authentication/AWSIdentityProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ typedef NS_ENUM(NSInteger, AWSCognitoLoginProviderKey) {
AWSCognitoLoginProviderKeyLoginWithAmazon,
};

FOUNDATION_EXPORT NSString *const AWSCognitoIdentityProviderErrorDomain;
typedef NS_ENUM(NSInteger, AWSCognitoIdentityProviderErrorType) {
AWSCognitoIdentityProviderErrorIdentityIsNil,
};

@class BFTask;

@protocol AWSIdentityProvider <NSObject>
Expand Down
85 changes: 67 additions & 18 deletions AWSCore/Authentication/AWSIdentityProvider.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@

#import "AWSCore.h"
#import "AWSIdentityProvider.h"
#import "Bolts.h"

NSString *const AWSCognitoIdentityIdChangedNotification = @"com.amazonaws.services.cognitoidentity.AWSCognitoIdentityIdChangedNotification";
NSString *const AWSCognitoIdentityProviderErrorDomain = @"com.amazonaws.service.cognitoidentity.AWSCognitoIdentityProvider";
NSString *const AWSCognitoNotificationPreviousId = @"PREVID";
NSString *const AWSCognitoNotificationNewId = @"NEWID";

Expand Down Expand Up @@ -49,7 +51,7 @@ - (void)clear {
}

- (BOOL)isAuthenticated {
return [self.logins count] > 0;
return self.logins != nil && [self.logins count] > 0;
}

- (void)setLogins:(NSDictionary *)logins {
Expand Down Expand Up @@ -93,6 +95,10 @@ - (NSDictionary *)updateKeysForLogins:(NSDictionary *)logins {
mutableLogin[updatedKey] = logins[key];
}

if ([mutableLogin count] == 0) {
return nil;
}

return mutableLogin;
}

Expand All @@ -115,6 +121,9 @@ - (void)postIdentityIdChangedNotification:(NSString *)newId {
@interface AWSBasicCognitoIdentityProvider()
@property (nonatomic, strong) NSString *accountId;
@property (nonatomic, strong) AWSCognitoIdentity *cib;
@property (nonatomic, strong) BFExecutor *executor;
@property (atomic, assign) int32_t count;
@property (nonatomic, strong) dispatch_semaphore_t semaphore;
@end

@implementation AWSBasicCognitoIdentityProvider
Expand All @@ -128,6 +137,9 @@ - (instancetype)initWithRegionType:(AWSRegionType)regionType

if (self = [super init]) {
_accountId = accountId;
_executor = [BFExecutor executorWithOperationQueue:[NSOperationQueue new]];
_count = 0;
_semaphore = dispatch_semaphore_create(0);
self.identityPoolId = identityPoolId;
self.identityId = identityId;
self.logins = [self updateKeysForLogins:logins];
Expand All @@ -144,51 +156,79 @@ - (instancetype)initWithRegionType:(AWSRegionType)regionType

- (BFTask *)getIdentityId {
if (self.identityId) {
return [BFTask taskWithResult:nil];
return [BFTask taskWithResult:self.identityId];
} else {
return [[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) {
if (!self.identityId) {
return [[[BFTask taskWithResult:nil] continueWithExecutor:self.executor withBlock:^id(BFTask *task) {
self.count++;
if (self.count <= 1) {
AWSCognitoIdentityGetIdInput *getIdInput = [AWSCognitoIdentityGetIdInput new];
getIdInput.accountId = self.accountId;
getIdInput.identityPoolId = self.identityPoolId;
getIdInput.logins = self.logins;

return [[self.cib getId:getIdInput] continueWithBlock:^id(BFTask *task) {
if (task.error) {
AWSLogError(@"GetId failed. Error is [%@]", task.error);
} else {
AWSCognitoIdentityGetIdResponse *getIdResponse = task.result;
self.identityId = getIdResponse.identityId;
}
return nil;
}];
return [self.cib getId:getIdInput];
}
return nil;
else {
dispatch_semaphore_wait(self.semaphore, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
return nil;
}
}] continueWithBlock:^id(BFTask *task) {
self.count--;
dispatch_semaphore_signal(self.semaphore);
if (task.error) {
AWSLogError(@"GetId failed. Error is [%@]", task.error);
return task;
} else if (task.result) {
AWSCognitoIdentityGetIdResponse *getIdResponse = task.result;
self.identityId = getIdResponse.identityId;
}
return [BFTask taskWithResult:self.identityId];
}];
}
}

- (BFTask *)refresh {
return [[[self getIdentityId] continueWithSuccessBlock:^id(BFTask *task) {
// This should never happen, but just in case
if (!self.identityId) {
AWSLogError(@"In refresh, but identitId is nil.");
AWSLogError(@"Result from getIdentityId is %@", task.result);
return [BFTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain
code:AWSCognitoIdentityProviderErrorIdentityIsNil
userInfo:@{NSLocalizedDescriptionKey: @"identityId shouldn't be nil"}]
];
}

AWSCognitoIdentityGetOpenIdTokenInput *getTokenInput = [AWSCognitoIdentityGetOpenIdTokenInput new];
getTokenInput.identityId = self.identityId;
getTokenInput.logins = self.logins;


return [[self.cib getOpenIdToken:getTokenInput] continueWithBlock:^id(BFTask *task) {
// When an invalid identityId is cached in the keychain for auth,
// we will refresh the identityId and try to get OpenID token again.
if (task.error) {
AWSLogError(@"GetOpenIdToken failed. Error is [%@]", task.error);

// if it's unauth, just fail out
if (!self.logins) {
if (![self isAuthenticated]) {
return task;
}

AWSLogError(@"GetOpenIdToken failed. Error is [%@]", task.error);
AWSLogVerbose(@"Calling GetId");
AWSLogVerbose(@"Resetting identity Id and calling getIdentityId");
// if it's auth, reset id and refetch
self.identityId = nil;
return [[self getIdentityId] continueWithSuccessBlock:^id(BFTask *task) {
// This should never happen, but just in case
if (!self.identityId) {
AWSLogError(@"In refresh, but identitId is nil.");
AWSLogError(@"Result from getIdentityId is %@", task.result);
return [BFTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain
code:AWSCognitoIdentityProviderErrorIdentityIsNil
userInfo:@{NSLocalizedDescriptionKey: @"identityId shouldn't be nil"}]
];
}

AWSLogVerbose(@"Retrying GetOpenIdToken");

// retry get token
Expand All @@ -206,6 +246,15 @@ - (BFTask *)refresh {
self.token = getTokenResponse.token;
NSString *identityIdFromToken = getTokenResponse.identityId;

// This should never happen, but just in case
if (!identityIdFromToken) {
AWSLogError(@"identityId from getOpenIdToken is nil");
return [BFTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain
code:AWSCognitoIdentityProviderErrorIdentityIsNil
userInfo:@{NSLocalizedDescriptionKey: @"identityId shouldn't be nil"}]
];
}

if (![self.identityId isEqualToString:identityIdFromToken]) {
self.identityId = identityIdFromToken;
}
Expand Down
1 change: 1 addition & 0 deletions AWSCore/Authentication/AWSSignature.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#import "AWSService.h"
#import "AWSCredentialsProvider.h"
#import "AWSLogging.h"
#import "Bolts.h"

NSString *const AWSSigV4Marker = @"AWS4";
NSString *const AWSSigV4Algorithm = @"AWS4-HMAC-SHA256";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* permissions and limitations under the License.
*/

#import "Bolts.h"
#import "AWSMobileAnalyticsDefaultHttpClient.h"
#import "AWSCore.h"
#import "AWSMobileAnalyticsInstanceIdInterceptor.h"
Expand Down Expand Up @@ -147,17 +148,17 @@ -(void) addInterceptor: (id<AWSMobileAnalyticsInterceptor>) theInterceptor
putEventInput.events = parsedEventsArray;
}

//Attach the request to the response
id<AWSMobileAnalyticsRequest> request = [[AWSMobileAnalyticsDefaultRequest alloc] init];
[request setUrl:ers.configuration.URL];
response.originatingRequest = request;

NSDate* requestStartDate = [NSDate date];
[[[ers putEvents:putEventInput] continueWithBlock:^id(BFTask *task) {

NSDictionary *resultDictionary = nil;
if (task.error) {
if (task.error.domain != AWSMobileAnalyticsERSErrorDomain || task.error.domain != AWSGeneralErrorDomain) {
//It is client side error, assign the error and return immediately
response.error = task.error;
return nil;
}
response.error = task.error;
resultDictionary = task.error.userInfo;
} else {
if ([task.result isKindOfClass:[NSDictionary class]]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ -(void) recordRequestTimeEventOnResponse:(id<AWSMobileAnalyticsResponse>) theRes
[recordEvent addAttribute:serverInfo forKey:@"serverInfo"];
}

[self.eventClient recordEvent:recordEvent andApplyGlobalAttributes:NO];
[self.eventClient recordEvent:recordEvent andApplyGlobalAttributes:YES];
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#import "AWSMobileAnalyticsSerializerFactory.h"
#import "AWSMobileAnalyticsStringUtils.h"
#import "AWSLogging.h"
#import "AWSMObileAnalyticsDefaultSessionClient.h"
#import <UIKit/UIKit.h>

static NSSet* RETRY_REQUEST_CODES = nil;
Expand Down Expand Up @@ -130,10 +131,30 @@ -(void) notify:(id<AWSMobileAnalyticsInternalEvent>) theEvent
[self enqueueEventForDelivery:theEvent];
}

-(BOOL) validateEvent:(id<AWSMobileAnalyticsInternalEvent>) theEvent {

if (![theEvent attributeForKey:AWSSessionIDAttributeKey]) {
AWSLogError(@"Event: '%@' Validation Error: %@ is nil",theEvent.eventType,AWSSessionIDAttributeKey);
return NO;
}

if (![theEvent attributeForKey:AWSSessionStartTimeAttributeKey]) {
AWSLogError(@"Event '%@' Validation Error: %@ is nil",theEvent.eventType,AWSSessionStartTimeAttributeKey);
return NO;
}

return YES;
}

-(void) enqueueEventForDelivery:(id<AWSMobileAnalyticsInternalEvent>) theEvent
{
if(self.operationQueue.operationCount >= MAX_OPERATIONS) {
AWSLogWarn(@"The event is being dropped because too many operations enqueued");
AWSLogError(@"The event: '%@' is being dropped because too many operations enqueued.",theEvent.eventType);
return;
}

if (![self validateEvent:theEvent]) {
AWSLogError(@"The event '%@'is being dropped because internal validation failed.",theEvent.eventType);
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ -(void)resumeWithSessionClient:(AWSMobileAnalyticsDefaultSessionClient *)session
}

-(void)pauseWithSessionClient:(AWSMobileAnalyticsDefaultSessionClient *)sessionClient{
id<AWSMobileAnalyticsInternalEvent> pauseEvent = [sessionClient.eventClient createInternalEvent:AWSSessionPauseEventType];
[sessionClient.eventClient recordEvent:pauseEvent andApplyGlobalAttributes:YES];

AWSLogVerbose( @"Session Pause Failed: No session is running.");
}

Expand Down
76 changes: 44 additions & 32 deletions AWSCore/MobileAnalyticsERS/AWSMobileAnalyticsERS.m
Original file line number Diff line number Diff line change
Expand Up @@ -81,40 +81,52 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response

}
if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) {
NSString *errorTypeStr = [[response allHeaderFields] objectForKey:@"x-amzn-ErrorType"];
NSString *errorTypeHeader = [[errorTypeStr componentsSeparatedByString:@":"] firstObject];

if ([errorTypeStr length] > 0 && errorTypeHeader) {
if (errorCodeDictionary[[[errorTypeHeader componentsSeparatedByString:@"#"] lastObject]]) {
if (error) {
NSMutableDictionary *userInfo = [@{
NSLocalizedFailureReasonErrorKey : errorTypeStr,
@"responseStatusCode" : @([response statusCode]),
@"responseHeaders" : [response allHeaderFields],
@"responseDataSize" : @(data?[data length]:0),
} mutableCopy];
[userInfo addEntriesFromDictionary:responseObject];
*error = [NSError errorWithDomain:AWSMobileAnalyticsERSErrorDomain
code:[[errorCodeDictionary objectForKey:[[errorTypeHeader componentsSeparatedByString:@"#"] lastObject]] integerValue]
userInfo:userInfo];
}
return responseObject;
} else if (errorTypeHeader) {
if (error) {
NSMutableDictionary *userInfo = [@{
NSLocalizedFailureReasonErrorKey : errorTypeStr,
@"responseStatusCode" : @([response statusCode]),
@"responseHeaders" : [response allHeaderFields],
@"responseDataSize" : @(data?[data length]:0),
} mutableCopy];
[userInfo addEntriesFromDictionary:responseObject];
*error = [NSError errorWithDomain:AWSMobileAnalyticsERSErrorDomain
code:AWSMobileAnalyticsERSErrorUnknown
userInfo:userInfo];
}
return responseObject;
NSString *errorTypeHeader = [[[[response allHeaderFields] objectForKey:@"x-amzn-ErrorType"] componentsSeparatedByString:@":"] firstObject];

//server may also return error message in the body, need to catch it.
if (errorTypeHeader == nil) {
errorTypeHeader = [responseObject objectForKey:@"__type"];
}


if (errorCodeDictionary[[[errorTypeHeader componentsSeparatedByString:@"#"] lastObject]]) {
if (error) {
NSMutableDictionary *userInfo = [@{
NSLocalizedFailureReasonErrorKey : errorTypeHeader,
@"responseStatusCode" : @([response statusCode]),
@"responseHeaders" : [response allHeaderFields],
@"responseDataSize" : @(data?[data length]:0),
} mutableCopy];
[userInfo addEntriesFromDictionary:responseObject];
*error = [NSError errorWithDomain:AWSMobileAnalyticsERSErrorDomain
code:[[errorCodeDictionary objectForKey:[[errorTypeHeader componentsSeparatedByString:@"#"] lastObject]] integerValue]
userInfo:userInfo];
}
return responseObject;
} else if ([[errorTypeHeader componentsSeparatedByString:@"#"] lastObject]) {
if (error) {
NSMutableDictionary *userInfo = [@{
NSLocalizedFailureReasonErrorKey : errorTypeHeader,
@"responseStatusCode" : @([response statusCode]),
@"responseHeaders" : [response allHeaderFields],
@"responseDataSize" : @(data?[data length]:0),
} mutableCopy];
[userInfo addEntriesFromDictionary:responseObject];
*error = [NSError errorWithDomain:AWSMobileAnalyticsERSErrorDomain
code:AWSMobileAnalyticsERSErrorUnknown
userInfo:userInfo];
}
return responseObject;
} else if (response.statusCode/100 != 2) {
//should be an error if not a 2xx response.
if (error) {
*error = [NSError errorWithDomain:AWSMobileAnalyticsERSErrorDomain
code:AWSMobileAnalyticsERSErrorUnknown
userInfo:responseObject];
}
return responseObject;
}


if (self.outputClass) {
responseObject = [MTLJSONAdapter modelOfClass:self.outputClass
Expand Down
2 changes: 1 addition & 1 deletion AWSCore/Networking/AWSNetworking.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
*/

#import <Foundation/Foundation.h>
#import "Bolts.h"
#import "AWSModel.h"

FOUNDATION_EXPORT NSString *const AWSNetworkingErrorDomain;
Expand All @@ -33,6 +32,7 @@ typedef NS_ENUM(NSInteger, AWSNetworkingRetryType) {

@class AWSNetworkingConfiguration;
@class AWSNetworkingRequest;
@class BFTask;

typedef void (^AWSNetworkingUploadProgressBlock) (int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend);
typedef void (^AWSNetworkingDownloadProgressBlock) (int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);
Expand Down
Loading

0 comments on commit 7e0f2a6

Please sign in to comment.