1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-03 09:57:46 +01:00
Telegram/thirdparty/GDFileManager/GDHTTPOperation.m
2015-10-01 19:19:52 +03:00

160 lines
6.0 KiB
Objective-C
Executable File

//
// GDParentOperation.m
// GDFileManagerExample
//
// Created by Graham Dennis on 4/07/13.
// Copyright (c) 2013 Graham Dennis. All rights reserved.
//
#import "GDHTTPOperation.h"
#import "AFJSONRequestOperation.h"
#import "GDHTTPClient.h"
#import "GDClientManager.h"
#import "GDAccessTokenClientCredential.h"
NSString * const GDHTTPStatusErrorDomain = @"GDHTTPStatusErrorDomain";
@interface GDHTTPOperation ()
@property (nonatomic) BOOL autoRefreshAccessToken;
@property (nonatomic) BOOL forceAccessTokenRefresh;
@property (nonatomic) NSUInteger numberOfRetryAttempts;
@property (nonatomic) NSUInteger maximumNumberOfRetryAttempts;
@end
@implementation GDHTTPOperation
- (id)initWithClient:(GDHTTPClient *)client urlRequest:(NSMutableURLRequest *)urlRequest
success:(void (^)(AFHTTPRequestOperation *, id))success failure:(void (^)(AFHTTPRequestOperation *operation, NSError *))failure
{
if ((self = [super init])) {
_client = client;
_urlRequest = urlRequest;
__block typeof(self) strongSelf = self;
dispatch_block_t cleanup = ^{[strongSelf finish]; strongSelf->_success = nil; strongSelf->_failure = nil; strongSelf->_shouldRetryAfterError = nil; strongSelf->_configureOperationBlock = nil; strongSelf = nil;};
_success = ^(AFHTTPRequestOperation *operation, id responseObject){
dispatch_async(strongSelf.successCallbackQueue, ^{
if (success) success(operation, responseObject);
cleanup();
});
};
_failure = ^(AFHTTPRequestOperation *operation, NSError *error){
dispatch_async(strongSelf.failureCallbackQueue, ^{
if (failure) failure(operation, error);
cleanup();
});
};
self.requiresAuthentication = YES;
self.autoRefreshAccessToken = YES;
self.maximumNumberOfRetryAttempts = 5;
self.retryOnStandardErrors = YES;
}
return self;
}
- (id)init
{
return [self initWithClient:nil urlRequest:nil success:NULL failure:NULL];
}
- (void)main
{
if (![self isExecuting]) {
return self.failure(nil, GDOperationCancelledError);
}
GDHTTPClient *client = self.client;
if (self.requiresAuthentication) {
if (!self.forceAccessTokenRefresh && [self.client authorizeRequest:self.urlRequest]) {
// Request is now authorized
;
} else {
if ((self.forceAccessTokenRefresh || self.autoRefreshAccessToken) && [client.credential isKindOfClass:[GDAccessTokenClientCredential class]]) {
self.forceAccessTokenRefresh = NO;
GDAccessTokenClientCredential *oldCredential = (GDAccessTokenClientCredential *)client.credential;
[oldCredential getRenewedAccessTokenUsingClient:client
success:^(GDClientCredential *credential, BOOL isFreshFromRemote) {
[client.clientManager removeCredential:oldCredential];
[client.clientManager addCredential:credential];
client.credential = credential;
self.autoRefreshAccessToken = !isFreshFromRemote;
[self main];
} failure:^(NSError *error) {
self.failure(nil, error);
}];
} else {
self.failure(nil, nil);
}
return;
}
}
AFHTTPRequestOperation *operation = nil;
operation = [client HTTPRequestOperationWithRequest:self.urlRequest
success:self.success
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
id errorDetails = nil;
if ([operation isKindOfClass:[AFJSONRequestOperation class]]) {
errorDetails = [(AFJSONRequestOperation *)operation responseJSON];
}
NSError *httpError = [client httpErrorWithErrorDomain:GDHTTPStatusErrorDomain fromAFNetworkingError:error errorDetails:errorDetails];
error = httpError ?: error;
if ([client.credential canBeRenewed] && [client isAuthenticationFailureError:error]) {
self.forceAccessTokenRefresh = YES;
self.requiresAuthentication = YES;
[self main];
return;
} else if (!([[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled)
&& [self isRetryError:error]
&& self.numberOfRetryAttempts < self.maximumNumberOfRetryAttempts) {
double delayInSeconds = pow(2.0, self.numberOfRetryAttempts++) + arc4random_uniform(500)/1000.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
[self main];
});
return;
} else {
self.failure(operation, error);
}
}];
if (self.configureOperationBlock)
self.configureOperationBlock(operation);
[self addChildOperation:operation];
[client enqueueHTTPRequestOperation:operation];
}
- (BOOL)isRetryError:(NSError *)error
{
if (self.retryOnStandardErrors) {
if (!GDIsErrorPermanentlyFatal(error))
return YES;
}
if (self.shouldRetryAfterError) {
return self.shouldRetryAfterError(error);
}
return NO;
}
@end