Shift-refresh forces no use of cache.
[pithos-macos] / pithos-macos / PithosAccountNode.m
1 //
2 //  PithosAccountNode.m
3 //  pithos-macos
4 //
5 // Copyright 2011 GRNET S.A. All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or
8 // without modification, are permitted provided that the following
9 // conditions are met:
10 // 
11 //   1. Redistributions of source code must retain the above
12 //      copyright notice, this list of conditions and the following
13 //      disclaimer.
14 // 
15 //   2. Redistributions in binary form must reproduce the above
16 //      copyright notice, this list of conditions and the following
17 //      disclaimer in the documentation and/or other materials
18 //      provided with the distribution.
19 // 
20 // THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
21 // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
24 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 // 
33 // The views and conclusions contained in the software and
34 // documentation are those of the authors and should not be
35 // interpreted as representing official policies, either expressed
36 // or implied, of GRNET S.A.
37
38 #import "PithosAccountNode.h"
39 #import "PithosContainerNode.h"
40 #import "ASIPithosAccountRequest.h"
41 #import "ASIPithosContainer.h"
42 #import "ASIDownloadCache.h"
43 #import "PithosFileUtilities.h"
44
45 static NSImage *sharedIcon = nil;
46
47 @implementation PithosAccountNode
48
49 + (void)initialize {
50         if (self == [PithosAccountNode class])
51         sharedIcon = [[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kUserIcon)] retain];
52 }
53
54 #pragma mark -
55 #pragma mark Object Lifecycle
56
57 - (void)dealloc {
58     [accountRequest clearDelegatesAndCancel];
59     [accountRequest release];
60     [containers release];
61     [super dealloc];
62 }
63
64 #pragma mark -
65 #pragma mark Properties
66
67 - (NSString *)url {
68     if (url == nil)
69         url = [[NSString alloc] initWithFormat:@"%@%@", 
70                (sharingAccount ? [ASIPithosRequest storageURLWithAuthUser:sharingAccount] : [ASIPithosRequest storageURL]), 
71                (shared ? @"?shared" : @"")];
72     return url;
73 }
74
75 - (NSArray *)children {
76     @synchronized(self) {
77         switch (freshness) {
78             case PithosNodeStateFresh:
79                 break;
80             case PithosNodeStateRefreshNeeded:
81                 freshness = PithosNodeStateRefreshing;
82                 accountRequest = [[ASIPithosAccountRequest listContainersRequestWithLimit:0 
83                                                                                    marker:nil 
84                                                                                    shared:shared 
85                                                                                     until:nil] retain];
86                 if (sharingAccount)
87                     [accountRequest setRequestUserFromDefaultTo:sharingAccount];
88                 accountRequest.delegate = self;
89                 accountRequest.didFinishSelector = @selector(accountRequestFinished:);
90                 accountRequest.didFailSelector = @selector(accountRequestFailed:);
91                 if (!forcedRefresh)
92                     accountRequest.downloadCache = [ASIDownloadCache sharedCache];
93                 [accountRequest startAsynchronous];
94                 break;
95             case PithosNodeStateRefreshing:
96                 break;
97             case PithosNodeStateRefreshFinished:
98                 if (newChildren) {
99                     [children release];
100                     children = newChildren;
101                     newChildren = nil;
102                 }
103                 freshness = PithosNodeStateFresh;
104             default:
105                 break;
106         }
107         return children;
108     }
109 }
110
111 - (NSString *)displayName {
112     if (displayName == nil)
113         return [NSString stringWithString:(sharingAccount ? sharingAccount : @"account")];
114     return [[displayName copy] autorelease];
115 }
116
117 - (NSImage *)icon {
118     if (icon == nil)
119         icon = [sharedIcon retain];
120     return icon;
121 }
122
123 #pragma mark -
124 #pragma mark ASIHTTPRequestDelegate
125
126 - (void)accountRequestFinished:(ASIPithosAccountRequest *)request {
127     NSLog(@"URL: %@", [accountRequest url]);
128     NSLog(@"cached: %d", [accountRequest didUseCachedResponse]);
129     
130     NSArray *someContainers = [accountRequest containers];
131     if (containers == nil) {
132         containers = [[NSMutableArray alloc] initWithArray:someContainers];
133     } else {
134         [containers addObjectsFromArray:someContainers];
135     }
136     if ([someContainers count] < 10000) {
137         if (!accountRequest.didUseCachedResponse || ([containers count] != [someContainers count]) || !children) {
138             // Save new children
139             NSLog(@"using newChildren");
140             newChildren = [[NSMutableArray alloc] init];
141             NSMutableIndexSet *keptNodes = [NSMutableIndexSet indexSet];
142             for (ASIPithosContainer *container in containers) {
143                 PithosContainerNode *node = [[[PithosContainerNode alloc] initWithPithosContainer:container] autorelease];
144                 node.parent = self;
145                 node.shared = shared;
146                 node.sharingAccount = sharingAccount;
147                 if (children) {
148                     NSUInteger oldIndex = [children indexOfObject:node];
149                     if (oldIndex != NSNotFound) {
150                         // Use the same pointer value, if possible
151                         node = [children objectAtIndex:oldIndex];
152                         node.pithosContainer = container;
153                         [keptNodes addIndex:oldIndex];
154                     }
155                 }
156                 [newChildren addObject:node];
157             }
158             [[children objectsAtIndexes:
159               [[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [children count])] indexesPassingTest:^(NSUInteger idx, BOOL *stop){
160                 if ([keptNodes containsIndex:idx])
161                     return NO;
162                 return YES;
163             }]] makeObjectsPerformSelector:@selector(pithosNodeWillBeRemoved)];
164         }
165         // Else cache was used and all results were fetched during this request, so existing children can be reused
166         [accountRequest release];
167         accountRequest = nil;
168         [containers release];
169         containers = nil;
170         forcedRefresh = NO;
171         @synchronized(self) {
172             freshness = PithosNodeStateRefreshFinished;
173         }
174         // Notify observers that children are updated
175         [[NSNotificationCenter defaultCenter] postNotificationName:@"PithosAccountNodeChildrenUpdated" object:self];
176     } else {
177         [accountRequest release];
178         // Do an additional request to fetch more objects
179         accountRequest = [[ASIPithosAccountRequest listContainersRequestWithLimit:0 
180                                                                            marker:[[someContainers lastObject] name] 
181                                                                            shared:shared 
182                                                                             until:nil] retain];
183         if (sharingAccount)
184             [accountRequest setRequestUserFromDefaultTo:sharingAccount];
185         accountRequest.delegate = self;
186         if (!forcedRefresh)
187             accountRequest.downloadCache = [ASIDownloadCache sharedCache];
188         [accountRequest startAsynchronous];
189     }
190 }
191
192 - (void)accountRequestFailed:(ASIPithosAccountRequest *)request {
193     [PithosFileUtilities httpRequestErrorAlertWithRequest:request];
194     [newChildren release];
195     newChildren = nil;
196     [accountRequest release];
197     accountRequest = nil;
198     [containers release];
199     containers = nil;
200     forcedRefresh = NO;
201     @synchronized(self) {
202         freshness = PithosNodeStateRefreshNeeded;
203     }
204 }
205
206 @end