root / Classes / OpenStackRequest.m @ 62ea6d49
History | View | Annotate | Download (21.8 kB)
1 |
// |
---|---|
2 |
// OpenStackRequest.m |
3 |
// OpenStack |
4 |
// |
5 |
// Created by Mike Mayo on 10/8/10. |
6 |
// The OpenStack project is provided under the Apache 2.0 license. |
7 |
// |
8 |
|
9 |
#import "OpenStackRequest.h" |
10 |
#import "Provider.h" |
11 |
#import "OpenStackAccount.h" |
12 |
#import "JSON.h" |
13 |
#import "Container.h" |
14 |
#import "StorageObject.h" |
15 |
#import "Folder.h" |
16 |
#import "AccountManager.h" |
17 |
#import "APICallback.h" |
18 |
#import "APILogEntry.h" |
19 |
#import "NSString+Conveniences.h" |
20 |
|
21 |
@implementation OpenStackRequest |
22 |
|
23 |
@synthesize account, callback, errorAlerter, retryWithUpdatedURL, retryBaseURL, retryType, followUpSelectorString, notificationURL; |
24 |
|
25 |
#pragma mark - Constructors |
26 |
#pragma mark Generic |
27 |
|
28 |
+ (id)requestWithoutToken:(OpenStackAccount *)account method:(NSString *)method url:(NSURL *)url { |
29 |
OpenStackRequest *request = [[[self alloc] initWithURL:url] autorelease]; |
30 |
request.account = account; |
31 |
request.requestMethod = method; |
32 |
[request addRequestHeader:@"Content-Type" value:@"application/json"]; |
33 |
request.timeOutSeconds = 60; |
34 |
request.numberOfTimesToRetryOnTimeout = 5; |
35 |
request.validatesSecureCertificate = !account.ignoreSSLErrors; |
36 |
request.retryWithUpdatedURL = NO; |
37 |
return request; |
38 |
} |
39 |
|
40 |
+ (id)request:(OpenStackAccount *)account method:(NSString *)method url:(NSURL *)url { |
41 |
OpenStackRequest *request = [self requestWithoutToken:account method:method url:url]; |
42 |
request.retryWithUpdatedURL = (account.provider.manual ? NO : YES); |
43 |
[request addRequestHeader:@"X-Auth-Token" value:account.authToken]; |
44 |
return request; |
45 |
} |
46 |
|
47 |
+ (id)filesRequest:(OpenStackAccount *)account method:(NSString *)method path:(NSString *)path { |
48 |
NSString *urlString = [[account.provider.authEndpointURL |
49 |
URLByAppendingPathComponent:(account.sharingAccount ? account.sharingAccount : account.username)] description]; |
50 |
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@?format=json%@", |
51 |
urlString, |
52 |
path, |
53 |
(account.shared ? @"&shared=" : @"")]]; |
54 |
OpenStackRequest *request = [self request:account method:method url:url]; |
55 |
request.retryBaseURL = account.provider.authEndpointURL; |
56 |
request.retryType = OpenStackRequestTypeAuthEndpoint; |
57 |
return request; |
58 |
} |
59 |
|
60 |
#pragma mark NSCopying |
61 |
|
62 |
- (id)copyWithZone:(NSZone *)zone { |
63 |
OpenStackRequest *newRequest = [super copyWithZone:zone]; |
64 |
newRequest.account = self.account; |
65 |
newRequest.callback = self.callback; |
66 |
newRequest.errorAlerter = self.errorAlerter; |
67 |
newRequest.retryWithUpdatedURL = self.retryWithUpdatedURL; |
68 |
newRequest.retryBaseURL = self.retryBaseURL; |
69 |
newRequest.retryType = self.retryType; |
70 |
newRequest.followUpSelectorString = self.followUpSelectorString; |
71 |
newRequest.notificationURL = self.notificationURL; |
72 |
return newRequest; |
73 |
} |
74 |
|
75 |
#pragma mark Service Catalog |
76 |
+ (id)serviceCatalogRequest:(OpenStackAccount *)account { |
77 |
OpenStackRequest *request = [self requestWithoutToken:account method:@"POST" url:account.provider.tokensURL]; |
78 |
if (account.authToken.length) |
79 |
[request appendPostData:[[NSString stringWithFormat:@"{\"auth\":{\"token\":{\"id\":\"%@\"}}}", account.authToken] |
80 |
dataUsingEncoding:NSUTF8StringEncoding]]; |
81 |
return request; |
82 |
} |
83 |
|
84 |
- (NSDictionary *)access { |
85 |
SBJSON *parser = [[[SBJSON alloc] init] autorelease]; |
86 |
NSDictionary *access = [[parser objectWithString:[self responseString]] objectForKey:@"access"]; |
87 |
return access; |
88 |
} |
89 |
|
90 |
- (NSDictionary *)token { |
91 |
return [[self access] objectForKey:@"token"]; |
92 |
} |
93 |
|
94 |
- (NSArray *)serviceCatalog { |
95 |
return [[self access] objectForKey:@"serviceCatalog"]; |
96 |
} |
97 |
|
98 |
- (NSArray *)user { |
99 |
return [[self access] objectForKey:@"user"]; |
100 |
} |
101 |
|
102 |
#pragma mark User Catalog |
103 |
+ (id)userCatalogRequest:(OpenStackAccount *)account displaynames:(NSArray *)displaynames UUIDs:(NSArray *)UUIDs { |
104 |
OpenStackRequest *request = [self request:account method:@"POST" url:account.provider.userCatalogURL]; |
105 |
request.retryBaseURL = account.provider.userCatalogURL; |
106 |
request.retryType = OpenStackRequestTypeUserCatalog; |
107 |
NSMutableString *dataString = [NSMutableString stringWithString:@"{\"displaynames\":["]; |
108 |
if (displaynames) { |
109 |
for (NSUInteger index = 0 ; index < displaynames.count ; index++) { |
110 |
[dataString appendFormat:@"\"%@\"%@", |
111 |
[[[displaynames objectAtIndex:index] stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"] |
112 |
stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""], |
113 |
((index == displaynames.count - 1) ? @"" : @",")]; |
114 |
} |
115 |
} |
116 |
[dataString appendFormat:@"],\"uuids\":["]; |
117 |
if (UUIDs) { |
118 |
for (NSUInteger index = 0 ; index < UUIDs.count ; index++) { |
119 |
[dataString appendFormat:@"\"%@\"%@", [UUIDs objectAtIndex:index], ((index == UUIDs.count - 1) ? @"" : @",")]; |
120 |
} |
121 |
} |
122 |
[dataString appendFormat:@"]}"]; |
123 |
[request appendPostData:[dataString dataUsingEncoding:NSUTF8StringEncoding]]; |
124 |
return request; |
125 |
} |
126 |
|
127 |
- (NSDictionary *)catalogs { |
128 |
SBJSON *parser = [[[SBJSON alloc] init] autorelease]; |
129 |
NSDictionary *catalogs = [parser objectWithString:[self responseString]]; |
130 |
return catalogs; |
131 |
} |
132 |
|
133 |
- (NSDictionary *)displaynameCatalog { |
134 |
return [[self catalogs] objectForKey:@"displayname_catalog"]; |
135 |
} |
136 |
|
137 |
- (NSDictionary *)UUIDCatalog { |
138 |
return [[self catalogs] objectForKey:@"uuid_catalog"]; |
139 |
} |
140 |
|
141 |
#pragma mark Top |
142 |
|
143 |
+ (id)authenticationRequest:(OpenStackAccount *)account { |
144 |
OpenStackRequest *request = [[[self alloc] initWithURL:account.provider.authEndpointURL] autorelease]; |
145 |
request.account = account; |
146 |
request.requestMethod = @"GET"; |
147 |
[request addRequestHeader:@"X-Auth-User" value:account.username]; |
148 |
[request addRequestHeader:@"X-Auth-Token" value:account.authToken]; |
149 |
request.timeOutSeconds = 60; |
150 |
request.numberOfTimesToRetryOnTimeout = 5; |
151 |
request.validatesSecureCertificate = !account.ignoreSSLErrors; |
152 |
request.retryWithUpdatedURL = (account.provider.manual ? NO : YES); |
153 |
request.retryBaseURL = account.provider.authEndpointURL; |
154 |
request.retryType = OpenStackRequestTypeAuthEndpoint; |
155 |
return request; |
156 |
} |
157 |
|
158 |
+ (id)getSharingAccountsRequest:(OpenStackAccount *)account |
159 |
marker:(NSString *)marker sharingAccountsBuffer:(NSMutableDictionary *)sharingAccountsBuffer { |
160 |
OpenStackRequest *request = [self request:account method:@"GET" |
161 |
url:[NSURL URLWithString:[NSString stringWithFormat:@"%@?format=json", |
162 |
account.provider.authEndpointURL]]]; |
163 |
request.retryBaseURL = account.provider.authEndpointURL; |
164 |
request.retryType = OpenStackRequestTypeAuthEndpoint; |
165 |
if (marker) |
166 |
request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&marker=%@", request.url.description, [NSString encodeToPercentEscape:marker]]]; |
167 |
if (!sharingAccountsBuffer) |
168 |
sharingAccountsBuffer = [NSMutableDictionary dictionary]; |
169 |
request.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: |
170 |
sharingAccountsBuffer, @"sharingAccountsBuffer", |
171 |
nil]; |
172 |
return request; |
173 |
} |
174 |
|
175 |
+ (id)getSharingAccountsRequest:(OpenStackAccount *)account { |
176 |
return [self getSharingAccountsRequest:account marker:nil sharingAccountsBuffer:nil]; |
177 |
} |
178 |
|
179 |
- (NSArray *)jsonSharingAccounts { |
180 |
return [[[[SBJSON alloc] init] autorelease] objectWithString:[self responseString]]; |
181 |
} |
182 |
|
183 |
#pragma mark Account |
184 |
|
185 |
+ (id)getStorageAccountInfoRequest:(OpenStackAccount *)account { |
186 |
return [self filesRequest:account method:@"HEAD" path:@""]; |
187 |
} |
188 |
|
189 |
+ (id)getContainersRequest:(OpenStackAccount *)account |
190 |
marker:(NSString *)marker containersBuffer:(NSMutableDictionary *)containersBuffer { |
191 |
OpenStackRequest *request = [self filesRequest:account method:@"GET" path:@""]; |
192 |
if (marker) |
193 |
request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&marker=%@", request.url.description, [NSString encodeToPercentEscape:marker]]]; |
194 |
if (!containersBuffer) |
195 |
containersBuffer = [NSMutableDictionary dictionary]; |
196 |
request.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: |
197 |
containersBuffer, @"containersBuffer", |
198 |
nil]; |
199 |
return request; |
200 |
} |
201 |
|
202 |
+ (id)getContainersRequest:(OpenStackAccount *)account { |
203 |
return [self getContainersRequest:account marker:nil containersBuffer:nil]; |
204 |
} |
205 |
|
206 |
- (NSArray *)jsonContainers { |
207 |
return [[[[SBJSON alloc] init] autorelease] objectWithString:[self responseString]]; |
208 |
} |
209 |
|
210 |
+ (id)writeAccountMetadataRequest:(OpenStackAccount *)account withAccountInfo:(NSDictionary *)accountInfo { |
211 |
OpenStackRequest *request = [self filesRequest:account method:@"POST" path:@""]; |
212 |
|
213 |
NSMutableDictionary *groups = [accountInfo objectForKey:@"groups"]; |
214 |
if (groups.count) { |
215 |
for (NSString *groupName in groups) { |
216 |
[request.requestHeaders setObject:[NSString encodeToPercentEscape:[groups objectForKey:groupName]] |
217 |
forKey:[NSString stringWithFormat:@"X-Account-Group-%@", [NSString encodeToPercentEscape:groupName]]]; |
218 |
} |
219 |
} else { |
220 |
[request.requestHeaders setObject:@"" forKey:@"X-Account-Group-group"]; |
221 |
} |
222 |
|
223 |
NSMutableDictionary *metadata = [accountInfo objectForKey:@"metadata"]; |
224 |
for (NSString *key in metadata) { |
225 |
[request.requestHeaders setObject:[NSString encodeToPercentEscape:[metadata objectForKey:key]] |
226 |
forKey:[NSString stringWithFormat:@"X-Account-Meta-%@", [NSString encodeToPercentEscape:key]]]; |
227 |
} |
228 |
|
229 |
return request; |
230 |
} |
231 |
|
232 |
#pragma mark Container |
233 |
|
234 |
+ (id)getContainerInfoRequest:(OpenStackAccount *)account container:(Container *)container { |
235 |
return [self filesRequest:account method:@"HEAD" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]]; |
236 |
} |
237 |
|
238 |
+ (id)createContainerRequest:(OpenStackAccount *)account container:(Container *)container { |
239 |
return [self filesRequest:account method:@"PUT" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]]; |
240 |
} |
241 |
|
242 |
+ (id)deleteContainerRequest:(OpenStackAccount *)account container:(Container *)container { |
243 |
return [self filesRequest:account method:@"DELETE" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]]; |
244 |
} |
245 |
|
246 |
+ (id)getObjectsRequest:(OpenStackAccount *)account container:(Container *)container |
247 |
marker:(NSString *)marker objectsBuffer:(NSMutableDictionary *)objectsBuffer { |
248 |
OpenStackRequest *request = [self filesRequest:account method:@"GET" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]]; |
249 |
if (marker) |
250 |
request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&marker=%@", request.url.description, [NSString encodeToPercentEscape:marker]]]; |
251 |
if (!objectsBuffer) |
252 |
objectsBuffer = [NSMutableDictionary dictionary]; |
253 |
request.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: |
254 |
container, @"container", |
255 |
objectsBuffer, @"objectsBuffer", |
256 |
nil]; |
257 |
return request; |
258 |
} |
259 |
|
260 |
+ (id)getObjectsRequest:(OpenStackAccount *)account container:(Container *)container { |
261 |
return [self getObjectsRequest:account container:container marker:nil objectsBuffer:nil]; |
262 |
} |
263 |
|
264 |
- (NSArray *)jsonObjects { |
265 |
return [[[[SBJSON alloc] init] autorelease] objectWithString:[self responseString]]; |
266 |
} |
267 |
|
268 |
+ (id)writeContainerPolicyRequest:(OpenStackAccount *)account container:(Container *)container { |
269 |
OpenStackRequest *request = [self filesRequest:account method:@"PUT" path:[NSString stringWithFormat:@"/%@", [NSString encodeToPercentEscape:container.name]]]; |
270 |
[request.requestHeaders setObject:container.versioning forKey:@"X-Container-Policy-Versioning"]; |
271 |
[request.requestHeaders setObject:[NSString stringWithFormat:@"%u", container.quota] forKey:@"X-Container-Policy-Quota"]; |
272 |
return request; |
273 |
} |
274 |
|
275 |
#pragma mark Storage Object |
276 |
|
277 |
+ (id)getObjectInfoRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
278 |
NSString *objectFullPath = object.fullPath; |
279 |
if ([objectFullPath hasPrefix:@"/"]) |
280 |
objectFullPath = [objectFullPath substringFromIndex:1]; |
281 |
return [self filesRequest:account method:@"HEAD" path:[NSString stringWithFormat:@"/%@/%@", [NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:objectFullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]]; |
282 |
} |
283 |
|
284 |
+ (id)getObjectInfoRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object version:(NSString *)version { |
285 |
OpenStackRequest *request = [self getObjectInfoRequest:account container:container object:object]; |
286 |
request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&version=%@", request.url.description, version]]; |
287 |
return request; |
288 |
} |
289 |
|
290 |
+ (id)getObjectVersionsRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
291 |
OpenStackRequest *request = [self filesRequest:account method:@"GET" path:[NSString stringWithFormat:@"/%@/%@", [NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]]; |
292 |
request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&version=list", request.url.description]]; |
293 |
return request; |
294 |
} |
295 |
|
296 |
- (NSMutableArray *)versions { |
297 |
SBJSON *parser = [[[SBJSON alloc] init] autorelease]; |
298 |
NSArray *jsonVersions = [[parser objectWithString:[self responseString]] objectForKey:@"versions"]; |
299 |
NSMutableArray *versions = [NSMutableArray arrayWithCapacity:[jsonVersions count]]; |
300 |
for (NSArray *jsonVersion in jsonVersions) { |
301 |
[versions addObject:[NSDictionary dictionaryWithObjectsAndKeys: |
302 |
[jsonVersion objectAtIndex:0], @"versionID", |
303 |
[NSDate dateWithTimeIntervalSince1970:[[jsonVersion objectAtIndex:1] doubleValue]], @"versionDate", |
304 |
nil]]; |
305 |
} |
306 |
return versions; |
307 |
} |
308 |
|
309 |
|
310 |
+ (id)getObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
311 |
return [self filesRequest:account method:@"GET" path:[NSString stringWithFormat:@"/%@/%@", [NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:object.fullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]]; |
312 |
} |
313 |
|
314 |
+ (id)getObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object version:(NSString *)version { |
315 |
OpenStackRequest *request = [self getObjectRequest:account container:container object:object]; |
316 |
if (version) |
317 |
request.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&version=%@", request.url.description, version]]; |
318 |
return request; |
319 |
} |
320 |
|
321 |
+ (id)writeObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
322 |
NSString *objectFullPath = object.fullPath; |
323 |
if ([objectFullPath hasPrefix:@"/"]) |
324 |
objectFullPath = [objectFullPath substringFromIndex:1]; |
325 |
OpenStackRequest *request = [self filesRequest:account method:@"PUT" path:[NSString stringWithFormat:@"/%@/%@", [NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:objectFullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]]; |
326 |
|
327 |
if (object.sharing) |
328 |
[request.requestHeaders setObject:object.sharing forKey:@"X-Object-Sharing"]; |
329 |
|
330 |
NSString *metadataKeyHeaderPrefix; |
331 |
if ([objectFullPath length] == 0) |
332 |
metadataKeyHeaderPrefix = @"X-Container-Meta-"; |
333 |
else |
334 |
metadataKeyHeaderPrefix = @"X-Object-Meta-"; |
335 |
for (NSString *metadataKey in object.metadata) { |
336 |
NSString *metadataKeyHeader = [NSString stringWithFormat:@"%@%@", metadataKeyHeaderPrefix, metadataKey]; |
337 |
metadataKeyHeader = [NSString encodeToPercentEscape:metadataKeyHeader]; |
338 |
NSString *metadataValue = [NSString encodeToPercentEscape:[object.metadata objectForKey:metadataKey]]; |
339 |
[request.requestHeaders setObject:metadataValue forKey:metadataKeyHeader]; |
340 |
} |
341 |
|
342 |
[request setPostBody:[NSMutableData dataWithData:object.data]]; |
343 |
[request.requestHeaders setObject:object.contentType forKey:@"Content-Type"]; |
344 |
return request; |
345 |
} |
346 |
|
347 |
+ (id)writeObjectMetadataRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
348 |
NSString *objectFullPath = object.fullPath; |
349 |
if ([objectFullPath hasPrefix:@"/"]) |
350 |
objectFullPath = [objectFullPath substringFromIndex:1]; |
351 |
OpenStackRequest *request = [self filesRequest:account method:@"POST" path:[NSString stringWithFormat:@"/%@/%@", [NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:objectFullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]]; |
352 |
|
353 |
NSString *metadataKeyHeaderPrefix; |
354 |
if ([objectFullPath length] == 0) |
355 |
metadataKeyHeaderPrefix = @"X-Container-Meta-"; |
356 |
else |
357 |
metadataKeyHeaderPrefix = @"X-Object-Meta-"; |
358 |
for (NSString *metadataKey in object.metadata) { |
359 |
NSString *metadataKeyHeader = [NSString stringWithFormat:@"%@%@", metadataKeyHeaderPrefix, metadataKey]; |
360 |
metadataKeyHeader = [NSString encodeToPercentEscape:metadataKeyHeader]; |
361 |
NSString *metadataValue = [NSString encodeToPercentEscape:[object.metadata objectForKey:metadataKey]]; |
362 |
[request.requestHeaders setObject:metadataValue forKey:metadataKeyHeader]; |
363 |
} |
364 |
|
365 |
if (!account.sharingAccount) { |
366 |
[request.requestHeaders setObject:([object.publicURI length] ? @"true" : @"false") forKey:@"X-Object-Public"]; |
367 |
if (object.sharing) { |
368 |
[request.requestHeaders setObject:[NSString encodeToPercentEscape:object.sharing] forKey:@"X-Object-Sharing"]; |
369 |
} |
370 |
} |
371 |
return request; |
372 |
} |
373 |
|
374 |
+ (id)deleteObjectRequest:(OpenStackAccount *)account container:(Container *)container object:(StorageObject *)object { |
375 |
NSString *objectFullPath = object.fullPath; |
376 |
if ([objectFullPath hasPrefix:@"/"]) |
377 |
objectFullPath = [objectFullPath substringFromIndex:1]; |
378 |
return [self filesRequest:account method:@"DELETE" path:[NSString stringWithFormat:@"/%@/%@", [NSString encodeToPercentEscape:container.name], [NSString encodeToPercentEscape:objectFullPath charactersToEncode:@"!*'();:@&=+$,?%#[]"]]]; |
379 |
} |
380 |
|
381 |
#pragma mark - ASIHTTPRequest Overrides |
382 |
|
383 |
- (void)setCompletionBlock:(ASIBasicBlock)aCompletionBlock { |
384 |
[super setCompletionBlock:aCompletionBlock]; |
385 |
[backupCompletionBlock release]; |
386 |
backupCompletionBlock = [aCompletionBlock copy]; |
387 |
} |
388 |
|
389 |
- (void)setFailedBlock:(ASIBasicBlock)aFailedBlock { |
390 |
[super setFailedBlock:aFailedBlock]; |
391 |
[backupFailureBlock release]; |
392 |
backupFailureBlock = [aFailedBlock copy]; |
393 |
} |
394 |
|
395 |
- (void)failWithError:(NSError *)theError { |
396 |
if (responseStatusCode == 503) { |
397 |
NSNotification *notification = [NSNotification notificationWithName:@"serviceUnavailable" object:nil userInfo:nil]; |
398 |
[[NSNotificationCenter defaultCenter] postNotification:notification]; |
399 |
// This crashes the app, check if it can be removed completely. |
400 |
// } else if (responseStatusCode == 0) { |
401 |
// NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; |
402 |
// if (![defaults boolForKey:@"already_failed_on_connection"]) { |
403 |
// UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Connection Error" message:@"Please check your connection or API URL and try again." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; |
404 |
// [alert show]; |
405 |
// [alert release]; |
406 |
// } |
407 |
// [defaults setBool:YES forKey:@"already_failed_on_connection"]; |
408 |
// [defaults synchronize]; |
409 |
} |
410 |
|
411 |
[super failWithError:theError]; |
412 |
} |
413 |
|
414 |
#pragma mark - Actions |
415 |
|
416 |
- (BOOL)isSuccess { |
417 |
return (200 <= [self responseStatusCode]) && ([self responseStatusCode] <= 299); |
418 |
} |
419 |
|
420 |
#pragma mark - Notifications |
421 |
|
422 |
- (void)notify:(NSString *)name { |
423 |
NSDictionary *callbackUserInfo = [NSDictionary dictionaryWithObject:self forKey:@"response"]; |
424 |
NSNotification *notification = [NSNotification notificationWithName:name object:nil userInfo:callbackUserInfo]; |
425 |
[[NSNotificationCenter defaultCenter] postNotification:notification]; |
426 |
} |
427 |
|
428 |
- (void)notify { |
429 |
NSString *observeName = [NSString stringWithFormat:@"%@ %@ %@", [self isSuccess] ? @"SUCCESS" : @"FAILURE", self.requestMethod, (self.notificationURL ? self.notificationURL.description : self.url.description)]; |
430 |
NSString *callbackName = [NSString stringWithFormat:@"%@ %@ %@ %@", [self isSuccess] ? @"SUCCESS" : @"FAILURE", self.requestMethod, (self.notificationURL ? self.notificationURL.description : self.url.description), self.callback.uuid]; |
431 |
|
432 |
NSDictionary *callbackUserInfo = [NSDictionary dictionaryWithObject:self forKey:@"response"]; |
433 |
|
434 |
NSNotification *observeNotification = [NSNotification notificationWithName:observeName object:nil userInfo:callbackUserInfo]; |
435 |
[[NSNotificationCenter defaultCenter] postNotification:observeNotification]; |
436 |
|
437 |
NSNotification *callbackNotification = [NSNotification notificationWithName:callbackName object:nil userInfo:callbackUserInfo]; |
438 |
[[NSNotificationCenter defaultCenter] postNotification:callbackNotification]; |
439 |
|
440 |
} |
441 |
|
442 |
#pragma mark - Memory Management |
443 |
|
444 |
- (void)releaseBackupBlocksOnMainThread { |
445 |
NSMutableArray *blocks = [NSMutableArray array]; |
446 |
if (backupCompletionBlock) { |
447 |
[blocks addObject:backupCompletionBlock]; |
448 |
[backupCompletionBlock release]; |
449 |
backupCompletionBlock = nil; |
450 |
} |
451 |
if (backupFailureBlock) { |
452 |
[blocks addObject:backupFailureBlock]; |
453 |
[backupFailureBlock release]; |
454 |
backupFailureBlock = nil; |
455 |
} |
456 |
[[self class] performSelectorOnMainThread:@selector(releaseBackupBlocks:) withObject:blocks waitUntilDone:[NSThread isMainThread]]; |
457 |
} |
458 |
|
459 |
// Always called on main thread |
460 |
+ (void)releaseBackupBlocks:(NSArray *)blocks { |
461 |
// Blocks will be released when this method exits |
462 |
} |
463 |
|
464 |
- (void)dealloc { |
465 |
[account release]; |
466 |
[errorAlerter release]; |
467 |
[retryBaseURL release]; |
468 |
[followUpSelectorString release]; |
469 |
[notificationURL release]; |
470 |
[self releaseBackupBlocksOnMainThread]; |
471 |
[super dealloc]; |
472 |
} |
473 |
|
474 |
@end |