Fix compile errors
[pithos-ios] / Classes / AccountManager.m
1 //
2 //  AccountManager.m
3 //  OpenStack
4 //
5 //  Created by Mike Mayo on 10/21/10.
6 //  The OpenStack project is provided under the Apache 2.0 license.
7 //
8
9 #import "AccountManager.h"
10 #import "OpenStackAccount.h"
11 #import "OpenStackRequest.h"
12 #import "Server.h"
13 #import "Provider.h"
14 #import "Image.h"
15 #import "Container.h"
16 #import "Folder.h"
17 #import "StorageObject.h"
18 #import "GetServersRequest.h"
19 #import "GetContainersRequest.h"
20 #import "GetObjectsRequest.h"
21 #import "GetImagesRequest.h"
22 #import "ASINetworkQueue.h"
23 #import "UpdateCDNContainerRequest.h"
24 #import "GetFlavorsRequest.h"
25 #import "LoadBalancer.h"
26 #import "LoadBalancerRequest.h"
27 #import "APICallback.h"
28 #import "Analytics.h"
29 #import "JSON.h"
30 #import "OpenStackAppDelegate.h"
31
32
33
34
35 @implementation AccountManager
36
37 @synthesize account, queue, objectDownloadRequests;
38
39 #pragma mark - Callbacks
40
41 - (APICallback *)callbackWithRequest:(id)request success:(APIResponseBlock)success failure:(APIResponseBlock)failure {
42     APICallback *callback = [[[APICallback alloc] initWithAccount:self.account request:request] autorelease];
43     ((OpenStackRequest *)request).delegate = self;
44     ((OpenStackRequest *)request).callback = callback; 
45
46     [request setCompletionBlock:^{
47         if ([request isSuccess]) {
48             success(request);
49             [request notify];
50         } else {
51             failure(request);
52             [request notify];
53         }
54     }];
55     [request setFailedBlock:^{
56         failure(request);
57         [request notify];
58     }];
59     [request startAsynchronous];    
60     return callback;
61 }
62
63 - (APICallback *)callbackWithRequest:(id)request success:(APIResponseBlock)success {
64     return [self callbackWithRequest:request success:success failure:^(OpenStackRequest *request){}];
65 }
66
67 - (APICallback *)callbackWithRequest:(id)request {
68     return [self callbackWithRequest:request success:^(OpenStackRequest *request){} failure:^(OpenStackRequest *request){}];
69 }
70
71 #pragma mark - Notification
72
73 - (NSString *)notificationName:(NSString *)key identifier:(NSString *)identifier {
74     return [NSString stringWithFormat:@"%@-%@-%@", key, self.account.uuid, identifier];
75 }
76
77 - (void)requestFinished:(OpenStackRequest *)request {
78     NSString *notificationName = [request.userInfo objectForKey:@"notificationName"];
79     id notificationObject = [request.userInfo objectForKey:@"notificationObject"];
80     
81     if ([request isSuccess]) {
82         NSNotification *notification = [NSNotification notificationWithName:[NSString stringWithFormat:@"%@Succeeded", notificationName] object:notificationObject];
83         [[NSNotificationCenter defaultCenter] postNotification:notification];
84     } else {
85         NSNotification *notification = [NSNotification notificationWithName:[NSString stringWithFormat:@"%@Failed", notificationName] object:notificationObject userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
86         [[NSNotificationCenter defaultCenter] postNotification:notification];
87     }
88 }
89
90 - (void)requestFailed:(OpenStackRequest *)request {
91     NSString *notificationName = [request.userInfo objectForKey:@"notificationName"];
92     id notificationObject = [request.userInfo objectForKey:@"notificationObject"];
93     NSNotification *notification = [NSNotification notificationWithName:[NSString stringWithFormat:@"%@Failed", notificationName] object:notificationObject userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
94     [[NSNotificationCenter defaultCenter] postNotification:notification];
95 }
96
97 - (void)sendRequest:(OpenStackRequest *)request name:(NSString *)name object:(id)notificationObject {
98     request.delegate = self;
99     request.userInfo = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:name, notificationObject, nil] forKeys:[NSArray arrayWithObjects:@"notificationName", @"notificationObject", nil]];
100     [request startAsynchronous];
101 }
102
103 - (void)notify:(NSString *)name request:(OpenStackRequest *)request {
104     NSNotification *notification = [NSNotification notificationWithName:name object:nil userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
105     [[NSNotificationCenter defaultCenter] postNotification:notification];
106 }
107
108 - (void)notify:(NSString *)name request:(OpenStackRequest *)request object:(id)object {
109     NSNotification *notification = [NSNotification notificationWithName:name object:object userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
110     [[NSNotificationCenter defaultCenter] postNotification:notification];
111 }
112
113 #pragma mark - API Calls
114
115 #pragma mark Get Limits
116
117 - (void)getLimits {
118     __block OpenStackRequest *request = [OpenStackRequest getLimitsRequest:self.account];
119     request.delegate = self;
120     [request setCompletionBlock:^{
121         if ([request isSuccess] && [request limits]) {
122             self.account.rateLimits = [request rateLimits];
123             [self.account persist];
124             [self notify:@"getLimitsSucceeded" request:request object:self.account];
125         } else {
126             [self notify:@"getLimitsFailed" request:request object:self.account];
127         }
128     }];
129     [request setFailedBlock:^{
130         [self notify:@"getLimitsFailed" request:request object:self.account];
131     }];    
132     [request startAsynchronous];
133 }
134
135 #pragma mark Reboot Server
136
137 - (void)softRebootServer:(Server *)server {
138     TrackEvent(CATEGORY_SERVER, EVENT_REBOOTED);
139     
140     __block OpenStackRequest *request = [OpenStackRequest softRebootServerRequest:self.account server:server];
141     request.delegate = self;
142     request.userInfo = [NSDictionary dictionaryWithObject:server forKey:@"server"];
143     [request setCompletionBlock:^{
144         [self notify:([request isSuccess] ? @"rebootSucceeded" : @"rebootFailed") request:request object:[request.userInfo objectForKey:@"server"]];
145     }];
146     [request setFailedBlock:^{
147         [self notify:@"rebootFailed" request:request object:[request.userInfo objectForKey:@"server"]];
148     }];
149     [request startAsynchronous];    
150 }
151
152 - (void)hardRebootServer:(Server *)server {
153     TrackEvent(CATEGORY_SERVER, EVENT_REBOOTED);
154     
155     __block OpenStackRequest *request = [OpenStackRequest hardRebootServerRequest:self.account server:server];
156     request.delegate = self;
157     request.userInfo = [NSDictionary dictionaryWithObject:server forKey:@"server"];
158     [request setCompletionBlock:^{
159         [self notify:([request isSuccess] ? @"rebootSucceeded" : @"rebootFailed") request:request object:[request.userInfo objectForKey:@"server"]];
160     }];
161     [request setFailedBlock:^{
162         [self notify:@"rebootFailed" request:request object:[request.userInfo objectForKey:@"server"]];
163     }];
164     [request startAsynchronous];
165 }
166
167 #pragma mark Change Admin Password
168
169 - (void)changeAdminPassword:(Server *)server password:(NSString *)password {
170     TrackEvent(CATEGORY_SERVER, EVENT_PASSWORD_CHANGED);
171     
172     __block OpenStackRequest *request = [OpenStackRequest changeServerAdminPasswordRequest:self.account server:server password:password];
173     request.delegate = self;
174     request.userInfo = [NSDictionary dictionaryWithObject:server forKey:@"server"];
175     [request setCompletionBlock:^{
176         [self notify:([request isSuccess] ? @"changeAdminPasswordSucceeded" : @"changeAdminPasswordFailed") request:request object:[request.userInfo objectForKey:@"server"]];
177     }];
178     [request setFailedBlock:^{
179         [self notify:@"changeAdminPasswordFailed" request:request object:[request.userInfo objectForKey:@"server"]];
180     }];
181     [request startAsynchronous];
182 }
183
184 #pragma mark Rename Server
185
186 - (APICallback *)renameServer:(Server *)server name:(NSString *)name {
187     TrackEvent(CATEGORY_SERVER, EVENT_RENAMED);
188     
189     __block OpenStackRequest *request = [OpenStackRequest renameServerRequest:self.account server:server name:name];
190     return [self callbackWithRequest:request];
191 }
192
193 #pragma mark Delete Server
194
195 - (void)deleteServer:(Server *)server {
196     TrackEvent(CATEGORY_SERVER, EVENT_DELETED);
197     
198     __block OpenStackRequest *request = [OpenStackRequest deleteServerRequest:self.account server:server];
199     request.delegate = self;
200     request.userInfo = [NSDictionary dictionaryWithObject:server forKey:@"server"];
201     [request setCompletionBlock:^{
202         [self notify:([request isSuccess] ? @"deleteServerSucceeded" : @"deleteServerFailed") request:request object:[request.userInfo objectForKey:@"server"]];        
203         [self notify:([request isSuccess] ? @"deleteServerSucceeded" : @"deleteServerFailed") request:request object:self.account];
204     }];
205     [request setFailedBlock:^{
206         [self notify:@"deleteServerFailed" request:request object:[request.userInfo objectForKey:@"server"]];        
207     }];
208     if (![self queue]) {
209         [self setQueue:(ASINetworkQueue *)[[[NSOperationQueue alloc] init] autorelease]];
210     }
211     [queue addOperation:request];    
212 }
213
214 #pragma mark Create Server
215
216 - (void)createServer:(Server *)server {
217     TrackEvent(CATEGORY_SERVER, EVENT_CREATED);
218     
219     __block OpenStackRequest *request = [OpenStackRequest createServerRequest:self.account server:server];
220     request.delegate = self;
221     request.userInfo = [NSDictionary dictionaryWithObject:server forKey:@"server"];
222     
223     // TODO: make these success block and failure block with "response" arg
224     [request setCompletionBlock:^{
225         NSLog(@"create server response: %i - %@", request.responseStatusCode, request.responseStatusMessage);
226         NSLog(@"body: %@", [request responseString]);            
227         [self notify:([request isSuccess] ? @"createServerSucceeded" : @"createServerFailed") request:request object:[request.userInfo objectForKey:@"server"]];        
228         [self notify:([request isSuccess] ? @"createServerSucceeded" : @"createServerFailed") request:request object:self.account];
229     }];    
230     [request setFailedBlock:^{
231         NSLog(@"create server response: %i - %@", request.responseStatusCode, request.responseStatusMessage);
232         NSLog(@"body: %@", [request responseString]);            
233         [self notify:@"createServerFailed" request:request object:[request.userInfo objectForKey:@"server"]];        
234     }];
235     if (![self queue]) {
236         [self setQueue:(ASINetworkQueue *)[[[NSOperationQueue alloc] init] autorelease]];
237     }
238     [queue addOperation:request];
239 }
240
241 #pragma mark Resize Server
242
243 - (void)resizeServer:(Server *)server flavor:(Flavor *)flavor {
244     TrackEvent(CATEGORY_SERVER, EVENT_RESIZED);
245     
246     __block OpenStackRequest *request = [OpenStackRequest resizeServerRequest:self.account server:server flavor:flavor];
247     request.delegate = self;
248     request.userInfo = [NSDictionary dictionaryWithObject:server forKey:@"server"];
249     [request setCompletionBlock:^{
250         NSString *name = [request isSuccess] ? @"resizeServerSucceeded" : @"resizeServerFailed";
251         NSNotification *notification = [NSNotification notificationWithName:[self notificationName:name identifier:server.identifier] object:nil userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
252         [[NSNotificationCenter defaultCenter] postNotification:notification];
253     }];
254     [request setFailedBlock:^{
255         NSNotification *notification = [NSNotification notificationWithName:[self notificationName:@"resizeServerFailed" identifier:server.identifier] object:nil userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
256         [[NSNotificationCenter defaultCenter] postNotification:notification];
257     }];
258     [request startAsynchronous];
259 }
260
261 - (void)confirmResizeServer:(Server *)server {
262     __block OpenStackRequest *request = [OpenStackRequest confirmResizeServerRequest:self.account server:server];
263     request.delegate = self;
264     request.userInfo = [NSDictionary dictionaryWithObject:server forKey:@"server"];
265     [request setCompletionBlock:^{
266         NSString *name = [request isSuccess] ? @"confirmResizeServerSucceeded" : @"confirmResizeServerFailed";
267         NSNotification *notification = [NSNotification notificationWithName:[self notificationName:name identifier:server.identifier] object:nil userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
268         [[NSNotificationCenter defaultCenter] postNotification:notification];
269     }];
270     [request setFailedBlock:^{
271         NSNotification *notification = [NSNotification notificationWithName:[self notificationName:@"confirmResizeServerFailed" identifier:server.identifier] object:nil userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
272         [[NSNotificationCenter defaultCenter] postNotification:notification];
273         
274     }];
275     [request startAsynchronous];
276 }
277
278 - (void)revertResizeServer:(Server *)server {
279     __block OpenStackRequest *request = [OpenStackRequest revertResizeServerRequest:self.account server:server];
280     request.delegate = self;
281     request.userInfo = [NSDictionary dictionaryWithObject:server forKey:@"server"];
282     [request setCompletionBlock:^{
283         NSString *name = [request isSuccess] ? @"revertResizeServerSucceeded" : @"revertResizeServerFailed";
284         NSNotification *notification = [NSNotification notificationWithName:[self notificationName:name identifier:server.identifier] object:nil userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
285         [[NSNotificationCenter defaultCenter] postNotification:notification];
286     }];
287     [request setFailedBlock:^{
288         NSNotification *notification = [NSNotification notificationWithName:[self notificationName:@"revertResizeServerFailed" identifier:server.identifier] object:nil userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
289         [[NSNotificationCenter defaultCenter] postNotification:notification];
290     }];
291     [request startAsynchronous];
292 }
293
294 - (void)rebuildServer:(Server *)server image:(Image *)image {
295     TrackEvent(CATEGORY_SERVER, EVENT_REBUILT);
296     
297     __block OpenStackRequest *request = [OpenStackRequest rebuildServerRequest:self.account server:server image:image];
298     request.delegate = self;
299     request.userInfo = [NSDictionary dictionaryWithObject:server forKey:@"server"];
300     [request setCompletionBlock:^{
301         NSString *name = [request isSuccess] ? @"rebuildServerSucceeded" : @"rebuildServerFailed";
302         NSNotification *notification = [NSNotification notificationWithName:[self notificationName:name identifier:server.identifier] object:nil userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
303         [[NSNotificationCenter defaultCenter] postNotification:notification];
304     }];
305     [request setFailedBlock:^{
306         NSNotification *notification = [NSNotification notificationWithName:[self notificationName:@"rebuildServerFailed" identifier:server.identifier] object:nil userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
307         [[NSNotificationCenter defaultCenter] postNotification:notification];
308     }];
309     [request startAsynchronous];
310 }
311
312 - (void)getBackupSchedule:(Server *)server {
313     __block OpenStackRequest *request = [OpenStackRequest getBackupScheduleRequest:self.account server:server];
314     request.delegate = self;
315     request.userInfo = [NSDictionary dictionaryWithObject:server forKey:@"server"];
316     [request setCompletionBlock:^{
317         server.backupSchedule = [request backupSchedule];
318         [self notify:([request isSuccess] ? @"getBackupScheduleSucceeded" : @"getBackupScheduleFailed") request:request object:[request.userInfo objectForKey:@"server"]];
319     }];
320     [request setFailedBlock:^{
321         [self notify:@"getBackupScheduleFailed" request:request object:[request.userInfo objectForKey:@"server"]];        
322     }];
323     [request startAsynchronous];
324 }
325
326 - (void)updateBackupSchedule:(Server *)server {
327     TrackEvent(CATEGORY_SERVER, EVENT_BACKUP_SCHEDULE_CHANGED);
328     
329     __block OpenStackRequest *request = [OpenStackRequest updateBackupScheduleRequest:self.account server:server];
330     request.delegate = self;
331     request.userInfo = [NSDictionary dictionaryWithObject:server forKey:@"server"];
332     [request setCompletionBlock:^{
333         [self notify:([request isSuccess] ? @"updateBackupScheduleSucceeded" : @"updateBackupScheduleFailed") request:request object:[request.userInfo objectForKey:@"server"]];
334         [self notify:([request isSuccess] ? @"updateBackupScheduleSucceeded" : @"updateBackupScheduleFailed") request:request object:self.account];
335     }];
336     [request setFailedBlock:^{
337         [self notify:@"updateBackupScheduleFailed" request:request object:[request.userInfo objectForKey:@"server"]];        
338         [self notify:@"updateBackupScheduleFailed" request:request object:self.account];        
339     }];
340     [request startAsynchronous];
341 }
342
343 #pragma mark Get Image
344
345 - (void)getImage:(Server *)server {
346     __block OpenStackRequest *request = [OpenStackRequest getImageRequest:self.account imageId:server.imageId];
347     request.delegate = self;
348     request.userInfo = [NSDictionary dictionaryWithObject:server.imageId forKey:@"imageId"];
349     [request setCompletionBlock:^{
350         if ([request isSuccess]) {
351             Image *image = [request image];
352             if ([image isKindOfClass:[Image class]]) {
353                 image.canBeLaunched = NO;
354                 [self.account.images setObject:image forKey:image.identifier];        
355                 [self.account persist];        
356             }
357             [self notify:@"getImageSucceeded" request:request];
358         } else {
359             [self notify:@"getImageFailed" request:request object:[request.userInfo objectForKey:@"imageId"]];
360         }
361     }];
362     [request setFailedBlock:^{
363         [self notify:@"getImageFailed" request:request object:[request.userInfo objectForKey:@"imageId"]];
364     }];
365     [request startAsynchronous];
366 }
367
368 #pragma mark Get Servers
369
370 - (void)getServers {
371     if (![self queue]) {
372         [self setQueue:[[[ASINetworkQueue alloc] init] autorelease]];
373     }
374     GetServersRequest *request = [GetServersRequest request:self.account];
375     [queue addOperation:request];
376 }
377
378 - (APICallback *)getServersWithCallback {
379     __block OpenStackRequest *request = [OpenStackRequest serversRequest:self.account method:@"GET" path:@"/servers/detail"];
380     return [self callbackWithRequest:request];
381 }
382
383
384 #pragma mark Get Flavors
385
386 - (void)getFlavors {
387     if (![self queue]) {
388         [self setQueue:[[[ASINetworkQueue alloc] init] autorelease]];
389     }
390     GetFlavorsRequest *request = [GetFlavorsRequest request:self.account];
391     [queue addOperation:request];
392 }
393
394 #pragma mark Get Images
395
396 - (void)getImages {
397     if (![self queue]) {
398         [self setQueue:[[[ASINetworkQueue alloc] init] autorelease]];
399     }
400     GetImagesRequest *request = [GetImagesRequest request:self.account];
401     [queue addOperation:request];
402 }
403
404 #pragma mark -
405 #pragma mark Object Storage
406
407
408 - (APICallback *)getStorageAccountInfo {
409     __block OpenStackRequest *request = [OpenStackRequest getStorageAccountInfoRequest:self.account];
410     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {        
411         self.account.containerCount = [[[request responseHeaders] objectForKey:@"X-Account-Container-Count"] intValue];
412         NSString *numStr = [[request responseHeaders] objectForKey:@"X-Account-Bytes-Used"];
413         self.account.totalBytesUsed = strtoull([numStr UTF8String], NULL, 0);
414         [self.account persist];
415         self.account.containerCount = [self.account.containers count];        
416     }];
417 }
418
419 - (APICallback *)getSharingAccounts {
420     __block OpenStackRequest *request = [OpenStackRequest getSharingAccountsRequest:self.account];
421     return [self callbackWithRequest:request];        
422 }
423
424 - (APICallback *)getContainers {
425     __block OpenStackRequest *request = [OpenStackRequest filesRequest:self.account method:@"GET" path:@""];
426     return [self callbackWithRequest:request];    
427 }
428
429 - (APICallback *)createContainer:(Container *)container {
430     TrackEvent(CATEGORY_CONTAINERS, EVENT_CREATED);
431
432     __block OpenStackRequest *request = [OpenStackRequest createContainerRequest:self.account container:container];
433     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
434         
435         [self.account.containers setObject:container forKey:container.name];        
436         [self.account persist];
437         self.account.containerCount = [self.account.containers count];        
438     }];
439 }
440
441 - (APICallback *)deleteContainer:(Container *)container {
442     TrackEvent(CATEGORY_CONTAINERS, EVENT_DELETED);
443     __block OpenStackRequest *request = [OpenStackRequest deleteContainerRequest:self.account container:container];
444     return [self callbackWithRequest:request];
445     
446 }
447
448 - (void)getObjects:(Container *)container {
449     [self getObjects:container afterMarker:nil objectsBuffer:nil];
450 }
451
452 - (void)getObjects:(Container *)container
453        afterMarker:(NSString *)marker
454      objectsBuffer:(NSMutableDictionary *)objectsBuffer {
455     if (![self queue]) {
456         [self setQueue:(ASINetworkQueue *)[[[NSOperationQueue alloc] init] autorelease]];
457     }    
458     GetObjectsRequest *request = [GetObjectsRequest request:self.account container:container marker:marker objectsBuffer:objectsBuffer];
459     [queue addOperation:request];
460 }
461
462 - (void)updateCDNContainer:(Container *)container {
463     TrackEvent(CATEGORY_CONTAINERS, EVENT_UPDATED);
464     
465     if (![self queue]) {
466         [self setQueue:(ASINetworkQueue *)[[[NSOperationQueue alloc] init] autorelease]];
467     }
468     UpdateCDNContainerRequest *request = [UpdateCDNContainerRequest request:self.account container:container];
469     [queue addOperation:request];
470 }
471
472 - (void)getObjectsSucceeded:(OpenStackRequest *)request {
473     if ([request isSuccess]) {
474         Container *container = [request.userInfo objectForKey:@"container"];
475         NSMutableDictionary *objects = [request objects];
476         container.rootFolder = [Folder folder];
477         container.rootFolder.objects = objects;
478         [self.account persist];
479         
480         NSNotification *notification = [NSNotification notificationWithName:@"getObjectsSucceeded" object:self.account userInfo:[NSDictionary dictionaryWithObject:container forKey:@"container"]];
481         [[NSNotificationCenter defaultCenter] postNotification:notification];
482     } else {
483         NSNotification *notification = [NSNotification notificationWithName:@"getObjectsFailed" object:self.account userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
484         [[NSNotificationCenter defaultCenter] postNotification:notification];
485     }
486 }
487
488 - (void)getObjectsFailed:(OpenStackRequest *)request {
489     NSNotification *notification = [NSNotification notificationWithName:@"getObjectsFailed" object:self.account userInfo:[NSDictionary dictionaryWithObject:request forKey:@"request"]];
490     [[NSNotificationCenter defaultCenter] postNotification:notification];
491 }
492
493 - (APICallback *)getContainerInfo:(Container *)container {
494     __block OpenStackRequest *request = [OpenStackRequest getContainerInfoRequest:self.account container:container];
495     return [self callbackWithRequest:request];
496 }
497
498 - (APICallback *)getObjectInfo:(Container *)container object:(StorageObject *)object {    
499     __block OpenStackRequest *request = [OpenStackRequest getObjectInfoRequest:self.account container:container object:object];
500     return [self callbackWithRequest:request];
501 }
502
503 - (APICallback *)getObjectInfo:(Container *)container object:(StorageObject *)object version:(NSString *)version {
504     if (!version)
505         return [self getObjectInfo:container object:object];
506     
507     __block OpenStackRequest *request = [OpenStackRequest getObjectInfoRequest:self.account container:container object:object version:version];
508     return [self callbackWithRequest:request];
509 }
510
511 - (APICallback *)getObjectVersionsList:(Container *)container object:(StorageObject *)object {
512     __block OpenStackRequest *request = [OpenStackRequest getObjectVersionsRequest:account container:container object:object];
513     return [self callbackWithRequest:request];
514 }
515
516 - (APICallback *)getObject:(Container *)container object:(StorageObject *)object downloadProgressDelegate:(id)downloadProgressDelegate {
517     return [self getObject:container object:object downloadProgressDelegate:downloadProgressDelegate requestUserInfo:nil];
518 }
519
520 - (APICallback *)getObject:(Container *)container
521                     object:(StorageObject *)object
522   downloadProgressDelegate:(id)downloadProgressDelegate
523            requestUserInfo:(NSDictionary *)requestUserInfo {
524     
525     return [self getObject:container object:object downloadProgressDelegate:downloadProgressDelegate requestUserInfo:requestUserInfo version:nil];
526 }
527
528
529 - (APICallback *)getObject:(Container *)container
530                     object:(StorageObject *)object
531   downloadProgressDelegate:(id)downloadProgressDelegate 
532            requestUserInfo:(NSDictionary *)requestUserInfo
533                    version:(NSString *)version{
534     __block OpenStackRequest *request = [OpenStackRequest getObjectRequest:self.account container:container object:object version:version];
535     request.delegate = self;
536     request.downloadProgressDelegate = downloadProgressDelegate;
537     request.showAccurateProgress = YES;  
538     if (requestUserInfo) {
539         request.userInfo = requestUserInfo;
540     }
541     if (!objectDownloadRequests)
542         self.objectDownloadRequests = [NSMutableDictionary dictionary];
543     [objectDownloadRequests setObject:request forKey:object.fullPath];
544     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
545         OpenStackAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
546         NSString *filePath = [appDelegate.cacheDirectoryPath stringByAppendingFormat:@"/%@.%@",object.hash, object.name.pathExtension];
547         [[request responseData] writeToFile:filePath atomically:YES];
548         @synchronized(appDelegate.cachedObjectsDictionary) {
549             if (!object.hash)
550                 object.hash = [request.responseHeaders objectForKey:@"X-Object-Hash"];
551             [appDelegate.cachedObjectsDictionary setObject:filePath forKey:object.hash];
552             [appDelegate saveCacheDictionary];
553         }
554         [objectDownloadRequests removeObjectForKey:object.fullPath];
555     }
556     failure:^(OpenStackRequest *request) { 
557         [objectDownloadRequests removeObjectForKey:object.fullPath];
558     }];
559 }
560
561 - (APICallback *)writeObject:(Container *)container object:(StorageObject *)object downloadProgressDelegate:(id)downloadProgressDelegate {
562     TrackEvent(CATEGORY_FILES, EVENT_CREATED);
563     
564     __block OpenStackRequest *request = [OpenStackRequest writeObjectRequest:self.account container:container object:object];
565     request.delegate = self;
566     request.uploadProgressDelegate = downloadProgressDelegate;
567     request.showAccurateProgress = YES;
568     
569     return [self callbackWithRequest:request];
570 }
571
572 - (APICallback *)deleteObject:(Container *)container object:(StorageObject *)object {
573     TrackEvent(CATEGORY_FILES, EVENT_DELETED);
574     
575     __block OpenStackRequest *request = [OpenStackRequest deleteObjectRequest:self.account container:container object:object];
576     return [self callbackWithRequest:request];
577 }
578
579 - (APICallback *)writeObjectMetadata:(Container *)container object:(StorageObject *)object {
580     __block OpenStackRequest *request = [OpenStackRequest writeObjectMetadataRequest:self.account container:container object:object];
581     return [self callbackWithRequest:request];
582 }
583
584 - (APICallback *)writeAccountMetadata:(NSDictionary *)accountInfo {
585     __block OpenStackRequest *request = [OpenStackRequest writeAccountMetadataRequest:self.account withAccountInfo:accountInfo];
586     return [self callbackWithRequest:request];
587 }
588
589 - (APICallback *)writeContainerPolicy:(Container *)container {
590     __block OpenStackRequest *request = [OpenStackRequest writeContainerPolicyRequest:self.account container:container];
591     return [self callbackWithRequest:request];
592 }
593
594 #pragma mark -
595 #pragma mark Load Balancing
596
597 - (APICallback *)getLoadBalancers:(NSString *)endpoint {
598     __block LoadBalancerRequest *request = [LoadBalancerRequest getLoadBalancersRequest:self.account endpoint:endpoint];
599     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
600         if (!self.account.loadBalancers) {
601             self.account.loadBalancers = [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease];
602         }
603         
604         NSLog(@"%@", self.account.loadBalancers);
605         NSLog(@"%@", [(LoadBalancerRequest *)request loadBalancers:self.account]);
606         NSLog(@"%@", endpoint);
607         NSMutableDictionary *lbs = [(LoadBalancerRequest *)request loadBalancers:self.account];
608         
609         for (NSString *identifier in lbs) {
610             LoadBalancer *lb = [lbs objectForKey:identifier];
611             lb.region = [self.account loadBalancerRegionForEndpoint:endpoint];
612             NSLog(@"lb.region = %@", lb.region);
613         }
614         
615         [self.account.loadBalancers setObject:lbs forKey:endpoint];
616         [self.account persist];
617     }];
618 }
619
620 - (APICallback *)getLoadBalancerDetails:(LoadBalancer *)loadBalancer endpoint:(NSString *)endpoint {
621     __block LoadBalancerRequest *request = [LoadBalancerRequest getLoadBalancerDetailsRequest:self.account loadBalancer:loadBalancer endpoint:endpoint];
622     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
623
624         LoadBalancer *newLB = [(LoadBalancerRequest *)request loadBalancer:self.account];
625         loadBalancer.status = newLB.status;
626         loadBalancer.nodes = newLB.nodes;
627         loadBalancer.connectionLoggingEnabled = newLB.connectionLoggingEnabled;
628         
629 //        if (!self.account.loadBalancers) {
630 //            self.account.loadBalancers = [[NSMutableDictionary alloc] initWithCapacity:2];
631 //        }
632 //        
633 //        NSLog(@"%@", self.account.loadBalancers);
634 //        NSLog(@"%@", [(LoadBalancerRequest *)request loadBalancers]);
635 //        NSLog(@"%@", endpoint);
636 //        NSMutableDictionary *lbs = [(LoadBalancerRequest *)request loadBalancers];
637 //        
638 //        for (NSString *identifier in lbs) {
639 //            LoadBalancer *lb = [lbs objectForKey:identifier];
640 //            lb.region = [self.account loadBalancerRegionForEndpoint:endpoint];
641 //            NSLog(@"lb.region = %@", lb.region);
642 //        }
643 //        
644 //        [self.account.loadBalancers setObject:lbs forKey:endpoint];
645         [self.account persist];
646     }];
647 }
648
649 - (APICallback *)getLoadBalancerProtocols:(NSString *)endpoint {
650     __block LoadBalancerRequest *request = [LoadBalancerRequest getLoadBalancerProtocols:self.account endpoint:endpoint];
651     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
652         self.account.lbProtocols = [(LoadBalancerRequest *)request protocols];
653     }];
654 }
655
656 - (APICallback *)createLoadBalancer:(LoadBalancer *)loadBalancer {
657     TrackEvent(CATEGORY_LOAD_BALANCER, EVENT_CREATED);
658     
659     NSString *endpoint = @"";
660     
661     for (NSString *url in [self.account loadBalancerURLs]) {
662         if ([url hasPrefix:[NSString stringWithFormat:@"https://%@", [loadBalancer.region lowercaseString]]]) {
663             endpoint = url;
664             break;
665         }
666     }
667     
668     __block LoadBalancerRequest *request = [LoadBalancerRequest createLoadBalancerRequest:self.account loadBalancer:loadBalancer endpoint:endpoint];
669     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
670     }];
671 }
672
673 - (APICallback *)updateLoadBalancer:(LoadBalancer *)loadBalancer {
674     TrackEvent(CATEGORY_LOAD_BALANCER, EVENT_UPDATED);
675     NSString *endpoint = [self.account loadBalancerEndpointForRegion:loadBalancer.region];
676     __block LoadBalancerRequest *request = [LoadBalancerRequest updateLoadBalancerRequest:self.account loadBalancer:loadBalancer endpoint:endpoint];
677     return [self callbackWithRequest:request];
678 }
679
680 - (APICallback *)deleteLoadBalancer:(LoadBalancer *)loadBalancer {
681     TrackEvent(CATEGORY_LOAD_BALANCER, EVENT_DELETED);
682     NSString *endpoint = [self.account loadBalancerEndpointForRegion:loadBalancer.region];
683     NSLog(@"endpoint: %@", endpoint);
684     __block LoadBalancerRequest *request = [LoadBalancerRequest deleteLoadBalancerRequest:self.account loadBalancer:loadBalancer endpoint:endpoint];
685     return [self callbackWithRequest:request];
686 }
687
688 - (APICallback *)updateLoadBalancerConnectionLogging:(LoadBalancer *)loadBalancer {
689     TrackEvent(CATEGORY_LOAD_BALANCER, EVENT_UPDATED_LB_CONNECTION_LOGGING);
690     __block LoadBalancerRequest *request = [LoadBalancerRequest updateConnectionLoggingRequest:self.account loadBalancer:loadBalancer];
691     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
692     } failure:^(OpenStackRequest *request) {
693         loadBalancer.connectionLoggingEnabled = !loadBalancer.connectionLoggingEnabled;
694     }];
695 }
696
697 - (APICallback *)getLoadBalancerConnectionThrottling:(LoadBalancer *)loadBalancer {
698     __block LoadBalancerRequest *request = [LoadBalancerRequest getConnectionThrottlingRequest:self.account loadBalancer:loadBalancer];
699     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
700         loadBalancer.connectionThrottle = [(LoadBalancerRequest *)request connectionThrottle];
701     }];
702 }
703
704 - (APICallback *)updateLoadBalancerConnectionThrottling:(LoadBalancer *)loadBalancer {
705     TrackEvent(CATEGORY_LOAD_BALANCER, EVENT_UPDATED_LB_CONNECTION_THROTTLING);
706     __block LoadBalancerRequest *request = [LoadBalancerRequest updateConnectionThrottlingRequest:self.account loadBalancer:loadBalancer];
707     return [self callbackWithRequest:request];
708 }
709
710 - (APICallback *)deleteLoadBalancerConnectionThrottling:(LoadBalancer *)loadBalancer {
711     TrackEvent(CATEGORY_LOAD_BALANCER, EVENT_DISABLED_LB_CONNECTION_THROTTLING);
712     __block LoadBalancerRequest *request = [LoadBalancerRequest disableConnectionThrottlingRequest:self.account loadBalancer:loadBalancer];
713     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
714         loadBalancer.connectionThrottle = nil;
715     }];
716 }
717
718 - (APICallback *)getLoadBalancerUsage:(LoadBalancer *)loadBalancer endpoint:(NSString *)endpoint {
719     __block LoadBalancerRequest *request = [LoadBalancerRequest getLoadBalancerUsageRequest:self.account loadBalancer:loadBalancer endpoint:endpoint];
720     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
721         loadBalancer.usage = [(LoadBalancerRequest *)request usage];
722     }];
723 }
724
725 - (APICallback *)addLBNodes:(NSArray *)nodes loadBalancer:(LoadBalancer *)loadBalancer endpoint:(NSString *)endpoint {
726     TrackEvent(CATEGORY_LOAD_BALANCER, EVENT_ADDED_LB_NODES);
727     __block LoadBalancerRequest *request = [LoadBalancerRequest addLoadBalancerNodesRequest:self.account loadBalancer:loadBalancer nodes:nodes endpoint:endpoint];
728     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
729         for (LoadBalancerNode *node in nodes) {
730             [loadBalancer.nodes addObject:node];
731         }
732         [self.account persist];
733     }];
734 }
735
736 - (APICallback *)updateLBNode:(LoadBalancerNode *)node loadBalancer:(LoadBalancer *)loadBalancer endpoint:(NSString *)endpoint {
737     TrackEvent(CATEGORY_LOAD_BALANCER, EVENT_UPDATED_LB_NODE);
738     __block LoadBalancerRequest *request = [LoadBalancerRequest updateLoadBalancerNodeRequest:self.account loadBalancer:loadBalancer node:node endpoint:endpoint];
739     return [self callbackWithRequest:request];
740 }
741
742 - (APICallback *)deleteLBNode:(LoadBalancerNode *)node loadBalancer:(LoadBalancer *)loadBalancer endpoint:(NSString *)endpoint {
743     TrackEvent(CATEGORY_LOAD_BALANCER, EVENT_DELETED_LB_NODE);
744     __block LoadBalancerRequest *request = [LoadBalancerRequest deleteLoadBalancerNodeRequest:self.account loadBalancer:loadBalancer node:node endpoint:endpoint];
745     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
746         [loadBalancer.nodes removeObject:node];
747     }];
748 }
749
750 - (APICallback *)authenticate {
751     __block OpenStackRequest *request = [OpenStackRequest authenticationRequest:self.account];
752     return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
753         if ([request isSuccess]) {        
754             self.account.authToken = [[request responseHeaders] objectForKey:@"X-Auth-Token"];
755             self.account.serversURL = [NSURL URLWithString:[[request responseHeaders] objectForKey:@"X-Server-Management-Url"]];
756             
757             if (![[request responseHeaders] objectForKey:@"X-Storage-URL"]) {
758                 NSString *filesStorageURL = [NSString stringWithFormat:@"%@/v1/%@",
759                                              [self.account.hostURL absoluteString],
760                                              [self.account username]];
761
762                 self.account.filesURL = [NSURL URLWithString:filesStorageURL];
763             }
764             else {
765                 self.account.filesURL = [NSURL URLWithString:[[request responseHeaders] objectForKey:@"X-Storage-Url"]];
766             }
767             
768             self.account.pithosPublicLinkURLPrefix = self.account.hostURL;
769             self.account.pithosLoginURLPrefix = [NSURL URLWithString:
770                                             [[self.account.hostURL absoluteString]
771                                              stringByAppendingString:@"/login"]];
772             self.account.cdnURL = [NSURL URLWithString:[[request responseHeaders] objectForKey:@"X-Cdn-Management-Url"]];
773             
774             [self.account persist];
775         }
776     }];
777 }
778
779
780 #pragma mark -
781 #pragma mark Memory Management
782
783 - (void)dealloc {
784     [objectDownloadRequests release];
785     [super dealloc];
786 }
787
788 @end