Swiftgram/MTProtoKit/MTHttpWorker.m
2017-02-02 18:58:11 +03:00

250 lines
6.9 KiB
Objective-C

/*
* This is the source code of Telegram for iOS v. 1.1
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Peter Iakovlev, 2013.
*/
#import "MTHttpWorker.h"
#import "MTTimer.h"
#import "MTQueue.h"
#import "MTDatacenterAddress.h"
#import "MTInternalId.h"
MTInternalIdClass(MTHttpWorker)
@implementation MTHttpWorkerBlockDelegate
- (void)httpWorker:(MTHttpWorker *)__unused httpWorker completedWithData:(NSData *)data
{
if (_completedWithData)
_completedWithData(data);
}
- (void)httpWorkerConnected:(MTHttpWorker *)__unused httpWorker
{
if (_connected)
_connected();
}
- (void)httpWorkerFailed:(MTHttpWorker *)__unused httpWorker
{
if (_failed)
_failed();
}
@end
@interface MTHttpWorker ()
{
MTTimer *_timeoutTimer;
AFHTTPRequestOperation *_operation;
bool _notifiedDelegateAboutConnection;
bool _isConnected;
bool _stopped;
NSTimeInterval _timeout;
}
@end
@implementation MTHttpWorker
+ (MTQueue *)httpWorkerProcessingQueue
{
static MTQueue *queue = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
queue = [[MTQueue alloc] initWithName:"org.mtproto.httpWorkerProcessingQueue"];
});
return queue;
}
- (instancetype)initWithDelegate:(id<MTHttpWorkerDelegate>)delegate address:(MTDatacenterAddress *)address payloadData:(NSData *)payloadData performsLongPolling:(bool)performsLongPolling
{
int32_t randomId = 0;
arc4random_buf(&randomId, 4);
/*#ifdef DEBUG
if (![address isIpv6]) {
address = [[MTDatacenterAddress alloc] initWithIp:@"127.0.0.1" port:443 preferForMedia:address.preferForMedia restrictToTcp:address.restrictToTcp];
}
#endif*/
NSString *urlString = [[NSString alloc] initWithFormat:@"http://%@:%d/api%" PRIx32 "", address.ip, (int)address.port, randomId];
self = [super initWithBaseURL:[[NSURL alloc] initWithString:urlString]];
if (self != nil)
{
_internalId = [[MTInternalId(MTHttpWorker) alloc] init];
_delegate = delegate;
_performsLongPolling = performsLongPolling;
[[MTHttpWorker httpWorkerProcessingQueue] dispatchOnQueue:^
{
__weak MTHttpWorker *weakSelf = self;
_timeout = performsLongPolling ? 40 : 12;
_timeoutTimer = [[MTTimer alloc] initWithTimeout:_timeout repeat:false completion:^
{
MTHttpWorker *strongSelf = weakSelf;
[strongSelf requestTimeout];
} queue:[MTHttpWorker httpWorkerProcessingQueue].nativeQueue];
[_timeoutTimer start];
NSMutableURLRequest *urlRequest = [self requestWithMethod:@"POST" path:urlString parameters:nil];
[urlRequest setHTTPBody:payloadData];
_operation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
[_operation setSuccessCallbackQueue:[MTHttpWorker httpWorkerProcessingQueue].nativeQueue];
[_operation setFailureCallbackQueue:[MTHttpWorker httpWorkerProcessingQueue].nativeQueue];
[_operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, __unused id responseObject)
{
MTHttpWorker *strongSelf = weakSelf;
[strongSelf requestCompleted:[operation responseData] error:nil];
} failure:^(__unused AFHTTPRequestOperation *operation, NSError *error)
{
MTHttpWorker *strongSelf = weakSelf;
[strongSelf requestCompleted:nil error:error];
}];
[_operation setUploadProgressBlock:^(__unused NSInteger bytesWritten, __unused NSInteger totalBytesWritten, __unused NSInteger totalBytesExpectedToWrite)
{
MTHttpWorker *strongSelf = weakSelf;
[strongSelf requestUploadProgress];
}];
/*if (request.progressBlock != nil)
{
[httpOperation setDownloadProgressBlock:^(__unused NSInteger bytesRead, NSInteger totalBytesRead, NSInteger totalBytesExpectedToRead)
{
if (totalBytesExpectedToRead > 0 && totalBytesRead > 0)
{
request.progressBlock(((float)totalBytesRead) / ((float)totalBytesExpectedToRead));
}
}];
}*/
[self enqueueHTTPRequestOperation:_operation];
}];
}
return self;
}
- (void)dealloc
{
[self stop];
}
- (bool)isConnected
{
return _isConnected;
}
- (void)stop
{
_stopped = true;
AFHTTPRequestOperation *operation = _operation;
_operation = nil;
[[MTHttpWorker httpWorkerProcessingQueue] dispatchOnQueue:^
{
[operation cancel];
}];
[self cancelTimer];
}
- (void)terminateWithFailure
{
[[MTHttpWorker httpWorkerProcessingQueue] dispatchOnQueue:^
{
[self stop];
id<MTHttpWorkerDelegate> delegate = _delegate;
if ([delegate respondsToSelector:@selector(httpWorkerFailed:)])
[delegate httpWorkerFailed:self];
}];
}
- (void)cancelTimer
{
if (_timeoutTimer != nil)
{
MTTimer *timeoutTimer = _timeoutTimer;
_timeoutTimer = nil;
[[MTHttpWorker httpWorkerProcessingQueue] dispatchOnQueue:^
{
[timeoutTimer invalidate];
}];
}
}
- (void)requestUploadProgress
{
[[MTHttpWorker httpWorkerProcessingQueue] dispatchOnQueue:^
{
_isConnected = true;
if (!_notifiedDelegateAboutConnection)
{
_notifiedDelegateAboutConnection = true;
id<MTHttpWorkerDelegate> delegate = _delegate;
if ([delegate respondsToSelector:@selector(httpWorkerConnected:)])
[delegate httpWorkerConnected:self];
}
[_timeoutTimer resetTimeout:_timeout];
}];
}
- (void)requestCompleted:(NSData *)response error:(NSError *)error
{
if (!_stopped)
{
id<MTHttpWorkerDelegate> delegate = _delegate;
if (error == nil && response != nil)
{
if ([delegate respondsToSelector:@selector(httpWorker:completedWithData:)])
[delegate httpWorker:self completedWithData:response];
}
else
{
if ([delegate respondsToSelector:@selector(httpWorkerFailed:)])
[delegate httpWorkerFailed:self];
}
}
[self cancelTimer];
_stopped = true;
_operation = nil;
}
- (void)requestTimeout
{
if (!_stopped)
{
[self stop];
id<MTHttpWorkerDelegate> delegate = _delegate;
if ([delegate respondsToSelector:@selector(httpWorkerFailed:)])
[delegate httpWorkerFailed:self];
}
[self cancelTimer];
_stopped = true;
_operation = nil;
}
@end