All requests made asynchronous.
[pithos-macos] / pithos-macos / PithosAccountNode.m
index 973d7a1..e45b6d7 100644 (file)
@@ -1,5 +1,5 @@
 //
-//  PithosNode.m
+//  PithosAccountNode.m
 //  pithos-macos
 //
 // Copyright 2011 GRNET S.A. All rights reserved.
 #import "PithosAccountNode.h"
 #import "PithosContainerNode.h"
 #import "ASIPithosAccountRequest.h"
+#import "ASIPithosAccount.h"
 #import "ASIPithosContainer.h"
 #import "ASIDownloadCache.h"
+#import "PithosUtilities.h"
+
+static NSImage *sharedIcon = nil;
 
 @implementation PithosAccountNode
+@synthesize pithosAccount;
+
++ (void)initialize {
+       if (self == [PithosAccountNode class])
+        sharedIcon = [[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kUserIcon)] retain];
+}
 
 #pragma mark -
 #pragma mark Object Lifecycle
 
-- (id)init {
-    if ((self = [super init])) {
-        refreshing = NO;
-    }
-    return self;
-}
-
 - (void)dealloc {
+    [accountRequest clearDelegatesAndCancel];
+    [accountRequest release];
+    [refreshMetadataAccountRequest clearDelegatesAndCancel];
+    [refreshMetadataAccountRequest release];
+    [applyMetadataAccountRequest clearDelegatesAndCancel];
+    [applyMetadataAccountRequest release];
     [containers release];
+    [pithosAccount release];
     [super dealloc];
 }
 
 #pragma mark -
