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