added download feature for iOS port
required libs:
* ZipArchive - Obj-C impl of zip
* asi-http-request : http request help to assist with asynchoronous downloading of files
* minizip : support for ZipArchive
*
Added default splash screen for iOS app. (using the Wagic background to keep it neutral to module)
TODO: refine handling for iPad splash screen
* add selection screen and input screen for location of downloadable content. (ie core files, image files, etc )
* add support to opt out of backing up to iCloud for core files. Right now iOS will automatically backup all files under Documents folder to iCloud. Consider only allowing player data to be backed up to iCloud. All graphics and other assets are considered volatile.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// ASICloudFilesCDNRequest.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesRequest.h"
|
||||
|
||||
@class ASICloudFilesContainerXMLParserDelegate;
|
||||
|
||||
@interface ASICloudFilesCDNRequest : ASICloudFilesRequest {
|
||||
NSString *accountName;
|
||||
NSString *containerName;
|
||||
ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate;
|
||||
|
||||
}
|
||||
|
||||
@property (retain) NSString *accountName;
|
||||
@property (retain) NSString *containerName;
|
||||
@property (retain) ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate;
|
||||
|
||||
|
||||
// HEAD /<api version>/<account>/<container>
|
||||
// Response:
|
||||
// X-CDN-Enabled: True
|
||||
// X-CDN-URI: http://cdn.cloudfiles.mosso.com/c1234
|
||||
// X-CDN-SSL-URI: https://cdn.ssl.cloudfiles.mosso.com/c1234
|
||||
// X-CDN-TTL: 86400
|
||||
+ (id)containerInfoRequest:(NSString *)containerName;
|
||||
- (BOOL)cdnEnabled;
|
||||
- (NSString *)cdnURI;
|
||||
- (NSString *)cdnSSLURI;
|
||||
- (NSUInteger)cdnTTL;
|
||||
|
||||
|
||||
// GET /<api version>/<account>
|
||||
// limit, marker, format, enabled_only=true
|
||||
+ (id)listRequest;
|
||||
+ (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker enabledOnly:(BOOL)enabledOnly;
|
||||
- (NSArray *)containers;
|
||||
|
||||
|
||||
// PUT /<api version>/<account>/<container>
|
||||
// PUT operations against a Container are used to CDN-enable that Container.
|
||||
// Include an HTTP header of X-TTL to specify a custom TTL.
|
||||
+ (id)putRequestWithContainer:(NSString *)containerName;
|
||||
+ (id)putRequestWithContainer:(NSString *)containerName ttl:(NSUInteger)ttl;
|
||||
// returns: - (NSString *)cdnURI;
|
||||
|
||||
// POST /<api version>/<account>/<container>
|
||||
// POST operations against a CDN-enabled Container are used to adjust CDN attributes.
|
||||
// The POST operation can be used to set a new TTL cache expiration or to enable/disable public sharing over the CDN.
|
||||
// X-TTL: 86400
|
||||
// X-CDN-Enabled: True
|
||||
+ (id)postRequestWithContainer:(NSString *)containerName;
|
||||
+ (id)postRequestWithContainer:(NSString *)containerName cdnEnabled:(BOOL)cdnEnabled ttl:(NSUInteger)ttl;
|
||||
// returns: - (NSString *)cdnURI;
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// ASICloudFilesCDNRequest.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesCDNRequest.h"
|
||||
#import "ASICloudFilesContainerXMLParserDelegate.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesCDNRequest
|
||||
|
||||
@synthesize accountName, containerName, xmlParserDelegate;
|
||||
|
||||
+ (id)cdnRequestWithMethod:(NSString *)method query:(NSString *)query {
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@%@", [ASICloudFilesRequest cdnManagementURL], query];
|
||||
ASICloudFilesCDNRequest *request = [[[ASICloudFilesCDNRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)cdnRequestWithMethod:(NSString *)method containerName:(NSString *)containerName {
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/%@", [ASICloudFilesRequest cdnManagementURL], containerName];
|
||||
ASICloudFilesCDNRequest *request = [[[ASICloudFilesCDNRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
request.containerName = containerName;
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark HEAD - Container Info
|
||||
|
||||
+ (id)containerInfoRequest:(NSString *)containerName {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"HEAD" containerName:containerName];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (BOOL)cdnEnabled {
|
||||
NSNumber *enabled = [[self responseHeaders] objectForKey:@"X-CDN-Enabled"];
|
||||
if (!enabled) {
|
||||
enabled = [[self responseHeaders] objectForKey:@"X-Cdn-Enabled"];
|
||||
}
|
||||
return [enabled boolValue];
|
||||
}
|
||||
|
||||
- (NSString *)cdnURI {
|
||||
NSString *uri = [[self responseHeaders] objectForKey:@"X-CDN-URI"];
|
||||
if (!uri) {
|
||||
uri = [[self responseHeaders] objectForKey:@"X-Cdn-Uri"];
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
- (NSString *)cdnSSLURI {
|
||||
NSString *uri = [[self responseHeaders] objectForKey:@"X-CDN-SSL-URI"];
|
||||
if (!uri) {
|
||||
uri = [[self responseHeaders] objectForKey:@"X-Cdn-Ssl-Uri"];
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
- (NSUInteger)cdnTTL {
|
||||
NSNumber *ttl = [[self responseHeaders] objectForKey:@"X-TTL"];
|
||||
if (!ttl) {
|
||||
ttl = [[self responseHeaders] objectForKey:@"X-Ttl"];
|
||||
}
|
||||
return [ttl intValue];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GET - CDN Container Lists
|
||||
|
||||
+ (id)listRequest {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"GET" query:@"?format=xml"];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker enabledOnly:(BOOL)enabledOnly {
|
||||
NSString *query = @"?format=xml";
|
||||
|
||||
if (limit > 0) {
|
||||
query = [query stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]];
|
||||
}
|
||||
|
||||
if (marker) {
|
||||
query = [query stringByAppendingString:[NSString stringWithFormat:@"&marker=%@", marker]];
|
||||
}
|
||||
|
||||
if (limit > 0) {
|
||||
query = [query stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]];
|
||||
}
|
||||
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"GET" query:query];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (NSArray *)containers {
|
||||
if (xmlParserDelegate.containerObjects) {
|
||||
return xmlParserDelegate.containerObjects;
|
||||
}
|
||||
|
||||
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease];
|
||||
if (xmlParserDelegate == nil) {
|
||||
xmlParserDelegate = [[ASICloudFilesContainerXMLParserDelegate alloc] init];
|
||||
}
|
||||
|
||||
[parser setDelegate:xmlParserDelegate];
|
||||
[parser setShouldProcessNamespaces:NO];
|
||||
[parser setShouldReportNamespacePrefixes:NO];
|
||||
[parser setShouldResolveExternalEntities:NO];
|
||||
[parser parse];
|
||||
|
||||
return xmlParserDelegate.containerObjects;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark PUT - CDN Enable Container
|
||||
|
||||
// PUT /<api version>/<account>/<container>
|
||||
// PUT operations against a Container are used to CDN-enable that Container.
|
||||
// Include an HTTP header of X-TTL to specify a custom TTL.
|
||||
+ (id)putRequestWithContainer:(NSString *)containerName {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"PUT" containerName:containerName];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)putRequestWithContainer:(NSString *)containerName ttl:(NSUInteger)ttl {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"PUT" containerName:containerName];
|
||||
[request addRequestHeader:@"X-Ttl" value:[NSString stringWithFormat:@"%i", ttl]];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark POST - Adjust CDN Attributes
|
||||
|
||||
// POST /<api version>/<account>/<container>
|
||||
// POST operations against a CDN-enabled Container are used to adjust CDN attributes.
|
||||
// The POST operation can be used to set a new TTL cache expiration or to enable/disable public sharing over the CDN.
|
||||
// X-TTL: 86400
|
||||
// X-CDN-Enabled: True
|
||||
+ (id)postRequestWithContainer:(NSString *)containerName {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"POST" containerName:containerName];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)postRequestWithContainer:(NSString *)containerName cdnEnabled:(BOOL)cdnEnabled ttl:(NSUInteger)ttl {
|
||||
ASICloudFilesCDNRequest *request = [ASICloudFilesCDNRequest cdnRequestWithMethod:@"POST" containerName:containerName];
|
||||
if (ttl > 0) {
|
||||
[request addRequestHeader:@"X-Ttl" value:[NSString stringWithFormat:@"%i", ttl]];
|
||||
}
|
||||
[request addRequestHeader:@"X-CDN-Enabled" value:cdnEnabled ? @"True" : @"False"];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Memory Management
|
||||
|
||||
-(void)dealloc {
|
||||
[accountName release];
|
||||
[containerName release];
|
||||
[xmlParserDelegate release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// ASICloudFilesContainer.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/7/10.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
|
||||
@interface ASICloudFilesContainer : NSObject {
|
||||
|
||||
// regular container attributes
|
||||
NSString *name;
|
||||
NSUInteger count;
|
||||
NSUInteger bytes;
|
||||
|
||||
// CDN container attributes
|
||||
BOOL cdnEnabled;
|
||||
NSUInteger ttl;
|
||||
NSString *cdnURL;
|
||||
BOOL logRetention;
|
||||
NSString *referrerACL;
|
||||
NSString *useragentACL;
|
||||
}
|
||||
|
||||
+ (id)container;
|
||||
|
||||
// regular container attributes
|
||||
@property (retain) NSString *name;
|
||||
@property (assign) NSUInteger count;
|
||||
@property (assign) NSUInteger bytes;
|
||||
|
||||
// CDN container attributes
|
||||
@property (assign) BOOL cdnEnabled;
|
||||
@property (assign) NSUInteger ttl;
|
||||
@property (retain) NSString *cdnURL;
|
||||
@property (assign) BOOL logRetention;
|
||||
@property (retain) NSString *referrerACL;
|
||||
@property (retain) NSString *useragentACL;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// ASICloudFilesContainer.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/7/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesContainer.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesContainer
|
||||
|
||||
// regular container attributes
|
||||
@synthesize name, count, bytes;
|
||||
|
||||
// CDN container attributes
|
||||
@synthesize cdnEnabled, ttl, cdnURL, logRetention, referrerACL, useragentACL;
|
||||
|
||||
+ (id)container {
|
||||
ASICloudFilesContainer *container = [[[self alloc] init] autorelease];
|
||||
return container;
|
||||
}
|
||||
|
||||
-(void) dealloc {
|
||||
[name release];
|
||||
[cdnURL release];
|
||||
[referrerACL release];
|
||||
[useragentACL release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// ASICloudFilesContainerRequest.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesRequest.h"
|
||||
|
||||
@class ASICloudFilesContainer, ASICloudFilesContainerXMLParserDelegate;
|
||||
|
||||
@interface ASICloudFilesContainerRequest : ASICloudFilesRequest {
|
||||
|
||||
// Internally used while parsing the response
|
||||
NSString *currentContent;
|
||||
NSString *currentElement;
|
||||
ASICloudFilesContainer *currentObject;
|
||||
ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate;
|
||||
}
|
||||
|
||||
@property (retain) NSString *currentElement;
|
||||
@property (retain) NSString *currentContent;
|
||||
@property (retain) ASICloudFilesContainer *currentObject;
|
||||
@property (retain) ASICloudFilesContainerXMLParserDelegate *xmlParserDelegate;
|
||||
|
||||
// HEAD /<api version>/<account>
|
||||
// HEAD operations against an account are performed to retrieve the number of Containers and the total bytes stored in Cloud Files for the account. This information is returned in two custom headers, X-Account-Container-Count and X-Account-Bytes-Used.
|
||||
+ (id)accountInfoRequest;
|
||||
- (NSUInteger)containerCount;
|
||||
- (NSUInteger)bytesUsed;
|
||||
|
||||
// GET /<api version>/<account>/<container>
|
||||
// Create a request to list all containers
|
||||
+ (id)listRequest;
|
||||
+ (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker;
|
||||
- (NSArray *)containers;
|
||||
|
||||
// PUT /<api version>/<account>/<container>
|
||||
+ (id)createContainerRequest:(NSString *)containerName;
|
||||
|
||||
// DELETE /<api version>/<account>/<container>
|
||||
+ (id)deleteContainerRequest:(NSString *)containerName;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// ASICloudFilesContainerRequest.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesContainerRequest.h"
|
||||
#import "ASICloudFilesContainer.h"
|
||||
#import "ASICloudFilesContainerXMLParserDelegate.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesContainerRequest
|
||||
|
||||
@synthesize currentElement, currentContent, currentObject;
|
||||
@synthesize xmlParserDelegate;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Constructors
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method containerName:(NSString *)containerName queryString:(NSString *)queryString {
|
||||
NSString *urlString;
|
||||
if (containerName == nil) {
|
||||
urlString = [NSString stringWithFormat:@"%@%@", [ASICloudFilesRequest storageURL], queryString];
|
||||
} else {
|
||||
urlString = [NSString stringWithFormat:@"%@/%@%@", [ASICloudFilesRequest storageURL], containerName, queryString];
|
||||
}
|
||||
|
||||
ASICloudFilesContainerRequest *request = [[[ASICloudFilesContainerRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method queryString:(NSString *)queryString {
|
||||
return [ASICloudFilesContainerRequest storageRequestWithMethod:method containerName:nil queryString:queryString];
|
||||
}
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method {
|
||||
return [ASICloudFilesContainerRequest storageRequestWithMethod:method queryString:@""];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark HEAD - Retrieve Container Count and Total Bytes Used
|
||||
|
||||
// HEAD /<api version>/<account>
|
||||
// HEAD operations against an account are performed to retrieve the number of Containers and the total bytes stored in Cloud Files for the account. This information is returned in two custom headers, X-Account-Container-Count and X-Account-Bytes-Used.
|
||||
+ (id)accountInfoRequest {
|
||||
ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"HEAD"];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (NSUInteger)containerCount {
|
||||
return [[[self responseHeaders] objectForKey:@"X-Account-Container-Count"] intValue];
|
||||
}
|
||||
|
||||
- (NSUInteger)bytesUsed {
|
||||
return [[[self responseHeaders] objectForKey:@"X-Account-Bytes-Used"] intValue];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GET - Retrieve Container List
|
||||
|
||||
+ (id)listRequestWithLimit:(NSUInteger)limit marker:(NSString *)marker {
|
||||
NSString *queryString = @"?format=xml";
|
||||
|
||||
if (limit > 0) {
|
||||
queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]];
|
||||
}
|
||||
|
||||
if (marker != nil) {
|
||||
queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&marker=%@", marker]];
|
||||
}
|
||||
|
||||
ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"GET" queryString:queryString];
|
||||
return request;
|
||||
}
|
||||
|
||||
// GET /<api version>/<account>/<container>
|
||||
// Create a request to list all containers
|
||||
+ (id)listRequest {
|
||||
ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"GET"
|
||||
queryString:@"?format=xml"];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (NSArray *)containers {
|
||||
if (xmlParserDelegate.containerObjects) {
|
||||
return xmlParserDelegate.containerObjects;
|
||||
}
|
||||
|
||||
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease];
|
||||
if (xmlParserDelegate == nil) {
|
||||
xmlParserDelegate = [[ASICloudFilesContainerXMLParserDelegate alloc] init];
|
||||
}
|
||||
|
||||
[parser setDelegate:xmlParserDelegate];
|
||||
[parser setShouldProcessNamespaces:NO];
|
||||
[parser setShouldReportNamespacePrefixes:NO];
|
||||
[parser setShouldResolveExternalEntities:NO];
|
||||
[parser parse];
|
||||
|
||||
return xmlParserDelegate.containerObjects;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark PUT - Create Container
|
||||
|
||||
// PUT /<api version>/<account>/<container>
|
||||
+ (id)createContainerRequest:(NSString *)containerName {
|
||||
ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"PUT" containerName:containerName queryString:@""];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark DELETE - Delete Container
|
||||
|
||||
// DELETE /<api version>/<account>/<container>
|
||||
+ (id)deleteContainerRequest:(NSString *)containerName {
|
||||
ASICloudFilesContainerRequest *request = [ASICloudFilesContainerRequest storageRequestWithMethod:@"DELETE" containerName:containerName queryString:@""];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Memory Management
|
||||
|
||||
- (void)dealloc {
|
||||
[currentElement release];
|
||||
[currentContent release];
|
||||
[currentObject release];
|
||||
[xmlParserDelegate release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// ASICloudFilesContainerXMLParserDelegate.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/10/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesRequest.h"
|
||||
|
||||
#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0)
|
||||
#import "ASINSXMLParserCompat.h"
|
||||
#endif
|
||||
|
||||
@class ASICloudFilesContainer;
|
||||
|
||||
@interface ASICloudFilesContainerXMLParserDelegate : NSObject <NSXMLParserDelegate> {
|
||||
|
||||
NSMutableArray *containerObjects;
|
||||
|
||||
// Internally used while parsing the response
|
||||
NSString *currentContent;
|
||||
NSString *currentElement;
|
||||
ASICloudFilesContainer *currentObject;
|
||||
}
|
||||
|
||||
@property (retain) NSMutableArray *containerObjects;
|
||||
|
||||
@property (retain) NSString *currentElement;
|
||||
@property (retain) NSString *currentContent;
|
||||
@property (retain) ASICloudFilesContainer *currentObject;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// ASICloudFilesContainerXMLParserDelegate.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/10/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesContainerXMLParserDelegate.h"
|
||||
#import "ASICloudFilesContainer.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesContainerXMLParserDelegate
|
||||
|
||||
@synthesize containerObjects, currentElement, currentContent, currentObject;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark XML Parser Delegate
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
|
||||
[self setCurrentElement:elementName];
|
||||
|
||||
if ([elementName isEqualToString:@"container"]) {
|
||||
[self setCurrentObject:[ASICloudFilesContainer container]];
|
||||
}
|
||||
[self setCurrentContent:@""];
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
|
||||
|
||||
if ([elementName isEqualToString:@"name"]) {
|
||||
[self currentObject].name = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"count"]) {
|
||||
[self currentObject].count = [[self currentContent] intValue];
|
||||
} else if ([elementName isEqualToString:@"bytes"]) {
|
||||
[self currentObject].bytes = [[self currentContent] intValue];
|
||||
} else if ([elementName isEqualToString:@"cdn_enabled"]) {
|
||||
[self currentObject].cdnEnabled = [[self currentObject] isEqual:@"True"];
|
||||
} else if ([elementName isEqualToString:@"ttl"]) {
|
||||
[self currentObject].ttl = [[self currentContent] intValue];
|
||||
} else if ([elementName isEqualToString:@"cdn_url"]) {
|
||||
[self currentObject].cdnURL = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"log_retention"]) {
|
||||
[self currentObject].logRetention = [[self currentObject] isEqual:@"True"];
|
||||
} else if ([elementName isEqualToString:@"referrer_acl"]) {
|
||||
[self currentObject].referrerACL = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"useragent_acl"]) {
|
||||
[self currentObject].useragentACL = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"container"]) {
|
||||
// we're done with this container. time to move on to the next
|
||||
if (containerObjects == nil) {
|
||||
containerObjects = [[NSMutableArray alloc] init];
|
||||
}
|
||||
[containerObjects addObject:currentObject];
|
||||
[self setCurrentObject:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
|
||||
[self setCurrentContent:[[self currentContent] stringByAppendingString:string]];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Memory Management
|
||||
|
||||
- (void)dealloc {
|
||||
[containerObjects release];
|
||||
[currentElement release];
|
||||
[currentContent release];
|
||||
[currentObject release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// ASICloudFilesObject.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/7/10.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
|
||||
@interface ASICloudFilesObject : NSObject {
|
||||
NSString *name;
|
||||
NSString *hash;
|
||||
NSUInteger bytes;
|
||||
NSString *contentType;
|
||||
NSDate *lastModified;
|
||||
NSData *data;
|
||||
NSMutableDictionary *metadata;
|
||||
}
|
||||
|
||||
@property (retain) NSString *name;
|
||||
@property (retain) NSString *hash;
|
||||
@property (assign) NSUInteger bytes;
|
||||
@property (retain) NSString *contentType;
|
||||
@property (retain) NSDate *lastModified;
|
||||
@property (retain) NSData *data;
|
||||
@property (retain) NSMutableDictionary *metadata;
|
||||
|
||||
+ (id)object;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// ASICloudFilesObject.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/7/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesObject.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesObject
|
||||
|
||||
@synthesize name, hash, bytes, contentType, lastModified, data, metadata;
|
||||
|
||||
+ (id)object {
|
||||
ASICloudFilesObject *object = [[[self alloc] init] autorelease];
|
||||
return object;
|
||||
}
|
||||
|
||||
-(void)dealloc {
|
||||
[name release];
|
||||
[hash release];
|
||||
[contentType release];
|
||||
[lastModified release];
|
||||
[data release];
|
||||
[metadata release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// ASICloudFilesObjectRequest.h
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesRequest.h"
|
||||
|
||||
#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0)
|
||||
#import "ASINSXMLParserCompat.h"
|
||||
#endif
|
||||
|
||||
@class ASICloudFilesObject;
|
||||
|
||||
@interface ASICloudFilesObjectRequest : ASICloudFilesRequest <NSXMLParserDelegate> {
|
||||
|
||||
|
||||
NSString *accountName;
|
||||
NSString *containerName;
|
||||
|
||||
// Internally used while parsing the response
|
||||
NSString *currentContent;
|
||||
NSString *currentElement;
|
||||
ASICloudFilesObject *currentObject;
|
||||
NSMutableArray *objects;
|
||||
|
||||
}
|
||||
|
||||
@property (retain) NSString *accountName;
|
||||
@property (retain) NSString *containerName;
|
||||
@property (retain) NSString *currentElement;
|
||||
@property (retain) NSString *currentContent;
|
||||
@property (retain) ASICloudFilesObject *currentObject;
|
||||
|
||||
|
||||
// HEAD /<api version>/<account>/<container>
|
||||
// HEAD operations against an account are performed to retrieve the number of Containers and the total bytes stored in Cloud Files for the account. This information is returned in two custom headers, X-Account-Container-Count and X-Account-Bytes-Used.
|
||||
+ (id)containerInfoRequest:(NSString *)containerName;
|
||||
- (NSUInteger)containerObjectCount;
|
||||
- (NSUInteger)containerBytesUsed;
|
||||
|
||||
// HEAD /<api version>/<account>/<container>/<object>
|
||||
// to get metadata
|
||||
+ (id)objectInfoRequest:(NSString *)containerName objectPath:(NSString *)objectPath;
|
||||
- (NSArray *)objects;
|
||||
|
||||
+ (id)listRequestWithContainer:(NSString *)containerName;
|
||||
+ (id)listRequestWithContainer:(NSString *)containerName limit:(NSUInteger)limit marker:(NSString *)marker prefix:(NSString *)prefix path:(NSString *)path;
|
||||
|
||||
// Conditional GET headers: If-Match • If-None-Match • If-Modified-Since • If-Unmodified-Since
|
||||
// HTTP Range header: “Range: bytes=0-5” • “Range: bytes=-5” • “Range: bytes=32-“
|
||||
+ (id)getObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath;
|
||||
- (ASICloudFilesObject *)object;
|
||||
|
||||
// PUT /<api version>/<account>/<container>/<object>
|
||||
// PUT operations are used to write, or overwrite, an Object's metadata and content.
|
||||
// The Object can be created with custom metadata via HTTP headers identified with the “X-Object-Meta-” prefix.
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName object:(ASICloudFilesObject *)object;
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath contentType:(NSString *)contentType objectData:(NSData *)objectData metadata:(NSDictionary *)metadata etag:(NSString *)etag;
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath contentType:(NSString *)contentType file:(NSString *)filePath metadata:(NSDictionary *)metadata etag:(NSString *)etag;
|
||||
|
||||
// POST /<api version>/<account>/<container>/<object>
|
||||
// POST operations against an Object name are used to set and overwrite arbitrary key/value metadata. You cannot use the POST operation to change any of the Object's other headers such as Content-Type, ETag, etc. It is not used to upload storage Objects (see PUT).
|
||||
// A POST request will delete all existing metadata added with a previous PUT/POST.
|
||||
+ (id)postObjectRequestWithContainer:(NSString *)containerName object:(ASICloudFilesObject *)object;
|
||||
+ (id)postObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath metadata:(NSDictionary *)metadata;
|
||||
|
||||
// DELETE /<api version>/<account>/<container>/<object>
|
||||
+ (id)deleteObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,261 @@
|
||||
//
|
||||
// ASICloudFilesObjectRequest.m
|
||||
//
|
||||
// Created by Michael Mayo on 1/6/10.
|
||||
//
|
||||
|
||||
#import "ASICloudFilesObjectRequest.h"
|
||||
#import "ASICloudFilesObject.h"
|
||||
|
||||
|
||||
@implementation ASICloudFilesObjectRequest
|
||||
|
||||
@synthesize currentElement, currentContent, currentObject;
|
||||
@synthesize accountName, containerName;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Constructors
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method containerName:(NSString *)containerName {
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/%@", [ASICloudFilesRequest storageURL], containerName];
|
||||
ASICloudFilesObjectRequest *request = [[[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
request.containerName = containerName;
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method containerName:(NSString *)containerName queryString:(NSString *)queryString {
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/%@%@", [ASICloudFilesRequest storageURL], containerName, queryString];
|
||||
ASICloudFilesObjectRequest *request = [[[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
request.containerName = containerName;
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)storageRequestWithMethod:(NSString *)method containerName:(NSString *)containerName objectPath:(NSString *)objectPath {
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/%@/%@", [ASICloudFilesRequest storageURL], containerName, objectPath];
|
||||
ASICloudFilesObjectRequest *request = [[[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]] autorelease];
|
||||
[request setRequestMethod:method];
|
||||
[request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
|
||||
request.containerName = containerName;
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark HEAD - Container Info
|
||||
|
||||
+ (id)containerInfoRequest:(NSString *)containerName {
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"HEAD" containerName:containerName];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (NSUInteger)containerObjectCount {
|
||||
return [[[self responseHeaders] objectForKey:@"X-Container-Object-Count"] intValue];
|
||||
}
|
||||
|
||||
- (NSUInteger)containerBytesUsed {
|
||||
return [[[self responseHeaders] objectForKey:@"X-Container-Bytes-Used"] intValue];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark HEAD - Object Info
|
||||
|
||||
+ (id)objectInfoRequest:(NSString *)containerName objectPath:(NSString *)objectPath {
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"HEAD" containerName:containerName objectPath:objectPath];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GET - List Objects
|
||||
|
||||
+ (NSString *)queryStringWithContainer:(NSString *)container limit:(NSUInteger)limit marker:(NSString *)marker prefix:(NSString *)prefix path:(NSString *)path {
|
||||
NSString *queryString = @"?format=xml";
|
||||
|
||||
if (limit && limit > 0) {
|
||||
queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&limit=%i", limit]];
|
||||
}
|
||||
if (marker) {
|
||||
queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&marker=%@", [marker stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
|
||||
}
|
||||
if (path) {
|
||||
queryString = [queryString stringByAppendingString:[NSString stringWithFormat:@"&path=%@", [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
|
||||
}
|
||||
|
||||
return queryString;
|
||||
}
|
||||
|
||||
+ (id)listRequestWithContainer:(NSString *)containerName limit:(NSUInteger)limit marker:(NSString *)marker prefix:(NSString *)prefix path:(NSString *)path {
|
||||
NSString *queryString = [ASICloudFilesObjectRequest queryStringWithContainer:containerName limit:limit marker:marker prefix:prefix path:path];
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"GET" containerName:containerName queryString:queryString];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)listRequestWithContainer:(NSString *)containerName {
|
||||
return [ASICloudFilesObjectRequest listRequestWithContainer:containerName limit:0 marker:nil prefix:nil path:nil];
|
||||
}
|
||||
|
||||
- (NSArray *)objects {
|
||||
if (objects) {
|
||||
return objects;
|
||||
}
|
||||
objects = [[[NSMutableArray alloc] init] autorelease];
|
||||
|
||||
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:[self responseData]] autorelease];
|
||||
[parser setDelegate:self];
|
||||
[parser setShouldProcessNamespaces:NO];
|
||||
[parser setShouldReportNamespacePrefixes:NO];
|
||||
[parser setShouldResolveExternalEntities:NO];
|
||||
[parser parse];
|
||||
return objects;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GET - Retrieve Object
|
||||
|
||||
+ (id)getObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath {
|
||||
return [ASICloudFilesObjectRequest storageRequestWithMethod:@"GET" containerName:containerName objectPath:objectPath];
|
||||
}
|
||||
|
||||
- (ASICloudFilesObject *)object {
|
||||
ASICloudFilesObject *object = [ASICloudFilesObject object];
|
||||
|
||||
NSString *path = [self url].path;
|
||||
NSRange range = [path rangeOfString:self.containerName];
|
||||
path = [path substringFromIndex:range.location + range.length + 1];
|
||||
|
||||
object.name = path;
|
||||
object.hash = [[self responseHeaders] objectForKey:@"ETag"];
|
||||
object.bytes = [[[self responseHeaders] objectForKey:@"Content-Length"] intValue];
|
||||
object.contentType = [[self responseHeaders] objectForKey:@"Content-Type"];
|
||||
object.lastModified = [[self responseHeaders] objectForKey:@"Last-Modified"];
|
||||
object.metadata = [NSMutableDictionary dictionary];
|
||||
|
||||
for (NSString *key in [[self responseHeaders] keyEnumerator]) {
|
||||
NSRange metaRange = [key rangeOfString:@"X-Object-Meta-"];
|
||||
if (metaRange.location == 0) {
|
||||
[object.metadata setObject:[[self responseHeaders] objectForKey:key] forKey:[key substringFromIndex:metaRange.length]];
|
||||
}
|
||||
}
|
||||
|
||||
object.data = [self responseData];
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark PUT - Upload Object
|
||||
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName object:(ASICloudFilesObject *)object {
|
||||
return [self putObjectRequestWithContainer:containerName objectPath:object.name contentType:object.contentType objectData:object.data metadata:object.metadata etag:nil];
|
||||
}
|
||||
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath contentType:(NSString *)contentType objectData:(NSData *)objectData metadata:(NSDictionary *)metadata etag:(NSString *)etag {
|
||||
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"PUT" containerName:containerName objectPath:objectPath];
|
||||
[request addRequestHeader:@"Content-Type" value:contentType];
|
||||
|
||||
// add metadata to headers
|
||||
if (metadata) {
|
||||
for (NSString *key in [metadata keyEnumerator]) {
|
||||
[request addRequestHeader:[NSString stringWithFormat:@"X-Object-Meta-%@", key] value:[metadata objectForKey:key]];
|
||||
}
|
||||
}
|
||||
|
||||
[request appendPostData:objectData];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (id)putObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath contentType:(NSString *)contentType file:(NSString *)filePath metadata:(NSDictionary *)metadata etag:(NSString *)etag
|
||||
{
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"PUT" containerName:containerName objectPath:objectPath];
|
||||
[request addRequestHeader:@"Content-Type" value:contentType];
|
||||
|
||||
// add metadata to headers
|
||||
if (metadata) {
|
||||
for (NSString *key in [metadata keyEnumerator]) {
|
||||
[request addRequestHeader:[NSString stringWithFormat:@"X-Object-Meta-%@", key] value:[metadata objectForKey:key]];
|
||||
}
|
||||
}
|
||||
|
||||
[request setShouldStreamPostDataFromDisk:YES];
|
||||
[request setPostBodyFilePath:filePath];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark POST - Set Object Metadata
|
||||
|
||||
+ (id)postObjectRequestWithContainer:(NSString *)containerName object:(ASICloudFilesObject *)object {
|
||||
return [self postObjectRequestWithContainer:containerName objectPath:object.name metadata:object.metadata];
|
||||
}
|
||||
|
||||
+ (id)postObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath metadata:(NSDictionary *)metadata {
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"POST" containerName:containerName objectPath:objectPath];
|
||||
|
||||
// add metadata to headers
|
||||
if (metadata) {
|
||||
for (NSString *key in [metadata keyEnumerator]) {
|
||||
[request addRequestHeader:[NSString stringWithFormat:@"X-Object-Meta-%@", key] value:[metadata objectForKey:key]];
|
||||
}
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark DELETE - Delete Object
|
||||
|
||||
+ (id)deleteObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath {
|
||||
ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"DELETE" containerName:containerName objectPath:objectPath];
|
||||
return request;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark XML Parser Delegate
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
|
||||
[self setCurrentElement:elementName];
|
||||
|
||||
if ([elementName isEqualToString:@"object"]) {
|
||||
[self setCurrentObject:[ASICloudFilesObject object]];
|
||||
}
|
||||
[self setCurrentContent:@""];
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
|
||||
if ([elementName isEqualToString:@"name"]) {
|
||||
[self currentObject].name = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"hash"]) {
|
||||
[self currentObject].hash = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"bytes"]) {
|
||||
[self currentObject].bytes = [[self currentContent] intValue];
|
||||
} else if ([elementName isEqualToString:@"content_type"]) {
|
||||
[self currentObject].contentType = [self currentContent];
|
||||
} else if ([elementName isEqualToString:@"last_modified"]) {
|
||||
[self currentObject].lastModified = [self dateFromString:[self currentContent]];
|
||||
} else if ([elementName isEqualToString:@"object"]) {
|
||||
// we're done with this object. time to move on to the next
|
||||
[objects addObject:currentObject];
|
||||
[self setCurrentObject:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
|
||||
[self setCurrentContent:[[self currentContent] stringByAppendingString:string]];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Memory Management
|
||||
|
||||
- (void)dealloc {
|
||||
[currentElement release];
|
||||
[currentContent release];
|
||||
[currentObject release];
|
||||
[accountName release];
|
||||
[containerName release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// ASICloudFilesRequest.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Michael Mayo on 22/12/09.
|
||||
// mike.mayo@rackspace.com or mike@overhrd.com
|
||||
// twitter.com/greenisus
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// A class for accessing data stored on the Rackspace Cloud Files Service
|
||||
// http://www.rackspacecloud.com/cloud_hosting_products/files
|
||||
//
|
||||
// Cloud Files Developer Guide:
|
||||
// http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
|
||||
@interface ASICloudFilesRequest : ASIHTTPRequest {
|
||||
}
|
||||
|
||||
+ (NSString *)storageURL;
|
||||
+ (NSString *)cdnManagementURL;
|
||||
+ (NSString *)authToken;
|
||||
|
||||
#pragma mark Rackspace Cloud Authentication
|
||||
|
||||
+ (id)authenticationRequest;
|
||||
+ (NSError *)authenticate;
|
||||
+ (NSString *)username;
|
||||
+ (void)setUsername:(NSString *)username;
|
||||
+ (NSString *)apiKey;
|
||||
+ (void)setApiKey:(NSString *)apiKey;
|
||||
|
||||
// helper to parse dates in the format returned by Cloud Files
|
||||
-(NSDate *)dateFromString:(NSString *)dateString;
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// ASICloudFilesRequest.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Michael Mayo on 22/12/09.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
// A class for accessing data stored on Rackspace's Cloud Files Service
|
||||
// http://www.rackspacecloud.com/cloud_hosting_products/files
|
||||
//
|
||||
// Cloud Files Developer Guide:
|
||||
// http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf
|
||||
|
||||
#import "ASICloudFilesRequest.h"
|
||||
|
||||
static NSString *username = nil;
|
||||
static NSString *apiKey = nil;
|
||||
static NSString *authToken = nil;
|
||||
static NSString *storageURL = nil;
|
||||
static NSString *cdnManagementURL = nil;
|
||||
static NSString *rackspaceCloudAuthURL = @"https://auth.api.rackspacecloud.com/v1.0";
|
||||
|
||||
static NSRecursiveLock *accessDetailsLock = nil;
|
||||
|
||||
@implementation ASICloudFilesRequest
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASICloudFilesRequest class]) {
|
||||
accessDetailsLock = [[NSRecursiveLock alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Attributes and Service URLs
|
||||
|
||||
+ (NSString *)authToken {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
+ (NSString *)storageURL {
|
||||
return storageURL;
|
||||
}
|
||||
|
||||
+ (NSString *)cdnManagementURL {
|
||||
return cdnManagementURL;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Authentication
|
||||
|
||||
+ (id)authenticationRequest
|
||||
{
|
||||
[accessDetailsLock lock];
|
||||
ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:rackspaceCloudAuthURL]] autorelease];
|
||||
[request addRequestHeader:@"X-Auth-User" value:username];
|
||||
[request addRequestHeader:@"X-Auth-Key" value:apiKey];
|
||||
[accessDetailsLock unlock];
|
||||
return request;
|
||||
}
|
||||
|
||||
+ (NSError *)authenticate
|
||||
{
|
||||
[accessDetailsLock lock];
|
||||
ASIHTTPRequest *request = [ASICloudFilesRequest authenticationRequest];
|
||||
[request startSynchronous];
|
||||
|
||||
if (![request error]) {
|
||||
NSDictionary *responseHeaders = [request responseHeaders];
|
||||
authToken = [responseHeaders objectForKey:@"X-Auth-Token"];
|
||||
storageURL = [responseHeaders objectForKey:@"X-Storage-Url"];
|
||||
cdnManagementURL = [responseHeaders objectForKey:@"X-CDN-Management-Url"];
|
||||
|
||||
// there is a bug in the Cloud Files API for some older accounts that causes
|
||||
// the CDN URL to come back in a slightly different header
|
||||
if (!cdnManagementURL) {
|
||||
cdnManagementURL = [responseHeaders objectForKey:@"X-Cdn-Management-Url"];
|
||||
}
|
||||
}
|
||||
[accessDetailsLock unlock];
|
||||
return [request error];
|
||||
}
|
||||
|
||||
+ (NSString *)username
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
+ (void)setUsername:(NSString *)newUsername
|
||||
{
|
||||
[accessDetailsLock lock];
|
||||
[username release];
|
||||
username = [newUsername retain];
|
||||
[accessDetailsLock unlock];
|
||||
}
|
||||
|
||||
+ (NSString *)apiKey {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
+ (void)setApiKey:(NSString *)newApiKey
|
||||
{
|
||||
[accessDetailsLock lock];
|
||||
[apiKey release];
|
||||
apiKey = [newApiKey retain];
|
||||
[accessDetailsLock unlock];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Date Parser
|
||||
|
||||
-(NSDate *)dateFromString:(NSString *)dateString
|
||||
{
|
||||
// We store our date formatter in the calling thread's dictionary
|
||||
// NSDateFormatter is not thread-safe, this approach ensures each formatter is only used on a single thread
|
||||
// This formatter can be reused many times in parsing a single response, so it would be expensive to keep creating new date formatters
|
||||
NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
|
||||
NSDateFormatter *dateFormatter = [threadDict objectForKey:@"ASICloudFilesResponseDateFormatter"];
|
||||
if (dateFormatter == nil) {
|
||||
dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
|
||||
[dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
|
||||
// example: 2009-11-04T19:46:20.192723
|
||||
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'H:mm:ss.SSSSSS"];
|
||||
[threadDict setObject:dateFormatter forKey:@"ASICloudFilesResponseDateFormatter"];
|
||||
}
|
||||
return [dateFormatter dateFromString:dateString];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user