+#pragma mark Properties
+
+- (NSString *)url {
+    if (url == nil)
+        url = [[NSString alloc] initWithFormat:@"%@%@", 
+               (sharingAccount ? [ASIPithosRequest storageURLWithAuthUser:sharingAccount] : [ASIPithosRequest storageURL]), 
+               (shared ? @"?shared" : @"")];
+    return url;
+}
+
+- (NSArray *)children {
+    @synchronized(self) {
+        switch (freshness) {
+            case PithosNodeStateFresh:
+                break;
+            case PithosNodeStateRefreshNeeded:
+                freshness = PithosNodeStateRefreshing;
+                accountRequest = [[ASIPithosAccountRequest listContainersRequestWithLimit:0 
+                                                                                   marker:nil 
+                                                                                   shared:shared 
+                                                                                    until:nil] retain];
+                if (sharingAccount)
+                    [accountRequest setRequestUserFromDefaultTo:sharingAccount];
+                accountRequest.delegate = self;
+                accountRequest.didFinishSelector = @selector(accountRequestFinished:);
+                accountRequest.didFailSelector = @selector(accountRequestFailed:);
+                if (!forcedRefresh)
+                    accountRequest.downloadCache = [ASIDownloadCache sharedCache];
+                [[PithosUtilities prepareRequest:accountRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
+                break;
+            case PithosNodeStateRefreshing:
+                break;
+            case PithosNodeStateRefreshFinished:
+                if (newChildren) {
+                    [children release];
+                    children = newChildren;
+                    newChildren = nil;
+                }
+                freshness = PithosNodeStateFresh;
+            default:
+                break;
+        }
+        return children;
+    }
+}
+
+- (NSString *)displayName {
+    if (displayName == nil)
+        return [NSString stringWithString:(sharingAccount ? sharingAccount : @"account")];
+    return [[displayName copy] autorelease];
+}
+
+- (NSImage *)icon {
+    if (icon == nil)
+        icon = [sharedIcon retain];
+    return icon;
+}
+
+#pragma mark -
 #pragma mark ASIHTTPRequestDelegate
 
-- (void)requestFinished:(ASIPithosAccountRequest *)accountRequest {
+- (void)accountRequestFinished:(ASIPithosAccountRequest *)request {
     NSLog(@"URL: %@", [accountRequest url]);
     NSLog(@"cached: %d", [accountRequest didUseCachedResponse]);
+
+    self.pithosAccount = [accountRequest account];
     
     NSArray *someContainers = [accountRequest containers];
     if (containers == nil) {
         if (!accountRequest.didUseCachedResponse || ([containers count] != [someContainers count]) || !children) {
             // Save new children
             NSLog(@"using newChildren");
-            NSMutableArray *newChildren = [NSMutableArray array];
+            newChildren = [[NSMutableArray alloc] init];
+            NSMutableIndexSet *keptNodes = [NSMutableIndexSet indexSet];
             for (ASIPithosContainer *container in containers) {
                 PithosContainerNode *node = [[[PithosContainerNode alloc] initWithPithosContainer:container] autorelease];
+                node.parent = self;
+                node.shared = shared;
+                node.sharingAccount = sharingAccount;
                 if (children) {
                     NSUInteger oldIndex = [children indexOfObject:node];
-                    if (oldIndex != NSNotFound)
+                    if (oldIndex != NSNotFound) {
                         // Use the same pointer value, if possible
                         node = [children objectAtIndex:oldIndex];
+                        node.pithosContainer = container;
+                        [keptNodes addIndex:oldIndex];
+                    }
                 }
                 [newChildren addObject:node];
             }
-            [children release];
-            children = [newChildren retain];
+            [[children objectsAtIndexes:
+              [[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [children count])] indexesPassingTest:^(NSUInteger idx, BOOL *stop){
+                if ([keptNodes containsIndex:idx])
+                    return NO;
+                return YES;
+            }]] makeObjectsPerformSelector:@selector(pithosNodeWillBeRemoved)];
         }
-        // Else cache was used and all results were fetched during this request, so previousChildren can be reused
+        // Else cache was used and all results were fetched during this request, so existing children can be reused
+        [accountRequest release];
+        accountRequest = nil;
         [containers release];
         containers = nil;
-        // XXX sort children based on preferences
-        refreshing = NO;
+        forcedRefresh = NO;
+        @synchronized(self) {
+            freshness = PithosNodeStateRefreshFinished;
+        }
         // Notify observers that children are updated
         [[NSNotificationCenter defaultCenter] postNotificationName:@"PithosAccountNodeChildrenUpdated" object:self];
     } else {
+        [accountRequest release];
         // Do an additional request to fetch more objects
-        ASIPithosAccountRequest *newAccountRequest = [ASIPithosAccountRequest listContainersRequestWithLimit:0 
-                                                                                                      marker:[[someContainers lastObject] name] 
-                                                                                                      shared:NO 
-                                                                                                       until:nil];
-        newAccountRequest.delegate = self;
-        newAccountRequest.downloadCache = [ASIDownloadCache sharedCache];
-        [newAccountRequest startAsynchronous];
+        accountRequest = [[ASIPithosAccountRequest listContainersRequestWithLimit:0 
+                                                                           marker:[[someContainers lastObject] name] 
+                                                                           shared:shared 
+                                                                            until:nil] retain];
+        if (sharingAccount)
+            [accountRequest setRequestUserFromDefaultTo:sharingAccount];
+        accountRequest.delegate = self;
+        if (!forcedRefresh)
+            accountRequest.downloadCache = [ASIDownloadCache sharedCache];
+        [[PithosUtilities prepareRequest:accountRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
     }
 }
 
-- (void)requestFailed:(ASIPithosAccountRequest *)accountRequest {
-    // XXX do something on error, cleanup
-    NSLog(@"error:%@", [accountRequest error]);
+- (void)accountRequestFailed:(ASIPithosAccountRequest *)request {
+    [PithosUtilities httpRequestErrorAlertWithRequest:request];
+    [newChildren release];
+    newChildren = nil;
+    [accountRequest release];
+    accountRequest = nil;
     [containers release];
     containers = nil;
-    childrenDirty = YES;
-    refreshing = NO;
+    forcedRefresh = NO;
+    @synchronized(self) {
+        freshness = PithosNodeStateRefreshNeeded;
+    }
 }
 
-#pragma mark -
-#pragma mark Properties
-
-- (NSString *)url {
-    if (url == nil) 
-        url = [[ASIPithosRequest storageURL] copy];
-    return url;
+- (void)accountMetadataRequestFinished:(ASIPithosAccountRequest *)request {
+    NSLog(@"URL: %@", [request url]);
+    NSLog(@"cached: %d", [request didUseCachedResponse]);
+    
+    if ([request isEqualTo:applyMetadataAccountRequest]) {
+        @synchronized(self) {
+            [applyMetadataAccountRequest release];
+            applyMetadataAccountRequest = nil;
+        }
+        [self refreshInfo];
+    } else if ([request isEqualTo:refreshMetadataAccountRequest]) {
+        self.pithosAccount = [refreshMetadataAccountRequest account];
+        @synchronized(self) {
+            [refreshMetadataAccountRequest release];
+            refreshMetadataAccountRequest = nil;
+        }
+    }
 }
 
-- (NSArray *)children {
-    if (childrenDirty) {
-        @synchronized (self) {
-            if (!refreshing) {
-                refreshing = YES;
-                childrenDirty = NO;
-                ASIPithosAccountRequest *accountRequest = [ASIPithosAccountRequest listContainersRequestWithLimit:0 
-                                                                                                           marker:nil 
-                                                                                                           shared:NO 
-                                                                                                            until:nil];
-                accountRequest.delegate = self;
-                accountRequest.downloadCache = [ASIDownloadCache sharedCache];
-                [accountRequest startAsynchronous];
-            }
+- (void)accountMetadataRequestFailed:(ASIPithosAccountRequest *)request {
+    if ([request isEqualTo:applyMetadataAccountRequest]) {
+        [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataAccountRequest];
+        @synchronized(self) {
+            [applyMetadataAccountRequest release];
+            applyMetadataAccountRequest = nil;
+        }
+    } else if ([request isEqualTo:refreshMetadataAccountRequest]) {
+        [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataAccountRequest];
+        @synchronized(self) {
+            [refreshMetadataAccountRequest release];
+            refreshMetadataAccountRequest = nil;
         }
     }
-    return children;
 }
 
-- (NSString *)displayName {
-    if (displayName == nil) {
-        displayName = [[NSString alloc] initWithString:@"account"];
+#pragma mark -
+#pragma mark Info
+
+- (void)applyInfo {
+    @synchronized(self) {
+        if (applyMetadataAccountRequest == nil) {
+            NSMutableDictionary *groups = pithosAccount.groups;
+            if ([groups count] == 0)
+                groups = [NSMutableDictionary dictionaryWithObject:@"" forKey:@"group"];
+            applyMetadataAccountRequest = [[ASIPithosAccountRequest updateAccountMetadataRequestWithGroups:groups 
+                                                                                                  metadata:pithosAccount.metadata 
+                                                                                                    update:NO] retain];
+            applyMetadataAccountRequest.delegate = self;
+            applyMetadataAccountRequest.didFinishSelector = @selector(accountMetadataRequestFinished:);
+            applyMetadataAccountRequest.didFailSelector = @selector(accountMetadataRequestFailed:);
+            [[PithosUtilities prepareRequest:applyMetadataAccountRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
+        }
     }
-    return displayName;
 }
 
-- (NSImage *)icon {
-    return nil;
+- (void)refreshInfo {
+    @synchronized(self) {
+        if (refreshMetadataAccountRequest == nil) {
+            refreshMetadataAccountRequest = [[ASIPithosAccountRequest accountMetadataRequest] retain];
+            refreshMetadataAccountRequest.delegate = self;
+            refreshMetadataAccountRequest.didFinishSelector = @selector(accountMetadataRequestFinished:);
+            refreshMetadataAccountRequest.didFailSelector = @selector(accountMetadataRequestFailed:);
+            refreshMetadataAccountRequest.downloadCache = [ASIDownloadCache sharedCache];
+            [[PithosUtilities prepareRequest:refreshMetadataAccountRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
+        }
+    }
 }
-    
+
 @end