Make activityFacility update interval a user default. Move refresh button to context...
[pithos-macos] / pithos-macos / PithosSharingAccountsNode.m
1 //
2 //  PithosAccountNode.m
3 //  pithos-macos
4 //
5 // Copyright 2011-2012 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 "PithosSharingAccountsNode.h"
39 #import "PithosAccountNode.h"
40 #import "ASIPithosRequest.h"
41 #import "ASIPithos.h"
42 #import "ASIPithosAccount.h"
43 #import "ASIDownloadCache.h"
44 #import "PithosUtilities.h"
45 #import "PithosActivityFacility.h"
46
47 @implementation PithosSharingAccountsNode
48 @synthesize pithos;
49
50 #pragma mark -
51 #pragma mark Object Lifecycle
52
53 - (id)initWithPithos:(ASIPithos *)aPithos {
54     if ((self = [super init])) {
55         self.pithos = aPithos;
56         self.sharingAccount = @"";
57     }
58     return self;
59 }
60
61 - (void)dealloc {
62     [sharingAccountsRequest clearDelegatesAndCancel];
63     [sharingAccountsRequest release];
64     [sharingAccounts release];
65     [pithos release];
66     [super dealloc];
67 }
68
69 #pragma mark -
70 #pragma mark Properties
71
72 - (void)setPithos:(ASIPithos *)aPithos {
73     if (aPithos && ![aPithos isEqualTo:pithos]) {
74         [pithos release];
75         pithos = [aPithos retain];
76         [url release];
77         url = nil;
78     }
79 }
80
81 - (NSString *)url {
82     if (url == nil) 
83         url = [pithos.storageURLPrefix copy];
84     return url;
85 }
86
87 - (NSArray *)children {
88     @synchronized(self) {
89         switch (freshness) {
90             case PithosNodeStateFresh:
91                 break;
92             case PithosNodeStateRefreshNeeded:
93                 freshness = PithosNodeStateRefreshing;
94                 sharingAccountsRequest = [[ASIPithosRequest listSharingAccountsRequestWithPithos:pithos limit:0 marker:nil] retain];
95                 sharingAccountsRequest.delegate = self;
96                 sharingAccountsRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
97                 sharingAccountsRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
98                 sharingAccountsRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
99                                                    [NSNumber numberWithInteger:NSOperationQueuePriorityVeryHigh], @"priority", 
100                                                    [NSNumber numberWithUnsignedInteger:10], @"retries", 
101                                                    NSStringFromSelector(@selector(sharingAccountsRequestFinished:)), @"didFinishSelector", 
102                                                    NSStringFromSelector(@selector(sharingAccountsRequestFailed:)), @"didFailSelector", 
103                                                    nil];
104                 if (!forcedRefresh)
105                     sharingAccountsRequest.downloadCache = [ASIDownloadCache sharedCache];
106                 [[PithosUtilities prepareRequest:sharingAccountsRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
107                 break;
108             case PithosNodeStateRefreshing:
109                 break;
110             case PithosNodeStateRefreshFinished:
111                 if (newChildren) {
112                     [children release];
113                     children = newChildren;
114                     newChildren = nil;
115                 }
116                 freshness = PithosNodeStateFresh;
117             default:
118                 break;
119         }
120         return children;
121     }
122 }
123
124 - (NSString *)displayName {
125     if (displayName == nil)
126         return [NSString stringWithString:@"sharing accounts"];
127     return [[displayName copy] autorelease];
128 }
129
130 #pragma mark -
131 #pragma mark ASIHTTPRequestDelegate
132
133 - (void)sharingAccountsRequestFailed:(ASIPithosRequest *)request {
134     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
135     NSUInteger retries = [[sharingAccountsRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
136     if (retries > 0) {
137         ASIPithosRequest *newSharingAccountsRequest = (ASIPithosRequest *)[PithosUtilities copyRequest:sharingAccountsRequest];
138         [(NSMutableDictionary *)(newSharingAccountsRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
139         [sharingAccountsRequest release];
140         sharingAccountsRequest = newSharingAccountsRequest;
141         [[PithosUtilities prepareRequest:sharingAccountsRequest priority:[[sharingAccountsRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous];
142     } else {
143         NSString *message;
144         NSError *error = [sharingAccountsRequest error];
145         if (error)
146             message = [NSString stringWithFormat:@"Sharing accounts listing failed: %@", error];
147         else
148             message = [NSString stringWithFormat:@"Sharing accounts listing failed: (%d) %@", 
149                        sharingAccountsRequest.responseStatusCode, sharingAccountsRequest.responseStatusMessage];
150         dispatch_async(dispatch_get_main_queue(), ^{
151             [[PithosActivityFacility defaultPithosActivityFacility] startAndEndActivityWithType:PithosActivityOther message:message];
152         });
153         [newChildren release];
154         newChildren = nil;
155         [sharingAccountsRequest release];
156         sharingAccountsRequest = nil;
157         [sharingAccounts release];
158         sharingAccounts = nil;
159         forcedRefresh = NO;
160         @synchronized(self) {
161             freshness = PithosNodeStateRefreshNeeded;
162         }
163     }
164     [pool drain];
165 }
166
167 - (void)sharingAccountsRequestFinished:(ASIPithosRequest *)request {
168     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
169     NSLog(@"List sharing accounts finished: %@", [sharingAccountsRequest url]);
170     NSLog(@"Cached: %d", [sharingAccountsRequest didUseCachedResponse]);
171     if (sharingAccountsRequest.responseStatusCode == 200) {
172         NSArray *someSharingAccounts = [sharingAccountsRequest sharingAccounts];
173         if (sharingAccounts == nil) {
174             sharingAccounts = [[NSMutableArray alloc] initWithArray:someSharingAccounts];
175         } else {
176             [sharingAccounts addObjectsFromArray:someSharingAccounts];
177         }
178         if ([someSharingAccounts count] < 10000) {
179             if (!sharingAccountsRequest.didUseCachedResponse || ([sharingAccounts count] != [someSharingAccounts count]) || !children) {
180                 // Save new children
181                 NSLog(@"using newChildren");
182                 newChildren = [[NSMutableArray alloc] init];
183                 NSMutableIndexSet *keptNodes = [NSMutableIndexSet indexSet];
184                 for (ASIPithosAccount *account in sharingAccounts) {
185                     if (![account.name isEqualToString:pithos.authUser]) {
186                         PithosAccountNode *node = [[[PithosAccountNode alloc] init] autorelease];
187                         node.parent = self;
188                         node.shared = shared;
189                         node.sharingAccount = account.name;
190                         if (children) {
191                             NSUInteger oldIndex = [children indexOfObject:node];
192                             if (oldIndex != NSNotFound) {
193                                 // Use the same pointer value, if possible
194                                 node = [children objectAtIndex:oldIndex];
195                                 [keptNodes addIndex:oldIndex];
196                             }
197                         }
198                         [newChildren addObject:node];
199                     }
200                 }
201                 [[children objectsAtIndexes:
202                   [[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [children count])] indexesPassingTest:^(NSUInteger idx, BOOL *stop){
203                     if ([keptNodes containsIndex:idx])
204                         return NO;
205                     return YES;
206                 }]] makeObjectsPerformSelector:@selector(pithosNodeWillBeRemoved)];
207             }
208             // Else cache was used and all results were fetched during this request, so existing children can be reused
209             [sharingAccountsRequest release];
210             sharingAccountsRequest = nil;
211             [sharingAccounts release];
212             sharingAccounts = nil;
213             forcedRefresh = NO;
214             @synchronized(self) {
215                 freshness = PithosNodeStateRefreshFinished;
216             }
217             // Notify observers that children are updated
218             [[NSNotificationCenter defaultCenter] postNotificationName:@"PithosSharingAccountsNodeChildrenUpdated" object:self];
219         } else {
220             [sharingAccountsRequest release];
221             // Do an additional request to fetch more objects
222             sharingAccountsRequest = [[ASIPithosRequest listSharingAccountsRequestWithPithos:pithos 
223                                                                                        limit:0 
224                                                                                       marker:[[someSharingAccounts lastObject] name]] retain];
225             sharingAccountsRequest.delegate = self;
226             sharingAccountsRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
227             sharingAccountsRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
228             sharingAccountsRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
229                                                [NSNumber numberWithInteger:NSOperationQueuePriorityVeryHigh], @"priority", 
230                                                [NSNumber numberWithUnsignedInteger:10], @"retries", 
231                                                NSStringFromSelector(@selector(sharingAccountsRequestFinished:)), @"didFinishSelector", 
232                                                NSStringFromSelector(@selector(sharingAccountsRequestFailed:)), @"didFailSelector", 
233                                                nil];
234             if (!forcedRefresh)
235                 sharingAccountsRequest.downloadCache = [ASIDownloadCache sharedCache];
236             [[PithosUtilities prepareRequest:sharingAccountsRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
237         }
238     } else {
239         [self sharingAccountsRequestFailed:sharingAccountsRequest];
240     }
241     [pool drain];
242 }
243
244 @end