Revision ef74c42f

b/Classes/AccountDetailsViewController.m
513 513
            [[account.manager authenticate]
514 514
             success:^(OpenStackRequest *request) {
515 515
                 if ([request isSuccess]) {
516
                     NSString *storageURLString = [[request responseHeaders] objectForKey:@"X-Storage-Url"];
517
                     if (storageURLString) {
518
                         account.filesURL = [NSURL URLWithString:storageURLString];
519
                     } else {
520
                         account.filesURL = [account.provider.authEndpointURL URLByAppendingPathComponent:account.username];
521
                     }
522 516
                     [account persist];
523 517
                     [[account.manager userCatalogForDisplaynames:nil UUIDs:[NSArray arrayWithObject:account.username]]
524 518
                      success:^(OpenStackRequest *request) {
......
550 544
            [[account.manager serviceCatalog]
551 545
             success:^(OpenStackRequest *request) {
552 546
                 if ([request isSuccess]) {
553
                     account.filesURL = [account.provider.authEndpointURL URLByAppendingPathComponent:account.username];
554 547
                     [account persist];
555 548
                     [[account.manager userCatalogForDisplaynames:nil UUIDs:[NSArray arrayWithObject:account.username]]
556 549
                      success:^(OpenStackRequest *request) {
b/Classes/AccountManager.h
33 33
- (APICallback *)getContainerInfo:(Container *)container;
34 34
- (APICallback *)createContainer:(Container *)container;
35 35
- (APICallback *)deleteContainer:(Container *)container;
36
- (void)getObjects:(Container *)container afterMarker:(NSString *)marker objectsBuffer:(NSMutableDictionary *)objectsBuffer;
37
- (void)getObjects:(Container *)container;
36
- (APICallback *)getObjects:(Container *)container;
38 37
- (APICallback *)writeContainerPolicy:(Container *)container;
39 38

  
40 39
- (APICallback *)getObjectInfo:(Container *)container object:(StorageObject *)object;
b/Classes/AccountManager.m
13 13
#import "Container.h"
14 14
#import "Folder.h"
15 15
#import "StorageObject.h"
16
#import "GetObjectsRequest.h"
17 16
#import "ASINetworkQueue.h"
18 17
#import "APICallback.h"
19 18
#import "JSON.h"
20 19
#import "OpenStackAppDelegate.h"
21 20
#import "NSString+Conveniences.h"
22 21

  
22
@interface AccountManager()
23
- (void)start:(OpenStackRequest *)request success:(APIResponseBlock)success failure:(APIResponseBlock)failure;
24
- (void)retryWithUpdatedURL:(OpenStackRequest *)request success:(APIResponseBlock)success failure:(APIResponseBlock)failure;
25
@end
26

  
23 27
@implementation AccountManager
24 28

  
25 29
@synthesize account, queue;
26 30

  
27 31
#pragma mark - Callbacks
28 32

  
29
- (APICallback *)callbackWithRequest:(id)request success:(APIResponseBlock)success failure:(APIResponseBlock)failure {
30
    APICallback *callback = [[[APICallback alloc] initWithAccount:self.account request:request] autorelease];
31
    ((OpenStackRequest *)request).delegate = self;
32
    ((OpenStackRequest *)request).callback = callback;
33
    
33
- (void)start:(OpenStackRequest *)request success:(APIResponseBlock)success failure:(APIResponseBlock)failure {
34 34
    [request setCompletionBlock:^{
35 35
        if ([request isSuccess]) {
36
            if (request.followUpSelectorString) {
37
                OpenStackRequest *followUpRequest = [self performSelector:NSSelectorFromString(request.followUpSelectorString)
38
                                                               withObject:request];
39
                if (followUpRequest) {
40
                    [self start:followUpRequest success:success failure:failure];
41
                    return;
42
                }
43
            }
36 44
            success(request);
37 45
            [request notify];
46
        } else if (request.retryWithUpdatedURL && ((request.responseStatusCode == 401) || (request.responseStatusCode == 404))) {
47
            [self retryWithUpdatedURL:request success:success failure:failure];
38 48
        } else {
39 49
            failure(request);
40 50
            [request notify];
41 51
        }
42 52
    }];
43 53
    [request setFailedBlock:^{
54
        if (request.retryWithUpdatedURL && ((request.responseStatusCode == 401) || (request.responseStatusCode == 404))) {
55
            [self retryWithUpdatedURL:request success:success failure:failure];
56
        } else {
57
            failure(request);
58
            [request notify];
59
        }
60
    }];
61
    [request startAsynchronous];
62
}
63

  
64
- (void)retryWithUpdatedURL:(OpenStackRequest *)request success:(APIResponseBlock)success failure:(APIResponseBlock)failure {
65
    [[self serviceCatalog] success:^(OpenStackRequest *serviceRequest) {
66
        OpenStackRequest *newRequest = [[request copy] autorelease];
67
        newRequest.retryWithUpdatedURL = NO;
68
        [self start:newRequest success:success failure:failure];
69
    } failure:^(OpenStackRequest *serviceRequest) {
44 70
        failure(request);
45 71
        [request notify];
46 72
    }];
47
    [request startAsynchronous];
73
}
74

  
75
- (APICallback *)callbackWithRequest:(OpenStackRequest *)request success:(APIResponseBlock)success failure:(APIResponseBlock)failure {
76
    APICallback *callback = [[[APICallback alloc] initWithAccount:self.account request:request] autorelease];
77
    request.delegate = self;
78
    request.callback = callback;
79
    [self start:request success:success failure:failure];
48 80
    return callback;
49 81
}
50 82

  
51
- (APICallback *)callbackWithRequest:(id)request success:(APIResponseBlock)success {
83
- (APICallback *)callbackWithRequest:(OpenStackRequest *)request success:(APIResponseBlock)success {
52 84
    return [self callbackWithRequest:request success:success failure:^(OpenStackRequest *request){}];
53 85
}
54 86

  
55
- (APICallback *)callbackWithRequest:(id)request {
87
- (APICallback *)callbackWithRequest:(OpenStackRequest *)request {
56 88
    return [self callbackWithRequest:request success:^(OpenStackRequest *request){} failure:^(OpenStackRequest *request){}];
57 89
}
58 90

  
......
138 170

  
139 171
- (APICallback *)getSharingAccounts {
140 172
    __block OpenStackRequest *request = [OpenStackRequest getSharingAccountsRequest:self.account];
173
    request.followUpSelectorString = NSStringFromSelector(@selector(followUpGetSharingAccountsRequest:));
174
    request.notificationURL = request.url;
141 175
    return [self callbackWithRequest:request];
142 176
}
143 177

  
178
- (OpenStackRequest *)followUpGetSharingAccountsRequest:(OpenStackRequest *)request {
179
    NSArray *jsonSharingAccounts = [request jsonSharingAccounts];
180
    NSMutableDictionary *sharingAccountsBuffer = [request.userInfo objectForKey:@"sharingAccountsBuffer"];
181
    for (NSDictionary *dict in jsonSharingAccounts) {
182
        [sharingAccountsBuffer setObject:dict forKey:[dict objectForKey:@"name"]];
183
    }
184
    
185
    if (jsonSharingAccounts.count < 10000) {
186
        return nil;
187
    } else {
188
        __block OpenStackRequest *followUpRequest = [OpenStackRequest getSharingAccountsRequest:self.account
189
                                                                                         marker:[[jsonSharingAccounts lastObject] objectForKey:@"name"]
190
                                                                          sharingAccountsBuffer:sharingAccountsBuffer];
191
        followUpRequest.callback = request.callback;
192
        followUpRequest.followUpSelectorString = request.followUpSelectorString;
193
        followUpRequest.notificationURL = request.notificationURL;
194
        return followUpRequest;
195
    }
196
}
197

  
144 198
#pragma mark Account
145 199

  
146 200
- (APICallback *)getStorageAccountInfo {
......
158 212

  
159 213
- (APICallback *)getContainers {
160 214
    __block OpenStackRequest *request = [OpenStackRequest getContainersRequest:self.account];
215
    request.followUpSelectorString = NSStringFromSelector(@selector(followUpGetContainersRequest:));
216
    request.notificationURL = request.url;
161 217
    return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
162
        self.account.containers = [request containers];
218
        NSMutableDictionary *containersBuffer = [request.userInfo objectForKey:@"containersBuffer"];
219
        self.account.containers = (containersBuffer ? containersBuffer : [NSMutableDictionary dictionary]);
163 220
        NSString *bytesUsedString = [request.responseHeaders objectForKey:@"X-Account-Bytes-Used"];
164 221
        self.account.bytesUsed = (bytesUsedString ?
165 222
                                  [NSNumber numberWithUnsignedLongLong:strtoull([bytesUsedString UTF8String], NULL, 0)] : nil);
......
170 227
    }];
171 228
}
172 229

  
230
- (OpenStackRequest *)followUpGetContainersRequest:(OpenStackRequest *)request {
231
    NSArray *jsonContainers = [request jsonContainers];
232
    NSMutableDictionary *containersBuffer = [request.userInfo objectForKey:@"containersBuffer"];
233
    for (NSDictionary *dict in jsonContainers) {
234
        Container *container = [Container fromJSON:dict];
235
        [containersBuffer setObject:container forKey:container.name];
236
    }
237
    
238
    if (jsonContainers.count < 10000) {
239
        return nil;
240
    } else {
241
        __block OpenStackRequest *followUpRequest = [OpenStackRequest getContainersRequest:self.account
242
                                                                                 marker:[[jsonContainers lastObject] objectForKey:@"name"]
243
                                                                          containersBuffer:containersBuffer];
244
        followUpRequest.callback = request.callback;
245
        followUpRequest.followUpSelectorString = request.followUpSelectorString;
246
        followUpRequest.notificationURL = request.notificationURL;
247
        return followUpRequest;
248
    }
249
}
250

  
173 251
- (APICallback *)writeAccountMetadata:(NSDictionary *)accountInfo {
174 252
    __block OpenStackRequest *request = [OpenStackRequest writeAccountMetadataRequest:self.account withAccountInfo:accountInfo];
175 253
    return [self callbackWithRequest:request];
......
204 282
    }];
205 283
}
206 284

  
207
- (void)getObjects:(Container *)container afterMarker:(NSString *)marker objectsBuffer:(NSMutableDictionary *)objectsBuffer {
208
    if (!self.queue) {
209
        self.queue = [ASINetworkQueue queue];
210
        self.queue.shouldCancelAllRequestsOnFailure = NO;
211
        [self.queue go];
212
    }
213
    GetObjectsRequest *request = [GetObjectsRequest request:self.account container:container marker:marker objectsBuffer:objectsBuffer];
214
    [queue addOperation:request];
285
- (APICallback *)getObjects:(Container *)container {
286
    __block OpenStackRequest *request = [OpenStackRequest getObjectsRequest:self.account container:container];
287
    request.followUpSelectorString = NSStringFromSelector(@selector(followUpGetObjectsRequest:));
288
    request.notificationURL = request.url;
289
    return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
290
        NSMutableDictionary *objectsBuffer = [request.userInfo objectForKey:@"objectsBuffer"];
291
        container.rootFolder = [Folder folder];
292
        container.rootFolder.objects = (objectsBuffer ? objectsBuffer : [NSMutableDictionary dictionary]);
293
        [self.account persist];
294
    }];
215 295
}
216 296

  
217
- (void)getObjects:(Container *)container {
218
    [self getObjects:container afterMarker:nil objectsBuffer:nil];
297
- (OpenStackRequest *)followUpGetObjectsRequest:(OpenStackRequest *)request {
298
    NSArray *jsonObjects = [request jsonObjects];
299
    NSMutableDictionary *objectsBuffer = [request.userInfo objectForKey:@"objectsBuffer"];
300
    for (NSDictionary *dict in jsonObjects) {
301
        StorageObject *object = [StorageObject fromJSON:dict];
302
        [objectsBuffer setObject:object forKey:object.name];
303
    }
304
    
305
    if (jsonObjects.count < 10000) {
306
        return nil;
307
    } else {
308
        __block OpenStackRequest *followUpRequest = [OpenStackRequest getObjectsRequest:self.account
309
                                                                              container:[request.userInfo objectForKey:@"container"]
310
                                                                                 marker:[[jsonObjects lastObject] objectForKey:@"name"]
311
                                                                          objectsBuffer:objectsBuffer];
312
        followUpRequest.callback = request.callback;
313
        followUpRequest.followUpSelectorString = request.followUpSelectorString;
314
        followUpRequest.notificationURL = request.notificationURL;
315
        return followUpRequest;
316
    }
219 317
}
220 318

  
221 319
- (APICallback *)writeContainerPolicy:(Container *)container {
......
343 441
    [[NSNotificationCenter defaultCenter] postNotification:notification];
344 442
}
345 443

  
346
#pragma mark - Observers
347

  
348
- (void)getObjectsSucceeded:(OpenStackRequest *)request {
349
    if ([request isSuccess]) {
350
        Container *container = [request.userInfo objectForKey:@"container"];
351
        NSMutableDictionary *objects = [request objects];
352
        container.rootFolder = [Folder folder];
353
        container.rootFolder.objects = objects;
354
        [self.account persist];
355
        
356
        NSNotification *notification = [NSNotification notificationWithName:@"getObjectsSucceeded" object:self.account userInfo:[NSDictionary dictionaryWithObject:container forKey:@"container"]];
357
        [[NSNotificationCenter defaultCenter] postNotification:notification];
358
    } else {
359
        NSNotification *notification = [NSNotification notificationWithName:@"getObjectsFailed" object:self.account userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
360
        [[NSNotificationCenter defaultCenter] postNotification:notification];
361
    }
362
}
363

  
364
- (void)getObjectsFailed:(OpenStackRequest *)request {
365
    NSNotification *notification = [NSNotification notificationWithName:@"getObjectsFailed" object:self.account userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
366
    [[NSNotificationCenter defaultCenter] postNotification:notification];
367
}
368

  
369 444
@end
b/Classes/AccountSettingsViewController.m
518 518
                     account.authToken = request.account.authToken;
519 519
                     account.username = request.account.username;
520 520
                     account.ignoreSSLErrors = request.account.ignoreSSLErrors;
521
                     NSString *storageURLString = [[request responseHeaders] objectForKey:@"X-Storage-Url"];
522
                     if (storageURLString) {
523
                         account.filesURL = [NSURL URLWithString:storageURLString];
524
                     } else {
525
                         account.filesURL = [account.provider.authEndpointURL URLByAppendingPathComponent:account.username];
526
                     }
527 521
                     [account persist];
528 522
                     [[account.manager userCatalogForDisplaynames:nil
529 523
                                                            UUIDs:[NSArray arrayWithObject:account.username]]
......
561 555
                     account.authToken = request.account.authToken;
562 556
                     account.username = request.account.username;
563 557
                     account.ignoreSSLErrors = request.account.ignoreSSLErrors;
564
                     account.filesURL = [account.provider.authEndpointURL URLByAppendingPathComponent:account.username];
565 558
                     [account persist];
566 559
                     [[account.manager userCatalogForDisplaynames:nil UUIDs:[NSArray arrayWithObject:account.username]]
567 560
                      success:^(OpenStackRequest *request) {
b/Classes/FolderViewController.h
34 34
    FolderSortDirection sortNameDirection;
35 35
    FolderSortDirection sortDateDirection;
36 36
    
37
    id successObserver;
38
    id failureObserver;
39

  
40 37
    FolderDetailViewController *folderDetailVC;
41 38
    StorageObjectViewController *selectedObjectViewController;
42 39
    UIDocumentInteractionController *documentInteractionController;
b/Classes/FolderViewController.m
747 747
- (void)refreshButtonPressed:(id)sender {
748 748
    __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Loading..."
749 749
                                                                                                   andAddToView:self.view];
750
    [self.account.manager getObjects:self.container];
751
    successObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"getObjectsSucceeded"
752
                                                                        object:self.container
753
                                                                         queue:[NSOperationQueue mainQueue]
754
                                                                    usingBlock:^(NSNotification* notification)
755
    {
750
    [[self.account.manager getObjects:self.container] success:^(OpenStackRequest *request) {
756 751
        [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
757 752
        [self reloadFolderViewControllers];
758 753
        if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
759
           if (self.selectedObjectViewController) {
760
               [self.selectedObjectViewController reloadMetadataSection];
761
           } else if ([self.folder isEqual:container.rootFolder]) {
762
               [containersViewController.containerDetailViewController reloadMetadataSection];
763
           } else if ([parentFolderViewController.folderDetailVC.navigationController.topViewController 
764
                       isEqual:parentFolderViewController.folderDetailVC]) {
765
               [parentFolderViewController.folderDetailVC reloadMetadataSection];
766
           }
754
            if (self.selectedObjectViewController) {
755
                [self.selectedObjectViewController reloadMetadataSection];
756
            } else if ([self.folder isEqual:container.rootFolder]) {
757
                [containersViewController.containerDetailViewController reloadMetadataSection];
758
            } else if ([parentFolderViewController.folderDetailVC.navigationController.topViewController
759
                        isEqual:parentFolderViewController.folderDetailVC]) {
760
                [parentFolderViewController.folderDetailVC reloadMetadataSection];
761
            }
767 762
        }
768
        [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
769
        [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
770
    }];
771
    failureObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"getObjectsFailed"
772
                                                                        object:self.container
773
                                                                         queue:[NSOperationQueue mainQueue]
774
                                                                    usingBlock:^(NSNotification* notification)
775
    {
763
    } failure:^(OpenStackRequest *request) {
776 764
        [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
777 765
        [self reloadData];
778 766
        [self alert:@"Error" message:@"Failed to retrieve files from server."];
779
        [[NSNotificationCenter defaultCenter] removeObserver:successObserver];
780
        [[NSNotificationCenter defaultCenter] removeObserver:failureObserver];
781 767
    }];
782 768
}
783 769

  
/dev/null
1
//
2
//  GetObjectsRequest.h
3
//  OpenStack
4
//
5
//  Created by Mike Mayo on 12/24/10.
6
//  The OpenStack project is provided under the Apache 2.0 license.
7
//
8

  
9
#import "OpenStackRequest.h"
10

  
11
@class OpenStackAccount, Container;
12

  
13
@interface GetObjectsRequest : OpenStackRequest {
14
    Container *container;
15
}
16

  
17
@property (nonatomic, retain) Container *container;
18

  
19
+ (id)request:(OpenStackAccount *)account container:(Container *)container;
20
+ (id)request:(OpenStackAccount *)account container:(Container *)container
21
       marker:(NSString *)marker objectsBuffer:(NSMutableDictionary *)objectsBuffer;
22

  
23
@end
/dev/null
1
//
2
//  GetObjectsRequest.m
3
//  OpenStack
4
//
5
//  Created by Mike Mayo on 12/24/10.
6
//  The OpenStack project is provided under the Apache 2.0 license.
7
//
8

  
9
#import "GetObjectsRequest.h"
10
#import "OpenStackAccount.h"
11
#import "Container.h"
12
#import "StorageObject.h"
13
#import "AccountManager.h"
14
#import "Folder.h"
15
#import "SBJSON.h"
16
#import "NSString+Conveniences.h"
17

  
18
@implementation GetObjectsRequest
19

  
20
@synthesize container;
21

  
22
#pragma mark - Constructors
23

  
24
+ (id)request:(OpenStackAccount *)account method:(NSString *)method url:(NSURL *)url {
25
	GetObjectsRequest *request = [[[self
26
                                    alloc] initWithURL:url] autorelease];
27
    request.account = account;
28
	request.requestMethod = method;
29
	[request addRequestHeader:@"X-Auth-Token" value:account.authToken];
30
    [request addRequestHeader:@"Content-Type" value:@"application/json"];
31
    request.timeOutSeconds = 60;
32
    request.numberOfTimesToRetryOnTimeout = 5;
33
    request.validatesSecureCertificate = !account.ignoreSSLErrors;
34
	return request;
35
}
36

  
37
+ (id)filesRequest:(OpenStackAccount *)account method:(NSString *)method path:(NSString *)path marker:(NSString *)marker {
38
    NSString *urlString = [account.filesURL description];
39
    if (account.sharingAccount) {
40
        urlString = [NSString stringWithFormat:@"%@%@",
41
                     [urlString substringToIndex:[urlString rangeOfString:account.username].location],
42
                     account.sharingAccount];
43
    }
44
	NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@?format=json%@%@",
45
                                       urlString,
46
                                       path,
47
                                       (account.shared ? @"&shared=" : @""),
48
                                       (marker ? [NSString stringWithFormat:@"&marker=%@", marker] : @"")]];
49
    return [self request:account method:method url:url];
50
}
51

  
52
+ (id)filesRequest:(OpenStackAccount *)account method:(NSString *)method path:(NSString *)path {
53
    return [self filesRequest:account method:method path:path marker:nil];
54
}
55

  
56
+ (id)request:(OpenStackAccount *)account container:(Container *)container {
57
    return [self request:account container:container marker:nil objectsBuffer:nil];
58
}
59

  
60
+ (id)request:(OpenStackAccount *)account container:(Container *)container
61
       marker:(NSString *)marker objectsBuffer:(NSMutableDictionary *)objectsBuffer {
62
    GetObjectsRequest *request = [self filesRequest:account
63
                                             method:@"GET"
64
                                               path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]
65
                                             marker:[NSString encodeToPercentEscape:marker]];
66
    request.container = container;
67
    if (objectsBuffer == nil)
68
        objectsBuffer = [NSMutableDictionary dictionary];
69
    request.userInfo = [NSMutableDictionary dictionaryWithObject:objectsBuffer forKey:@"objectsBuffer"];
70
    return request;
71
}
72

  
73
#pragma mark - ASIHTTPRequest Overrides
74

  
75
- (void)requestFinished {
76
    if ([self isSuccess]) {
77
        Container *aContainer = self.container;
78
        NSMutableDictionary *objects = [self objects];
79
        NSMutableDictionary *objectsBuffer = [self.userInfo objectForKey:@"objectsBuffer"];
80
        [objectsBuffer addEntriesFromDictionary:objects];
81
        if (objects.count < 10000) {
82
            aContainer.rootFolder = [Folder folder];
83
            aContainer.rootFolder.objects = objectsBuffer;
84
            [self.account persist];
85
            NSNotification *notification = [NSNotification notificationWithName:@"getObjectsSucceeded" object:self.container
86
                                                                       userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
87
                                                                                 aContainer, @"container",
88
                                                                                 self, @"request",
89
                                                                                 nil]];
90
            [[NSNotificationCenter defaultCenter] postNotification:notification];
91
        } else {
92
            SBJSON *parser = [[[SBJSON alloc] init] autorelease];
93
            NSArray *jsonObjects = [parser objectWithString:[self responseString]];
94
            NSString *marker = [[jsonObjects lastObject] objectForKey:@"name"];
95
            [self.account.manager getObjects:self.container afterMarker:marker objectsBuffer:objectsBuffer];
96
        }        
97
    } else {
98
        NSNotification *notification = [NSNotification notificationWithName:@"getObjectsFailed" object:self.container userInfo:[NSDictionary dictionaryWithObject:self forKey:@"request"]];
99
        [[NSNotificationCenter defaultCenter] postNotification:notification];
100
    }
101
    
102
    [super requestFinished];
103
}
104

  
105
- (void)failWithError:(NSError *)theError {
106
    NSNotification *notification = [NSNotification notificationWithName:@"getObjectsFailed" object:self.container userInfo:[NSDictionary dictionaryWithObject:self forKey:@"request"]];
107
    [[NSNotificationCenter defaultCenter] postNotification:notification];
108
    [super failWithError:theError];
109
}
110

  
111
#pragma mark - Memory Management
112

  
113
- (void)dealloc {
114
    [container release];
115
    [super dealloc];
116
}
117

  
118
@end
b/Classes/OpenStackAccount.h
18 18
@property (nonatomic, retain) NSString *username;
19 19
@property (nonatomic, retain) NSString *apiKey;
20 20
@property (nonatomic, retain) NSString *authToken;
21
@property (nonatomic, retain) NSURL *filesURL;
21
@property (nonatomic, readonly) NSURL *filesURL;
22 22
@property (nonatomic, retain) AccountManager *manager;
23 23
@property (nonatomic, retain) NSNumber *bytesUsed;
24 24
@property (nonatomic, retain) NSNumber *policyQuota;
b/Classes/OpenStackAccount.m
51 51
        self.provider = [self decode:coder key:@"provider"];
52 52
        self.username = [self decode:coder key:@"username"];
53 53
        
54
        self.filesURL = [self decode:coder key:@"filesURL"];
55 54
        self.bytesUsed = [self decode:coder key:@"bytesUsed"];
56 55
        self.policyQuota = [self decode:coder key:@"policyQuota"];
57 56
        
......
80 79
    copy.apiKey = [[self.apiKey copy] autorelease];
81 80
    copy.authToken = [[self.authToken copy] autorelease];
82 81
    
83
    copy.filesURL = [[self.filesURL copy] autorelease];
84 82
    copy.bytesUsed = [[self.bytesUsed copy] autorelease];
85 83
    copy.policyQuota = [[self.policyQuota copy] autorelease];
86 84
    
......
98 96
    [coder encodeObject:provider forKey:@"provider"];
99 97
    [coder encodeObject:username forKey:@"username"];
100 98
    
101
    [coder encodeObject:filesURL forKey:@"filesURL"];
102 99
    [coder encodeObject:bytesUsed forKey:@"bytesUsed"];
103 100
    [coder encodeObject:policyQuota forKey:@"policyQuota"];
104 101
    
......
120 117

  
121 118
#pragma mark - Properties
122 119

  
120
- (NSURL *)filesURL {
121
    return [self.provider.authEndpointURL URLByAppendingPathComponent:self.username];
122
}
123

  
123 124
- (void)setShared:(BOOL)aShared {
124 125
    if (shared != aShared) {
125 126
        self.containers = nil;
......
243 244
    [manager release];
244 245
    [provider release];
245 246
    [username release];
246
    [filesURL release];
247 247
    [containers release];
248 248
    [sharingAccount release];
249 249
    [bytesUsed release];
b/Classes/OpenStackRequest.h
10 10

  
11 11
@class OpenStackAccount, Container, StorageObject, APICallback, ErrorAlerter;
12 12

  
13
@interface OpenStackRequest : ASIHTTPRequest {
13
@interface OpenStackRequest : ASIHTTPRequest <NSCopying> {
14 14
    OpenStackAccount *account;
15 15
    ASIBasicBlock backupCompletionBlock;
16 16
    ASIBasicBlock backupFailureBlock;
17 17
    APICallback *callback;
18
    BOOL retryWithUpdatedURL;
19
    NSString *followUpSelectorString;
20
    NSURL *notificationURL;
18 21
}
19 22

  
20 23
@property (nonatomic, retain) OpenStackAccount *account;
21 24
@property (nonatomic, retain) APICallback *callback;
22 25
@property (nonatomic, retain) ErrorAlerter *errorAlerter;
26
@property (nonatomic, assign) BOOL retryWithUpdatedURL;
27
@property (nonatomic, retain) NSString *followUpSelectorString;
28
@property (nonatomic, retain) NSURL *notificationURL;
23 29

  
24 30
+ (id)requestWithoutToken:(OpenStackAccount *)account method:(NSString *)method url:(NSURL *)url;
25 31
+ (id)request:(OpenStackAccount *)account method:(NSString *)method url:(NSURL *)url;
......
37 43
- (NSDictionary *)UUIDCatalog;
38 44

  
39 45
+ (id)authenticationRequest:(OpenStackAccount *)account;
46
+ (id)getSharingAccountsRequest:(OpenStackAccount *)account
47
                         marker:(NSString *)marker sharingAccountsBuffer:(NSMutableDictionary *)sharingAccountsBuffer;
40 48
+ (id)getSharingAccountsRequest:(OpenStackAccount *)account;
41
- (NSArray *)sharingAccounts;
49
- (NSArray *)jsonSharingAccounts;
42 50

  
43 51
+ (id)getStorageAccountInfoRequest:(OpenStackAccount *)account;
52
+ (id)getContainersRequest:(OpenStackAccount *)account
53
                    marker:(NSString *)marker containersBuffer:(NSMutableDictionary *)containersBuffer;
44 54
+ (id)getContainersRequest:(OpenStackAccount *)account;
45
- (NSMutableDictionary *)containers;
55
- (NSArray *)jsonContainers;
46 56
+ (id)writeAccountMetadataRequest:(OpenStackAccount *)account withAccountInfo:(NSDictionary *)accountInfo;
47 57

  
48 58
+ (id)getContainerInfoRequest:(OpenStackAccount *)account container:(Container *)container;
49 59
+ (id)createContainerRequest:(OpenStackAccount *)account container:(Container *)container;
50 60
+ (id)deleteContainerRequest:(OpenStackAccount *)account container:(Container *)container;
61
+ (id)getObjectsRequest:(OpenStackAccount *)account container:(Container *)container
62
                 marker:(NSString *)marker objectsBuffer:(NSMutableDictionary *)objectsBuffer;
51 63
+ (id)getObjectsRequest:(OpenStackAccount *)account container:(Container *)container;
52
- (NSMutableDictionary *)objects;
64
- (NSArray *)jsonObjects;
53 65
+ (id)writeContainerPolicyRequest:(OpenStackAccount *)account container:(Container *)container;
54 66

  
55 67
+ (id)getObjectInfoRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object;
b/Classes/OpenStackRequest.m
20 20

  
21 21
@implementation OpenStackRequest
22 22

  
23
@synthesize account, callback, errorAlerter;
23
@synthesize account, callback, errorAlerter, retryWithUpdatedURL, followUpSelectorString, notificationURL;
24 24

  
25 25
#pragma mark - Constructors
26 26
#pragma mark Generic
......
33 33
    request.timeOutSeconds = 60;
34 34
    request.numberOfTimesToRetryOnTimeout = 5;
35 35
    request.validatesSecureCertificate = !account.ignoreSSLErrors;
36
    request.retryWithUpdatedURL = (account.provider.manual ? NO : YES);
36 37
	return request;
37 38
}
38 39

  
......
56 57
    return [self request:account method:method url:url];
57 58
}
58 59

  
60
#pragma mark NSCopying
61

  
62
- (id)copyWithZone:(NSZone *)zone {
63
    OpenStackRequest *newRequest = [super copyWithZone:zone];
64
    newRequest.account = self.account;
65
    newRequest.callback = self.callback;
66
    newRequest.errorAlerter = self.errorAlerter;
67
    newRequest.retryWithUpdatedURL = self.retryWithUpdatedURL;
68
    newRequest.followUpSelectorString = self.followUpSelectorString;
69
    newRequest.notificationURL = self.notificationURL;
70
    return newRequest;
71
}
72

  
59 73
#pragma mark Service Catalog
60 74
+ (id)serviceCatalogRequest:(OpenStackAccount *)account {
61 75
    OpenStackRequest *request = [self requestWithoutToken:account method:@"POST" url:account.provider.tokensURL];
......
131 145
    request.timeOutSeconds = 60;
132 146
    request.numberOfTimesToRetryOnTimeout = 5;
133 147
    request.validatesSecureCertificate = !account.ignoreSSLErrors;
148
    request.retryWithUpdatedURL = (account.provider.manual ? NO : YES);
134 149
	return request;
135 150
}
136 151

  
152
+ (id)getSharingAccountsRequest:(OpenStackAccount *)account
153
                         marker:(NSString *)marker sharingAccountsBuffer:(NSMutableDictionary *)sharingAccountsBuffer {
154
    OpenStackRequest *request = [self request:account method:@"GET"
155
                                          url:[NSURL URLWithString:[NSString stringWithFormat:@"%@?format=json",
156
                                                                    account.provider.authEndpointURL]]];
157
    if (marker)
158
        request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&marker=%@", request.url.description, [NSString encodeToPercentEscape:marker]]];
159
    if (!sharingAccountsBuffer)
160
        sharingAccountsBuffer = [NSMutableDictionary dictionary];
161
    request.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
162
                        sharingAccountsBuffer, @"sharingAccountsBuffer",
163
                        nil];
164
    return request;
165
}
166

  
137 167
+ (id)getSharingAccountsRequest:(OpenStackAccount *)account {
138
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?format=json", account.provider.authEndpointURL]];
139
    return [self request:account method:@"GET" url:url];
168
    return [self getSharingAccountsRequest:account marker:nil sharingAccountsBuffer:nil];
140 169
}
141 170

  
142
- (NSArray *)sharingAccounts {
143
    SBJSON *parser = [[[SBJSON alloc] init] autorelease];
144
    NSArray *sharingAccounts = [parser objectWithString:[self responseString]];
145
    return sharingAccounts;
171
- (NSArray *)jsonSharingAccounts {
172
    return [[[[SBJSON alloc] init] autorelease] objectWithString:[self responseString]];
146 173
}
147 174

  
148 175
#pragma mark Account
......
151 178
    return [self filesRequest:account method:@"HEAD" path:@""];
152 179
}
153 180

  
181
+ (id)getContainersRequest:(OpenStackAccount *)account
182
                    marker:(NSString *)marker containersBuffer:(NSMutableDictionary *)containersBuffer {
183
    OpenStackRequest *request = [self filesRequest:account method:@"GET" path:@""];
184
    if (marker)
185
        request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&marker=%@", request.url.description, [NSString encodeToPercentEscape:marker]]];
186
    if (!containersBuffer)
187
        containersBuffer = [NSMutableDictionary dictionary];
188
    request.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
189
                        containersBuffer, @"containersBuffer",
190
                        nil];
191
    return request;
192
}
193

  
154 194
+ (id)getContainersRequest:(OpenStackAccount *)account {
155
    return [self filesRequest:account method:@"GET" path:@""];
195
    return [self getContainersRequest:account marker:nil containersBuffer:nil];
156 196
}
157 197

  
158
- (NSMutableDictionary *)containers {
159
    SBJSON *parser = [[[SBJSON alloc] init] autorelease];
160
    NSArray *jsonObjects = [parser objectWithString:[self responseString]];
161
    NSMutableDictionary *containers = [NSMutableDictionary dictionaryWithCapacity:[jsonObjects count]];
162
    for (NSDictionary *dict in jsonObjects) {
163
        Container *container = [Container fromJSON:dict];
164
        [containers setObject:container forKey:container.name];
165
    }
166
    return containers;
198
- (NSArray *)jsonContainers {
199
    return [[[[SBJSON alloc] init] autorelease] objectWithString:[self responseString]];
167 200
}
168 201

  
169 202
+ (id)writeAccountMetadataRequest:(OpenStackAccount *)account withAccountInfo:(NSDictionary *)accountInfo {
......
202 235
    return [self filesRequest:account method:@"DELETE" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]];
203 236
}
204 237

  
238
+ (id)getObjectsRequest:(OpenStackAccount *)account container:(Container *)container
239
                 marker:(NSString *)marker objectsBuffer:(NSMutableDictionary *)objectsBuffer {
240
    OpenStackRequest *request = [self filesRequest:account method:@"GET" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]];
241
    if (marker)
242
        request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&marker=%@", request.url.description, [NSString encodeToPercentEscape:marker]]];
243
    if (!objectsBuffer)
244
        objectsBuffer = [NSMutableDictionary dictionary];
245
    request.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
246
                        container, @"container",
247
                        objectsBuffer, @"objectsBuffer",
248
                        nil];
249
    return request;
250
}
251

  
205 252
+ (id)getObjectsRequest:(OpenStackAccount *)account container:(Container *)container {
206
    return [self filesRequest:account method:@"GET" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]];
253
    return [self getObjectsRequest:account container:container marker:nil objectsBuffer:nil];
207 254
}
208 255

  
209
- (NSMutableDictionary *)objects {
210
    SBJSON *parser = [[[SBJSON alloc] init] autorelease];
211
    NSArray *jsonObjects = [parser objectWithString:[self responseString]];
212
    NSMutableDictionary *objects = [NSMutableDictionary dictionaryWithCapacity:[jsonObjects count]];
213
    for (NSDictionary *dict in jsonObjects) {
214
        StorageObject *object = [StorageObject fromJSON:dict];
215
        [objects setObject:object forKey:object.name];
216
    }
217
    return objects;
256
- (NSArray *)jsonObjects {
257
    return [[[[SBJSON alloc] init] autorelease] objectWithString:[self responseString]];
218 258
}
219 259

  
220 260
+ (id)writeContainerPolicyRequest:(OpenStackAccount *)account container:(Container *)container {
......
378 418
}
379 419

  
380 420
- (void)notify {
381
    NSString *observeName = [NSString stringWithFormat:@"%@ %@ %@", [self isSuccess] ? @"SUCCESS" : @"FAILURE", self.requestMethod, [self.url description]];
382
    NSString *callbackName = [NSString stringWithFormat:@"%@ %@ %@ %@", [self isSuccess] ? @"SUCCESS" : @"FAILURE", self.requestMethod, [self.url description], self.callback.uuid];
421
    NSString *observeName = [NSString stringWithFormat:@"%@ %@ %@", [self isSuccess] ? @"SUCCESS" : @"FAILURE", self.requestMethod, (self.notificationURL ? self.notificationURL.description : self.url.description)];
422
    NSString *callbackName = [NSString stringWithFormat:@"%@ %@ %@ %@", [self isSuccess] ? @"SUCCESS" : @"FAILURE", self.requestMethod, (self.notificationURL ? self.notificationURL.description : self.url.description), self.callback.uuid];
383 423

  
384 424
    NSDictionary *callbackUserInfo = [NSDictionary dictionaryWithObject:self forKey:@"response"];
385 425

  
......
416 456
- (void)dealloc {
417 457
    [account release];
418 458
    [errorAlerter release];
459
    [followUpSelectorString release];
460
    [notificationURL release];
419 461
    [self releaseBackupBlocksOnMainThread];
420 462
    [super dealloc];
421 463
}
b/Classes/SharingAccountsViewController.m
92 92
    [[self.account.manager getSharingAccounts]
93 93
     success:^(OpenStackRequest *request) {
94 94
         [sharingAccounts removeAllObjects];
95
         for (NSDictionary *dict in [request sharingAccounts]) {
96
             [sharingAccounts addObject:[dict objectForKey:@"name"]];
97
         }
95
         [sharingAccounts addObjectsFromArray:[[request.userInfo objectForKey:@"sharingAccountsBuffer"] allKeys]];
98 96
         [[self.account.manager userCatalogForDisplaynames:nil
99 97
                                                     UUIDs:sharingAccounts]
100 98
          success:^(OpenStackRequest *request) {
b/OpenStack-Info.plist
41 41
	<key>CFBundlePackageType</key>
42 42
	<string>APPL</string>
43 43
	<key>CFBundleShortVersionString</key>
44
	<string>1.7.1</string>
44
	<string>1.7.2</string>
45 45
	<key>CFBundleSignature</key>
46 46
	<string>????</string>
47 47
	<key>CFBundleURLTypes</key>
......
56 56
		</dict>
57 57
	</array>
58 58
	<key>CFBundleVersion</key>
59
	<string>20130625.0</string>
59
	<string>20130628.0</string>
60 60
	<key>LSRequiresIPhoneOS</key>
61 61
	<true/>
62 62
	<key>NSMainNibFile</key>
b/OpenStack.xcodeproj/project.pbxproj
121 121
		2787C13E12F0D26A009EAD7C /* text-file.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2787C13D12F0D26A009EAD7C /* text-file.txt */; };
122 122
		2788941B12C28C66006448E2 /* ContainerDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2788941812C28C66006448E2 /* ContainerDetailViewController.m */; };
123 123
		2788941C12C28C66006448E2 /* ContainerDetailViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2788941912C28C66006448E2 /* ContainerDetailViewController.xib */; };
124
		278896B312C53956006448E2 /* GetObjectsRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 278896B112C53956006448E2 /* GetObjectsRequest.m */; };
125 124
		278906E012BEDAB5007112B6 /* StorageObjectViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 278906DD12BEDAB5007112B6 /* StorageObjectViewController.xib */; };
126 125
		278907A212BEF72C007112B6 /* StorageObjectViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 278907A112BEF72C007112B6 /* StorageObjectViewController.m */; };
127 126
		279754961256BA2100D7A533 /* Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = 279754941256BA2100D7A533 /* Base64.m */; };
......
346 345
		2788941712C28C66006448E2 /* ContainerDetailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContainerDetailViewController.h; sourceTree = "<group>"; };
347 346
		2788941812C28C66006448E2 /* ContainerDetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContainerDetailViewController.m; sourceTree = "<group>"; };
348 347
		2788941912C28C66006448E2 /* ContainerDetailViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ContainerDetailViewController.xib; sourceTree = "<group>"; };
349
		278896B012C53956006448E2 /* GetObjectsRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetObjectsRequest.h; sourceTree = "<group>"; };
350
		278896B112C53956006448E2 /* GetObjectsRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetObjectsRequest.m; sourceTree = "<group>"; };
351 348
		278906DB12BEDAB5007112B6 /* StorageObjectViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageObjectViewController.h; sourceTree = "<group>"; };
352 349
		278906DD12BEDAB5007112B6 /* StorageObjectViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StorageObjectViewController.xib; sourceTree = "<group>"; };
353 350
		278907A112BEF72C007112B6 /* StorageObjectViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StorageObjectViewController.m; sourceTree = "<group>"; };
......
577 574
			children = (
578 575
				277BF6A3133A712D00C36FFA /* APICallback.h */,
579 576
				277BF6A4133A712D00C36FFA /* APICallback.m */,
580
				2788958612C476A3006448E2 /* Object Storage */,
581 577
				27F73E0D125F73EE002C6CB0 /* OpenStackRequest.h */,
582 578
				27F73E0E125F73EE002C6CB0 /* OpenStackRequest.m */,
583 579
			);
......
839 835
			name = "Create File";
840 836
			sourceTree = "<group>";
841 837
		};
842
		2788958612C476A3006448E2 /* Object Storage */ = {
843
			isa = PBXGroup;
844
			children = (
845
				278896B012C53956006448E2 /* GetObjectsRequest.h */,
846
				278896B112C53956006448E2 /* GetObjectsRequest.m */,
847
			);
848
			name = "Object Storage";
849
			sourceTree = "<group>";
850
		};
851 838
		2788982B12E0F0BF000216D7 /* UIButton */ = {
852 839
			isa = PBXGroup;
853 840
			children = (
......
1286 1273
				277B89B912B97D6D006483B0 /* FolderViewController.m in Sources */,
1287 1274
				278907A212BEF72C007112B6 /* StorageObjectViewController.m in Sources */,
1288 1275
				2788941B12C28C66006448E2 /* ContainerDetailViewController.m in Sources */,
1289
				278896B312C53956006448E2 /* GetObjectsRequest.m in Sources */,
1290 1276
				2734687112D3AB9500341268 /* AddObjectViewController.m in Sources */,
1291 1277
				273468C512D3B0E800341268 /* AddFolderViewController.m in Sources */,
1292 1278
				273468CF12D3B0FC00341268 /* AddFileViewController.m in Sources */,

Also available in: Unified diff