mirror of
https://github.com/danog/Telegram.git
synced 2024-12-02 09:27:55 +01:00
277 lines
8.5 KiB
Objective-C
277 lines
8.5 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 "TGDatacenterWatchdogActor.h"
|
|
|
|
#import "ActionStage.h"
|
|
|
|
#import <MTProtoKit/MTContext.h>
|
|
#import <MTProtoKit/MTProto.h>
|
|
#import <MTProtoKit/MTTimer.h>
|
|
#import <MTProtoKit/MTRequestMessageService.h>
|
|
#import <MTProtoKit/MTRequest.h>
|
|
#import <MTProtoKit/MTDatacenterAddressSet.h>
|
|
#import <MTProtoKit/MTDatacenterAddress.h>
|
|
|
|
#import "TGTelegramNetworking.h"
|
|
|
|
#import "TL/TLMetaScheme.h"
|
|
|
|
#import "TLDcOption$modernDcOption.h"
|
|
|
|
@interface TGDatacenterWatchdogActor ()
|
|
{
|
|
MTTimer *_startupTimer;
|
|
MTTimer *_addOneMoreDatacenterTimer;
|
|
|
|
NSMutableSet *_processedDatacenters;
|
|
|
|
id _mainMtProtoRequestId;
|
|
|
|
MTProto *_currentMtProto;
|
|
MTRequestMessageService *_currentRequestService;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation TGDatacenterWatchdogActor
|
|
|
|
+ (void)load
|
|
{
|
|
[ASActor registerActorClass:self];
|
|
}
|
|
|
|
+ (NSString *)genericPath
|
|
{
|
|
return @"/tg/datacenterWatchdog";
|
|
}
|
|
|
|
- (instancetype)initWithPath:(NSString *)path
|
|
{
|
|
self = [super initWithPath:path];
|
|
if (self != nil)
|
|
{
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[_startupTimer invalidate];
|
|
_startupTimer = nil;
|
|
|
|
[_addOneMoreDatacenterTimer invalidate];
|
|
_addOneMoreDatacenterTimer = nil;
|
|
|
|
[_currentMtProto removeMessageService:_currentRequestService];
|
|
[_currentMtProto stop];
|
|
}
|
|
|
|
- (void)execute:(NSDictionary *)__unused options
|
|
{
|
|
__weak TGDatacenterWatchdogActor *weakSelf = self;
|
|
_startupTimer = [[MTTimer alloc] initWithTimeout:8.0 repeat:false completion:^
|
|
{
|
|
__strong TGDatacenterWatchdogActor *strongSelf = weakSelf;
|
|
[strongSelf begin];
|
|
} queue:[ActionStageInstance() globalStageDispatchQueue]];
|
|
[_startupTimer start];
|
|
}
|
|
|
|
- (void)begin
|
|
{
|
|
MTContext *context = [[TGTelegramNetworking instance] context];
|
|
if (context == nil)
|
|
[ActionStageInstance() actionFailed:self.path reason:-1];
|
|
else
|
|
{
|
|
[self tryMainMtProto];
|
|
}
|
|
}
|
|
|
|
- (void)tryMainMtProto
|
|
{
|
|
MTRequest *request = [[MTRequest alloc] init];
|
|
request.dependsOnPasswordEntry = false;
|
|
request.body = [[TLRPChelp_getConfig$help_getConfig alloc] init];
|
|
|
|
__weak TGDatacenterWatchdogActor *weakSelf = self;
|
|
[request setCompleted:^(TLConfig *result, __unused NSTimeInterval timestamp, id error)
|
|
{
|
|
[ActionStageInstance() dispatchOnStageQueue:^
|
|
{
|
|
__strong TGDatacenterWatchdogActor *strongSelf = weakSelf;
|
|
if (error == nil)
|
|
{
|
|
[strongSelf processConfig:result fromDatacenterId:[[TGTelegramNetworking instance] masterDatacenterId]];
|
|
}
|
|
}];
|
|
}];
|
|
|
|
_addOneMoreDatacenterTimer = [[MTTimer alloc] initWithTimeout:10.0 repeat:true completion:^
|
|
{
|
|
__strong TGDatacenterWatchdogActor *strongSelf = weakSelf;
|
|
[strongSelf switchToNextDatacenter];
|
|
} queue:[ActionStageInstance() globalStageDispatchQueue]];
|
|
[_addOneMoreDatacenterTimer start];
|
|
|
|
_mainMtProtoRequestId = request.internalId;
|
|
[[TGTelegramNetworking instance] addRequest:request];
|
|
}
|
|
|
|
- (void)switchToNextDatacenter
|
|
{
|
|
MTContext *context = [[TGTelegramNetworking instance] context];
|
|
|
|
[_currentMtProto removeMessageService:_currentRequestService];
|
|
[_currentMtProto stop];
|
|
_currentMtProto = nil;
|
|
_currentRequestService = nil;
|
|
|
|
if (_mainMtProtoRequestId != nil)
|
|
{
|
|
[[TGTelegramNetworking instance] cancelRpc:_mainMtProtoRequestId];
|
|
_mainMtProtoRequestId = nil;
|
|
}
|
|
|
|
bool foundDatacenter = false;
|
|
NSInteger datacenterId = 0;
|
|
for (NSNumber *nDatacenterId in [context knownDatacenterIds])
|
|
{
|
|
if (![_processedDatacenters containsObject:nDatacenterId])
|
|
{
|
|
if (_processedDatacenters == nil)
|
|
_processedDatacenters = [[NSMutableSet alloc] init];
|
|
[_processedDatacenters addObject:nDatacenterId];
|
|
|
|
foundDatacenter = true;
|
|
datacenterId = [nDatacenterId integerValue];
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!foundDatacenter)
|
|
{
|
|
[_processedDatacenters removeAllObjects];
|
|
|
|
NSNumber *nDatacenterId = [context knownDatacenterIds].firstObject;
|
|
if (nDatacenterId != nil)
|
|
{
|
|
[_processedDatacenters addObject:nDatacenterId];
|
|
foundDatacenter = true;
|
|
datacenterId = [nDatacenterId integerValue];
|
|
}
|
|
}
|
|
|
|
if (foundDatacenter)
|
|
[self requestNetworkConfigFromDatacenter:datacenterId];
|
|
}
|
|
|
|
- (void)requestNetworkConfigFromDatacenter:(NSInteger)datacenterId
|
|
{
|
|
TGLog(@"[TGDatacenterWatchdogActor#%p requesting network config from %d]", self, (int)datacenterId);
|
|
|
|
MTContext *context = [[TGTelegramNetworking instance] context];
|
|
|
|
MTProto *mtProto = [[MTProto alloc] initWithContext:context datacenterId:datacenterId];
|
|
MTRequestMessageService *requestService = [[MTRequestMessageService alloc] initWithContext:context];
|
|
[mtProto addMessageService:requestService];
|
|
|
|
_currentMtProto = mtProto;
|
|
_currentRequestService = requestService;
|
|
|
|
MTRequest *request = [[MTRequest alloc] init];
|
|
request.dependsOnPasswordEntry = false;
|
|
request.body = [[TLRPChelp_getConfig$help_getConfig alloc] init];
|
|
|
|
__weak TGDatacenterWatchdogActor *weakSelf = self;
|
|
[request setCompleted:^(TLConfig *result, __unused NSTimeInterval timestamp, id error)
|
|
{
|
|
[ActionStageInstance() dispatchOnStageQueue:^
|
|
{
|
|
__strong TGDatacenterWatchdogActor *strongSelf = weakSelf;
|
|
if (error == nil)
|
|
{
|
|
[strongSelf processConfig:result fromDatacenterId:datacenterId];
|
|
}
|
|
}];
|
|
}];
|
|
|
|
[requestService addRequest:request];
|
|
}
|
|
|
|
- (void)processConfig:(TLConfig *)config fromDatacenterId:(NSInteger)__unused datacenterId
|
|
{
|
|
MTContext *context = [[TGTelegramNetworking instance] context];
|
|
|
|
[context performBatchUpdates:^
|
|
{
|
|
NSMutableDictionary *addressListByDatacenterId = [[NSMutableDictionary alloc] init];
|
|
|
|
for (TLDcOption$modernDcOption *dcOption in config.dc_options)
|
|
{
|
|
MTDatacenterAddress *configAddress = [[MTDatacenterAddress alloc] initWithIp:dcOption.ip_address port:(uint16_t)dcOption.port preferForMedia:dcOption.flags & (1 << 1) restrictToTcp:dcOption.flags & (1 << 2)];
|
|
|
|
NSMutableArray *array = addressListByDatacenterId[@(dcOption.n_id)];
|
|
if (array == nil)
|
|
{
|
|
array = [[NSMutableArray alloc] init];
|
|
addressListByDatacenterId[@(dcOption.n_id)] = array;
|
|
}
|
|
|
|
if (![array containsObject:configAddress])
|
|
[array addObject:configAddress];
|
|
}
|
|
|
|
[addressListByDatacenterId enumerateKeysAndObjectsUsingBlock:^(NSNumber *nDatacenterId, NSArray *addressList, __unused BOOL *stop)
|
|
{
|
|
MTDatacenterAddressSet *addressSet = [[MTDatacenterAddressSet alloc] initWithAddressList:addressList];
|
|
|
|
MTDatacenterAddressSet *currentAddressSet = [context addressSetForDatacenterWithId:[nDatacenterId integerValue]];
|
|
|
|
if (currentAddressSet == nil || ![addressSet isEqual:currentAddressSet])
|
|
{
|
|
TGLog(@"[TGDatacenterWatchdogActor#%p updating datacenter %d address set to %@]", self, [nDatacenterId intValue], addressSet);
|
|
[context updateAddressSetForDatacenterWithId:[nDatacenterId integerValue] addressSet:addressSet];
|
|
}
|
|
}];
|
|
|
|
[ActionStageInstance() dispatchOnStageQueue:^
|
|
{
|
|
TGLog(@"[TGDatacenterWatchdogActor#%p processed %d datacenter addresses from datacenter %d]", self, (int)config.dc_options.count, (int)datacenterId);
|
|
|
|
[self _completed];
|
|
}];
|
|
}];
|
|
}
|
|
|
|
- (void)_completed
|
|
{
|
|
_mainMtProtoRequestId = nil;
|
|
|
|
NSTimeInterval nextCheckDelay = 60.0 * 60.0;
|
|
|
|
[_addOneMoreDatacenterTimer invalidate];
|
|
_addOneMoreDatacenterTimer = nil;
|
|
|
|
[_processedDatacenters removeAllObjects];
|
|
|
|
__weak TGDatacenterWatchdogActor *weakSelf = self;
|
|
|
|
[_startupTimer invalidate];
|
|
_startupTimer = [[MTTimer alloc] initWithTimeout:nextCheckDelay repeat:false completion:^
|
|
{
|
|
__strong TGDatacenterWatchdogActor *strongSelf = weakSelf;
|
|
[strongSelf begin];
|
|
} queue:[ActionStageInstance() globalStageDispatchQueue]];
|
|
[_startupTimer start];
|
|
}
|
|
|
|
@end
|