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