2017-02-24 17:15:41 +00:00
/*
This file is part of Telegram Desktop ,
2018-01-03 10:23:14 +00:00
the official desktop application for the Telegram messaging service .
2017-02-24 17:15:41 +00:00
2018-01-03 10:23:14 +00:00
For license and copyright information please follow this link :
https : //github.com/telegramdesktop/tdesktop/blob/master/LEGAL
2017-02-24 17:15:41 +00:00
*/
# include "mtproto/mtp_instance.h"
2017-12-18 12:40:15 +00:00
# include "mtproto/session.h"
2017-02-24 17:15:41 +00:00
# include "mtproto/dc_options.h"
2017-06-26 17:38:16 +00:00
# include "mtproto/dcenter.h"
# include "mtproto/config_loader.h"
2018-05-17 19:58:00 +00:00
# include "mtproto/special_config_request.h"
2017-06-26 17:38:16 +00:00
# include "mtproto/connection.h"
# include "mtproto/sender.h"
# include "mtproto/rsa_public_key.h"
2017-03-04 10:23:56 +00:00
# include "storage/localstorage.h"
2018-09-12 17:02:30 +00:00
# include "calls/calls_instance.h"
2017-02-24 17:15:41 +00:00
# include "auth_session.h"
2018-05-11 14:03:53 +00:00
# include "application.h"
2017-04-13 17:59:05 +00:00
# include "apiwrap.h"
2017-02-24 17:15:41 +00:00
# include "messenger.h"
2017-04-13 17:59:05 +00:00
# include "lang/lang_instance.h"
2017-05-30 09:31:32 +00:00
# include "lang/lang_cloud_manager.h"
2017-04-13 17:59:05 +00:00
# include "base/timer.h"
2017-02-24 17:15:41 +00:00
namespace MTP {
2018-04-24 07:21:19 +00:00
namespace {
constexpr auto kConfigBecomesOldIn = 2 * 60 * TimeMs ( 1000 ) ;
2018-05-02 19:52:57 +00:00
constexpr auto kConfigBecomesOldForBlockedIn = 8 * TimeMs ( 1000 ) ;
2018-04-24 07:21:19 +00:00
} // namespace
2017-02-24 17:15:41 +00:00
2017-04-18 15:21:03 +00:00
class Instance : : Private : private Sender {
2017-02-24 17:15:41 +00:00
public :
2017-08-17 08:31:24 +00:00
Private ( not_null < Instance * > instance , not_null < DcOptions * > options , Instance : : Mode mode ) ;
2017-02-24 17:15:41 +00:00
void start ( Config & & config ) ;
2018-05-17 19:58:00 +00:00
void resolveProxyDomain ( const QString & host ) ;
void setGoodProxyDomain ( const QString & host , const QString & ip ) ;
2017-02-24 17:15:41 +00:00
void suggestMainDcId ( DcId mainDcId ) ;
void setMainDcId ( DcId mainDcId ) ;
DcId mainDcId ( ) const ;
void setKeyForWrite ( DcId dcId , const AuthKeyPtr & key ) ;
2017-02-25 16:44:02 +00:00
AuthKeysList getKeysForWrite ( ) const ;
void addKeysForDestroy ( AuthKeysList & & keys ) ;
2017-02-24 17:15:41 +00:00
2017-08-17 08:31:24 +00:00
not_null < DcOptions * > dcOptions ( ) ;
2017-02-24 17:15:41 +00:00
2017-04-13 17:59:05 +00:00
void requestConfig ( ) ;
2018-04-24 07:21:19 +00:00
void requestConfigIfOld ( ) ;
2017-04-13 17:59:05 +00:00
void requestCDNConfig ( ) ;
2018-05-02 19:27:03 +00:00
void setUserPhone ( const QString & phone ) ;
2018-05-24 13:40:19 +00:00
void badConfigurationError ( ) ;
2017-02-24 17:15:41 +00:00
void restart ( ) ;
void restart ( ShiftedDcId shiftedDcId ) ;
int32 dcstate ( ShiftedDcId shiftedDcId = 0 ) ;
QString dctransport ( ShiftedDcId shiftedDcId = 0 ) ;
void ping ( ) ;
void cancel ( mtpRequestId requestId ) ;
int32 state ( mtpRequestId requestId ) ; // < 0 means waiting for such count of ms
void killSession ( ShiftedDcId shiftedDcId ) ;
2017-02-25 16:44:02 +00:00
void killSession ( std : : unique_ptr < internal : : Session > session ) ;
2017-02-24 17:15:41 +00:00
void stopSession ( ShiftedDcId shiftedDcId ) ;
2017-04-18 15:21:03 +00:00
void reInitConnection ( DcId dcId ) ;
2017-02-24 17:15:41 +00:00
void logout ( RPCDoneHandlerPtr onDone , RPCFailHandlerPtr onFail ) ;
2017-06-26 17:38:16 +00:00
std : : shared_ptr < internal : : Dcenter > getDcById ( ShiftedDcId shiftedDcId ) ;
2017-02-24 17:15:41 +00:00
void unpaused ( ) ;
2017-12-18 12:40:15 +00:00
void queueQuittingConnection (
std : : unique_ptr < internal : : Connection > & & connection ) ;
2017-02-24 17:15:41 +00:00
void connectionFinished ( internal : : Connection * connection ) ;
2018-06-02 14:29:21 +00:00
void sendRequest (
mtpRequestId requestId ,
2018-06-25 18:55:27 +00:00
SecureRequest & & request ,
2018-06-02 14:29:21 +00:00
RPCResponseHandler & & callbacks ,
ShiftedDcId shiftedDcId ,
TimeMs msCanWait ,
bool needsLayer ,
mtpRequestId afterRequestId ) ;
void registerRequest ( mtpRequestId requestId , ShiftedDcId shiftedDcId ) ;
2017-02-24 17:15:41 +00:00
void unregisterRequest ( mtpRequestId requestId ) ;
2018-06-02 14:29:21 +00:00
void storeRequest (
mtpRequestId requestId ,
2018-06-25 18:55:27 +00:00
const SecureRequest & request ,
2017-12-18 12:40:15 +00:00
RPCResponseHandler & & callbacks ) ;
2018-06-25 18:55:27 +00:00
SecureRequest getRequest ( mtpRequestId requestId ) ;
2018-01-02 13:44:12 +00:00
void clearCallbacksDelayed ( std : : vector < RPCCallbackClear > & & ids ) ;
2017-02-24 17:15:41 +00:00
void execCallback ( mtpRequestId requestId , const mtpPrime * from , const mtpPrime * end ) ;
bool hasCallbacks ( mtpRequestId requestId ) ;
void globalCallback ( const mtpPrime * from , const mtpPrime * end ) ;
2018-06-02 14:29:21 +00:00
void onStateChange ( ShiftedDcId shiftedDcId , int32 state ) ;
void onSessionReset ( ShiftedDcId shiftedDcId ) ;
2017-02-24 17:15:41 +00:00
// return true if need to clean request data
bool rpcErrorOccured ( mtpRequestId requestId , const RPCFailHandlerPtr & onFail , const RPCError & err ) ;
inline bool rpcErrorOccured ( mtpRequestId requestId , const RPCResponseHandler & handler , const RPCError & err ) {
return rpcErrorOccured ( requestId , handler . onFail , err ) ;
}
void setUpdatesHandler ( RPCDoneHandlerPtr onDone ) ;
void setGlobalFailHandler ( RPCFailHandlerPtr onFail ) ;
2018-06-04 15:35:11 +00:00
void setStateChangedHandler ( Fn < void ( ShiftedDcId shiftedDcId , int32 state ) > handler ) ;
void setSessionResetHandler ( Fn < void ( ShiftedDcId shiftedDcId ) > handler ) ;
2017-02-24 17:15:41 +00:00
void clearGlobalHandlers ( ) ;
2018-06-02 14:29:21 +00:00
not_null < internal : : Session * > getSession ( ShiftedDcId shiftedDcId ) ;
2017-02-24 17:15:41 +00:00
2017-06-26 17:38:16 +00:00
bool isNormal ( ) const {
return ( _mode = = Instance : : Mode : : Normal ) ;
}
2017-02-25 16:44:02 +00:00
bool isKeysDestroyer ( ) const {
return ( _mode = = Instance : : Mode : : KeysDestroyer ) ;
}
2017-06-26 17:38:16 +00:00
bool isSpecialConfigRequester ( ) const {
return ( _mode = = Instance : : Mode : : SpecialConfigRequester ) ;
}
2017-02-25 16:44:02 +00:00
void scheduleKeyDestroy ( ShiftedDcId shiftedDcId ) ;
void performKeyDestroy ( ShiftedDcId shiftedDcId ) ;
void completedKeyDestroy ( ShiftedDcId shiftedDcId ) ;
void clearKilledSessions ( ) ;
2017-02-25 17:55:11 +00:00
void prepareToDestroy ( ) ;
2017-02-24 17:15:41 +00:00
private :
bool hasAuthorization ( ) ;
void importDone ( const MTPauth_Authorization & result , mtpRequestId requestId ) ;
bool importFail ( const RPCError & error , mtpRequestId requestId ) ;
void exportDone ( const MTPauth_ExportedAuthorization & result , mtpRequestId requestId ) ;
bool exportFail ( const RPCError & error , mtpRequestId requestId ) ;
bool onErrorDefault ( mtpRequestId requestId , const RPCError & error ) ;
2018-05-17 19:58:00 +00:00
void applyDomainIps (
const QString & host ,
const QStringList & ips ,
TimeMs expireAt ) ;
2017-12-18 12:40:15 +00:00
void logoutGuestDcs ( ) ;
2017-02-24 17:15:41 +00:00
bool logoutGuestDone ( mtpRequestId requestId ) ;
2018-05-02 19:52:57 +00:00
void requestConfigIfExpired ( ) ;
2017-02-24 17:15:41 +00:00
void configLoadDone ( const MTPConfig & result ) ;
bool configLoadFail ( const RPCError & error ) ;
2018-09-21 16:28:46 +00:00
std : : optional < ShiftedDcId > queryRequestByDc (
2018-04-27 13:08:12 +00:00
mtpRequestId requestId ) const ;
2018-09-21 16:28:46 +00:00
std : : optional < ShiftedDcId > changeRequestByDc (
2018-04-27 13:08:12 +00:00
mtpRequestId requestId , DcId newdc ) ;
2017-03-23 16:11:35 +00:00
2018-01-02 13:44:12 +00:00
// RPCError::NoError means do not toggle onError callback.
void clearCallbacks (
mtpRequestId requestId ,
int32 errorCode = RPCError : : NoError ) ;
void clearCallbacks ( const std : : vector < RPCCallbackClear > & ids ) ;
2017-02-24 17:15:41 +00:00
void checkDelayedRequests ( ) ;
2017-08-17 08:31:24 +00:00
not_null < Instance * > _instance ;
not_null < DcOptions * > _dcOptions ;
2017-02-25 16:44:02 +00:00
Instance : : Mode _mode = Instance : : Mode : : Normal ;
2017-02-24 17:15:41 +00:00
DcId _mainDcId = Config : : kDefaultMainDc ;
bool _mainDcIdForced = false ;
2017-06-26 17:38:16 +00:00
std : : map < DcId , std : : shared_ptr < internal : : Dcenter > > _dcenters ;
2017-02-24 17:15:41 +00:00
internal : : Session * _mainSession = nullptr ;
std : : map < ShiftedDcId , std : : unique_ptr < internal : : Session > > _sessions ;
2017-02-25 16:44:02 +00:00
std : : vector < std : : unique_ptr < internal : : Session > > _killedSessions ; // delayed delete
2017-02-24 17:15:41 +00:00
base : : set_of_unique_ptr < internal : : Connection > _quittingConnections ;
std : : unique_ptr < internal : : ConfigLoader > _configLoader ;
2018-05-17 19:58:00 +00:00
std : : unique_ptr < DomainResolver > _domainResolver ;
2018-05-02 19:27:03 +00:00
QString _userPhone ;
2017-03-23 16:11:35 +00:00
mtpRequestId _cdnConfigLoadRequestId = 0 ;
2018-04-24 07:21:19 +00:00
TimeMs _lastConfigLoadedTime = 0 ;
2018-05-02 19:52:57 +00:00
TimeMs _configExpiresAt = 0 ;
2017-02-24 17:15:41 +00:00
std : : map < DcId , AuthKeyPtr > _keysForWrite ;
mutable QReadWriteLock _keysForWriteLock ;
std : : map < ShiftedDcId , mtpRequestId > _logoutGuestRequestIds ;
// holds dcWithShift for request to this dc or -dc for request to main dc
std : : map < mtpRequestId , ShiftedDcId > _requestsByDc ;
2018-04-27 13:08:12 +00:00
mutable QMutex _requestByDcLock ;
2017-02-24 17:15:41 +00:00
// holds target dcWithShift for auth export request
std : : map < mtpRequestId , ShiftedDcId > _authExportRequests ;
std : : map < mtpRequestId , RPCResponseHandler > _parserMap ;
QMutex _parserMapLock ;
2018-06-25 18:55:27 +00:00
std : : map < mtpRequestId , SecureRequest > _requestMap ;
2017-02-24 17:15:41 +00:00
QReadWriteLock _requestMapLock ;
std : : deque < std : : pair < mtpRequestId , TimeMs > > _delayedRequests ;
std : : map < mtpRequestId , int > _requestsDelays ;
std : : set < mtpRequestId > _badGuestDcRequests ;
std : : map < DcId , std : : vector < mtpRequestId > > _authWaiters ;
RPCResponseHandler _globalHandler ;
2018-06-04 15:35:11 +00:00
Fn < void ( ShiftedDcId shiftedDcId , int32 state ) > _stateChangedHandler ;
Fn < void ( ShiftedDcId shiftedDcId ) > _sessionResetHandler ;
2017-02-24 17:15:41 +00:00
2017-04-13 17:59:05 +00:00
base : : Timer _checkDelayedTimer ;
2017-02-27 18:47:29 +00:00
// Debug flag to find out how we end up crashing.
bool MustNotCreateSessions = false ;
2017-02-24 17:15:41 +00:00
} ;
2018-05-17 19:58:00 +00:00
Instance : : Private : : Private (
not_null < Instance * > instance ,
not_null < DcOptions * > options ,
Instance : : Mode mode )
: Sender ( )
2017-06-26 17:38:16 +00:00
, _instance ( instance )
2017-02-25 16:44:02 +00:00
, _dcOptions ( options )
, _mode ( mode ) {
2017-02-24 17:15:41 +00:00
}
void Instance : : Private : : start ( Config & & config ) {
2017-02-25 16:44:02 +00:00
if ( isKeysDestroyer ( ) ) {
_instance - > connect ( _instance , SIGNAL ( keyDestroyed ( qint32 ) ) , _instance , SLOT ( onKeyDestroyed ( qint32 ) ) , Qt : : QueuedConnection ) ;
2017-06-26 17:38:16 +00:00
} else if ( isNormal ( ) ) {
2017-02-25 16:44:02 +00:00
unixtimeInit ( ) ;
}
2017-02-24 17:15:41 +00:00
2017-02-25 16:44:02 +00:00
for ( auto & key : config . keys ) {
auto dcId = key - > dcId ( ) ;
auto shiftedDcId = dcId ;
if ( isKeysDestroyer ( ) ) {
shiftedDcId = MTP : : destroyKeyNextDcId ( shiftedDcId ) ;
// There could be several keys for one dc if we're destroying them.
// Place them all in separate shiftedDcId so that they won't conflict.
while ( _keysForWrite . find ( shiftedDcId ) ! = _keysForWrite . cend ( ) ) {
shiftedDcId = MTP : : destroyKeyNextDcId ( shiftedDcId ) ;
}
}
_keysForWrite [ shiftedDcId ] = key ;
2017-02-24 17:15:41 +00:00
auto dc = std : : make_shared < internal : : Dcenter > ( _instance , dcId , std : : move ( key ) ) ;
2017-02-25 16:44:02 +00:00
_dcenters . emplace ( shiftedDcId , std : : move ( dc ) ) ;
2017-02-24 17:15:41 +00:00
}
if ( config . mainDcId ! = Config : : kNotSetMainDc ) {
_mainDcId = config . mainDcId ;
_mainDcIdForced = true ;
}
2017-02-25 16:44:02 +00:00
if ( isKeysDestroyer ( ) ) {
for ( auto & dc : _dcenters ) {
2017-08-17 09:06:26 +00:00
Assert ( ! MustNotCreateSessions ) ;
2017-02-25 16:44:02 +00:00
auto shiftedDcId = dc . first ;
auto session = std : : make_unique < internal : : Session > ( _instance , shiftedDcId ) ;
auto it = _sessions . emplace ( shiftedDcId , std : : move ( session ) ) . first ;
it - > second - > start ( ) ;
}
} else if ( _mainDcId ! = Config : : kNoneMainDc ) {
2017-08-17 09:06:26 +00:00
Assert ( ! MustNotCreateSessions ) ;
2017-02-24 17:15:41 +00:00
auto main = std : : make_unique < internal : : Session > ( _instance , _mainDcId ) ;
_mainSession = main . get ( ) ;
2017-02-25 16:44:02 +00:00
_sessions . emplace ( _mainDcId , std : : move ( main ) ) ;
_mainSession - > start ( ) ;
2017-02-24 17:15:41 +00:00
}
2017-04-13 17:59:05 +00:00
_checkDelayedTimer . setCallback ( [ this ] { checkDelayedRequests ( ) ; } ) ;
2017-02-24 17:15:41 +00:00
2017-08-17 09:06:26 +00:00
Assert ( ( _mainDcId = = Config : : kNoneMainDc ) = = isKeysDestroyer ( ) ) ;
2018-04-27 13:08:12 +00:00
requestConfig ( ) ;
2017-02-24 17:15:41 +00:00
}
2018-05-17 19:58:00 +00:00
void Instance : : Private : : resolveProxyDomain ( const QString & host ) {
if ( ! _domainResolver ) {
_domainResolver = std : : make_unique < DomainResolver > ( [ = ] (
const QString & host ,
const QStringList & ips ,
TimeMs expireAt ) {
applyDomainIps ( host , ips , expireAt ) ;
} ) ;
}
_domainResolver - > resolve ( host ) ;
}
void Instance : : Private : : applyDomainIps (
const QString & host ,
const QStringList & ips ,
TimeMs expireAt ) {
const auto applyToProxy = [ & ] ( ProxyData & proxy ) {
if ( ! proxy . tryCustomResolve ( ) | | proxy . host ! = host ) {
return false ;
}
proxy . resolvedExpireAt = expireAt ;
auto copy = ips ;
auto & current = proxy . resolvedIPs ;
const auto i = ranges : : remove_if ( current , [ & ] ( const QString & ip ) {
const auto index = copy . indexOf ( ip ) ;
if ( index < 0 ) {
return true ;
}
copy . removeAt ( index ) ;
return false ;
} ) ;
if ( i = = end ( current ) & & copy . isEmpty ( ) ) {
// Even if the proxy was changed already, we still want
// to refreshOptions in all sessions across all instances.
return true ;
}
current . erase ( i , end ( current ) ) ;
for ( const auto & ip : copy ) {
proxy . resolvedIPs . push_back ( ip ) ;
}
return true ;
} ;
for ( auto & proxy : Global : : RefProxiesList ( ) ) {
applyToProxy ( proxy ) ;
}
if ( applyToProxy ( Global : : RefSelectedProxy ( ) ) & & Global : : UseProxy ( ) ) {
for ( auto & session : _sessions ) {
session . second - > refreshOptions ( ) ;
}
}
emit _instance - > proxyDomainResolved ( host , ips , expireAt ) ;
}
void Instance : : Private : : setGoodProxyDomain (
const QString & host ,
const QString & ip ) {
const auto applyToProxy = [ & ] ( ProxyData & proxy ) {
if ( ! proxy . tryCustomResolve ( ) | | proxy . host ! = host ) {
return false ;
}
auto & current = proxy . resolvedIPs ;
auto i = ranges : : find ( current , ip ) ;
if ( i = = end ( current ) | | i = = begin ( current ) ) {
return false ;
}
while ( i ! = begin ( current ) ) {
const auto j = i - - ;
std : : swap ( * i , * j ) ;
}
return true ;
} ;
for ( auto & proxy : Global : : RefProxiesList ( ) ) {
applyToProxy ( proxy ) ;
}
if ( applyToProxy ( Global : : RefSelectedProxy ( ) ) & & Global : : UseProxy ( ) ) {
Sandbox : : refreshGlobalProxy ( ) ;
}
}
2017-02-24 17:15:41 +00:00
void Instance : : Private : : suggestMainDcId ( DcId mainDcId ) {
if ( _mainDcIdForced ) return ;
setMainDcId ( mainDcId ) ;
}
void Instance : : Private : : setMainDcId ( DcId mainDcId ) {
if ( ! _mainSession ) {
LOG ( ( " MTP Error: attempting to change mainDcId in an MTP instance without main session. " ) ) ;
return ;
}
_mainDcIdForced = true ;
auto oldMainDcId = _mainSession - > getDcWithShift ( ) ;
_mainDcId = mainDcId ;
if ( oldMainDcId ! = _mainDcId ) {
killSession ( oldMainDcId ) ;
}
Local : : writeMtpData ( ) ;
}
DcId Instance : : Private : : mainDcId ( ) const {
2017-04-13 17:59:05 +00:00
Expects ( _mainDcId ! = Config : : kNoneMainDc ) ;
2017-02-24 17:15:41 +00:00
return _mainDcId ;
}
2017-04-13 17:59:05 +00:00
void Instance : : Private : : requestConfig ( ) {
2018-04-27 13:08:12 +00:00
if ( _configLoader | | isKeysDestroyer ( ) ) {
2017-02-24 17:15:41 +00:00
return ;
}
2018-05-02 19:27:03 +00:00
_configLoader = std : : make_unique < internal : : ConfigLoader > (
_instance ,
_userPhone ,
rpcDone ( [ = ] ( const MTPConfig & result ) { configLoadDone ( result ) ; } ) ,
rpcFail ( [ = ] ( const RPCError & error ) { return configLoadFail ( error ) ; } ) ) ;
2017-02-24 17:15:41 +00:00
_configLoader - > load ( ) ;
}
2018-05-02 19:27:03 +00:00
void Instance : : Private : : setUserPhone ( const QString & phone ) {
if ( _userPhone ! = phone ) {
_userPhone = phone ;
if ( _configLoader ) {
_configLoader - > setPhone ( _userPhone ) ;
}
}
}
2018-05-24 13:40:19 +00:00
void Instance : : Private : : badConfigurationError ( ) {
if ( _mode = = Mode : : Normal ) {
Messenger : : Instance ( ) . badMtprotoConfigurationError ( ) ;
}
}
2018-04-24 07:21:19 +00:00
void Instance : : Private : : requestConfigIfOld ( ) {
2018-05-02 19:52:57 +00:00
const auto timeout = Global : : BlockedMode ( )
? kConfigBecomesOldForBlockedIn
: kConfigBecomesOldIn ;
if ( getms ( true ) - _lastConfigLoadedTime > = timeout ) {
requestConfig ( ) ;
}
}
void Instance : : Private : : requestConfigIfExpired ( ) {
const auto requestIn = ( _configExpiresAt - getms ( true ) ) ;
if ( requestIn > 0 ) {
App : : CallDelayed (
std : : min ( requestIn , 3600 * TimeMs ( 1000 ) ) ,
_instance ,
[ = ] { requestConfigIfExpired ( ) ; } ) ;
} else {
2018-04-24 07:21:19 +00:00
requestConfig ( ) ;
}
}
2017-04-13 17:59:05 +00:00
void Instance : : Private : : requestCDNConfig ( ) {
2017-03-23 16:11:35 +00:00
if ( _cdnConfigLoadRequestId | | _mainDcId = = Config : : kNoneMainDc ) {
return ;
}
2018-04-27 13:08:12 +00:00
_cdnConfigLoadRequestId = request (
MTPhelp_GetCdnConfig ( )
) . done ( [ this ] ( const MTPCdnConfig & result ) {
2017-03-23 16:11:35 +00:00
_cdnConfigLoadRequestId = 0 ;
Expects ( result . type ( ) = = mtpc_cdnConfig ) ;
dcOptions ( ) - > setCDNConfig ( result . c_cdnConfig ( ) ) ;
Local : : writeSettings ( ) ;
emit _instance - > cdnConfigLoaded ( ) ;
} ) . send ( ) ;
}
2017-02-24 17:15:41 +00:00
void Instance : : Private : : restart ( ) {
for ( auto & session : _sessions ) {
session . second - > restart ( ) ;
}
}
void Instance : : Private : : restart ( ShiftedDcId shiftedDcId ) {
2018-06-11 18:35:27 +00:00
auto dcId = BareDcId ( shiftedDcId ) ;
2017-02-24 17:15:41 +00:00
for ( auto & session : _sessions ) {
2018-06-11 18:35:27 +00:00
if ( BareDcId ( session . second - > getDcWithShift ( ) ) = = dcId ) {
2017-02-24 17:15:41 +00:00
session . second - > restart ( ) ;
}
}
}
int32 Instance : : Private : : dcstate ( ShiftedDcId shiftedDcId ) {
if ( ! shiftedDcId ) {
2017-08-17 09:06:26 +00:00
Assert ( _mainSession ! = nullptr ) ;
2017-02-24 17:15:41 +00:00
return _mainSession - > getState ( ) ;
}
2018-06-11 18:35:27 +00:00
if ( ! BareDcId ( shiftedDcId ) ) {
2017-08-17 09:06:26 +00:00
Assert ( _mainSession ! = nullptr ) ;
2018-06-11 18:35:27 +00:00
shiftedDcId + = BareDcId ( _mainSession - > getDcWithShift ( ) ) ;
2017-02-24 17:15:41 +00:00
}
auto it = _sessions . find ( shiftedDcId ) ;
2017-02-27 18:47:29 +00:00
if ( it ! = _sessions . cend ( ) ) {
return it - > second - > getState ( ) ;
}
2017-02-24 17:15:41 +00:00
return DisconnectedState ;
}
QString Instance : : Private : : dctransport ( ShiftedDcId shiftedDcId ) {
if ( ! shiftedDcId ) {
2017-08-17 09:06:26 +00:00
Assert ( _mainSession ! = nullptr ) ;
2017-02-24 17:15:41 +00:00
return _mainSession - > transport ( ) ;
}
2018-06-11 18:35:27 +00:00
if ( ! BareDcId ( shiftedDcId ) ) {
2017-08-17 09:06:26 +00:00
Assert ( _mainSession ! = nullptr ) ;
2018-06-11 18:35:27 +00:00
shiftedDcId + = BareDcId ( _mainSession - > getDcWithShift ( ) ) ;
2017-02-24 17:15:41 +00:00
}
auto it = _sessions . find ( shiftedDcId ) ;
if ( it ! = _sessions . cend ( ) ) {
return it - > second - > transport ( ) ;
}
return QString ( ) ;
}
void Instance : : Private : : ping ( ) {
2018-06-02 14:29:21 +00:00
getSession ( 0 ) - > ping ( ) ;
2017-02-24 17:15:41 +00:00
}
void Instance : : Private : : cancel ( mtpRequestId requestId ) {
if ( ! requestId ) return ;
2018-06-24 13:19:49 +00:00
DEBUG_LOG ( ( " MTP Info: Cancel request %1. " ) . arg ( requestId ) ) ;
2018-04-27 13:08:12 +00:00
const auto shiftedDcId = queryRequestByDc ( requestId ) ;
auto msgId = mtpMsgId ( 0 ) ;
2017-02-24 17:15:41 +00:00
{
QWriteLocker locker ( & _requestMapLock ) ;
auto it = _requestMap . find ( requestId ) ;
if ( it ! = _requestMap . end ( ) ) {
msgId = * ( mtpMsgId * ) ( it - > second - > constData ( ) + 4 ) ;
_requestMap . erase ( it ) ;
}
}
2018-04-27 13:08:12 +00:00
unregisterRequest ( requestId ) ;
if ( shiftedDcId ) {
2018-06-02 14:29:21 +00:00
const auto session = getSession ( qAbs ( * shiftedDcId ) ) ;
session - > cancel ( requestId , msgId ) ;
2017-02-24 17:15:41 +00:00
}
clearCallbacks ( requestId ) ;
}
2018-06-02 14:29:21 +00:00
// result < 0 means waiting for such count of ms.
int32 Instance : : Private : : state ( mtpRequestId requestId ) {
2017-02-24 17:15:41 +00:00
if ( requestId > 0 ) {
2018-04-27 13:08:12 +00:00
if ( const auto shiftedDcId = queryRequestByDc ( requestId ) ) {
2018-06-02 14:29:21 +00:00
const auto session = getSession ( qAbs ( * shiftedDcId ) ) ;
return session - > requestState ( requestId ) ;
2017-02-24 17:15:41 +00:00
}
return MTP : : RequestSent ;
}
2018-06-02 14:29:21 +00:00
const auto session = getSession ( - requestId ) ;
return session - > requestState ( 0 ) ;
2017-02-24 17:15:41 +00:00
}
void Instance : : Private : : killSession ( ShiftedDcId shiftedDcId ) {
2017-02-25 16:44:02 +00:00
auto checkIfMainAndKill = [ this ] ( ShiftedDcId shiftedDcId ) {
auto it = _sessions . find ( shiftedDcId ) ;
if ( it ! = _sessions . cend ( ) ) {
_killedSessions . push_back ( std : : move ( it - > second ) ) ;
_sessions . erase ( it ) ;
_killedSessions . back ( ) - > kill ( ) ;
return ( _killedSessions . back ( ) . get ( ) = = _mainSession ) ;
2017-02-24 17:15:41 +00:00
}
2017-02-25 16:44:02 +00:00
return false ;
} ;
if ( checkIfMainAndKill ( shiftedDcId ) ) {
checkIfMainAndKill ( _mainDcId ) ;
2017-08-17 09:06:26 +00:00
Assert ( ! MustNotCreateSessions ) ;
2017-02-25 16:44:02 +00:00
auto main = std : : make_unique < internal : : Session > ( _instance , _mainDcId ) ;
_mainSession = main . get ( ) ;
_sessions . emplace ( _mainDcId , std : : move ( main ) ) ;
_mainSession - > start ( ) ;
2017-02-24 17:15:41 +00:00
}
2017-04-18 15:21:03 +00:00
InvokeQueued ( _instance , [ this ] {
clearKilledSessions ( ) ;
} ) ;
2017-02-25 16:44:02 +00:00
}
void Instance : : Private : : clearKilledSessions ( ) {
_killedSessions . clear ( ) ;
2017-02-24 17:15:41 +00:00
}
void Instance : : Private : : stopSession ( ShiftedDcId shiftedDcId ) {
auto it = _sessions . find ( shiftedDcId ) ;
if ( it ! = _sessions . end ( ) ) {
if ( it - > second . get ( ) ! = _mainSession ) { // don't stop main session
it - > second - > stop ( ) ;
}
}
}
2017-04-18 15:21:03 +00:00
void Instance : : Private : : reInitConnection ( DcId dcId ) {
2018-05-17 19:58:00 +00:00
for ( auto & session : _sessions ) {
2018-06-11 18:35:27 +00:00
if ( BareDcId ( session . second - > getDcWithShift ( ) ) = = dcId ) {
2018-05-17 19:58:00 +00:00
session . second - > reInitConnection ( ) ;
}
}
2017-04-18 15:21:03 +00:00
}
2017-12-18 12:40:15 +00:00
void Instance : : Private : : logout (
RPCDoneHandlerPtr onDone ,
RPCFailHandlerPtr onFail ) {
_instance - > send ( MTPauth_LogOut ( ) , std : : move ( onDone ) , std : : move ( onFail ) ) ;
logoutGuestDcs ( ) ;
}
2017-02-24 17:15:41 +00:00
2017-12-18 12:40:15 +00:00
void Instance : : Private : : logoutGuestDcs ( ) {
2017-02-24 17:15:41 +00:00
auto dcIds = std : : vector < DcId > ( ) ;
{
QReadLocker lock ( & _keysForWriteLock ) ;
dcIds . reserve ( _keysForWrite . size ( ) ) ;
for ( auto & key : _keysForWrite ) {
dcIds . push_back ( key . first ) ;
}
}
for ( auto dcId : dcIds ) {
2017-03-23 16:11:35 +00:00
if ( dcId ! = mainDcId ( ) & & dcOptions ( ) - > dcType ( dcId ) ! = DcType : : Cdn ) {
2017-02-25 16:44:02 +00:00
auto shiftedDcId = MTP : : logoutDcId ( dcId ) ;
2017-02-24 17:15:41 +00:00
auto requestId = _instance - > send ( MTPauth_LogOut ( ) , rpcDone ( [ this ] ( mtpRequestId requestId ) {
logoutGuestDone ( requestId ) ;
} ) , rpcFail ( [ this ] ( mtpRequestId requestId ) {
return logoutGuestDone ( requestId ) ;
} ) , shiftedDcId ) ;
2017-02-25 16:44:02 +00:00
_logoutGuestRequestIds . emplace ( shiftedDcId , requestId ) ;
2017-02-24 17:15:41 +00:00
}
}
}
bool Instance : : Private : : logoutGuestDone ( mtpRequestId requestId ) {
for ( auto i = _logoutGuestRequestIds . begin ( ) , e = _logoutGuestRequestIds . end ( ) ; i ! = e ; + + i ) {
if ( i - > second = = requestId ) {
killSession ( i - > first ) ;
_logoutGuestRequestIds . erase ( i ) ;
return true ;
}
}
return false ;
}
2017-06-26 17:38:16 +00:00
std : : shared_ptr < internal : : Dcenter > Instance : : Private : : getDcById ( ShiftedDcId shiftedDcId ) {
2017-02-25 16:44:02 +00:00
auto it = _dcenters . find ( shiftedDcId ) ;
2017-02-24 17:15:41 +00:00
if ( it = = _dcenters . cend ( ) ) {
2018-06-11 18:35:27 +00:00
auto dcId = BareDcId ( shiftedDcId ) ;
2017-06-26 17:38:16 +00:00
if ( isTemporaryDcId ( dcId ) ) {
if ( auto realDcId = getRealIdFromTemporaryDcId ( dcId ) ) {
dcId = realDcId ;
}
}
2017-02-25 16:44:02 +00:00
it = _dcenters . find ( dcId ) ;
if ( it = = _dcenters . cend ( ) ) {
auto result = std : : make_shared < internal : : Dcenter > ( _instance , dcId , AuthKeyPtr ( ) ) ;
2017-06-26 17:38:16 +00:00
return _dcenters . emplace ( dcId , std : : move ( result ) ) . first - > second ;
2017-02-25 16:44:02 +00:00
}
2017-02-24 17:15:41 +00:00
}
return it - > second ;
}
void Instance : : Private : : setKeyForWrite ( DcId dcId , const AuthKeyPtr & key ) {
2017-06-26 17:38:16 +00:00
if ( isTemporaryDcId ( dcId ) ) {
return ;
}
2017-02-24 17:15:41 +00:00
QWriteLocker lock ( & _keysForWriteLock ) ;
if ( key ) {
_keysForWrite [ dcId ] = key ;
} else {
_keysForWrite . erase ( dcId ) ;
}
}
2017-02-25 16:44:02 +00:00
AuthKeysList Instance : : Private : : getKeysForWrite ( ) const {
auto result = AuthKeysList ( ) ;
2017-02-24 17:15:41 +00:00
QReadLocker lock ( & _keysForWriteLock ) ;
2017-02-25 16:44:02 +00:00
result . reserve ( _keysForWrite . size ( ) ) ;
2017-02-24 17:15:41 +00:00
for ( auto & key : _keysForWrite ) {
result . push_back ( key . second ) ;
}
return result ;
}
2017-02-25 16:44:02 +00:00
void Instance : : Private : : addKeysForDestroy ( AuthKeysList & & keys ) {
2017-06-26 17:38:16 +00:00
Expects ( isKeysDestroyer ( ) ) ;
2017-02-25 16:44:02 +00:00
for ( auto & key : keys ) {
auto dcId = key - > dcId ( ) ;
auto shiftedDcId = MTP : : destroyKeyNextDcId ( dcId ) ;
{
QWriteLocker lock ( & _keysForWriteLock ) ;
// There could be several keys for one dc if we're destroying them.
// Place them all in separate shiftedDcId so that they won't conflict.
while ( _keysForWrite . find ( shiftedDcId ) ! = _keysForWrite . cend ( ) ) {
shiftedDcId = MTP : : destroyKeyNextDcId ( shiftedDcId ) ;
}
_keysForWrite [ shiftedDcId ] = key ;
}
auto dc = std : : make_shared < internal : : Dcenter > ( _instance , dcId , std : : move ( key ) ) ;
_dcenters . emplace ( shiftedDcId , std : : move ( dc ) ) ;
2017-08-17 09:06:26 +00:00
Assert ( ! MustNotCreateSessions ) ;
2017-02-25 16:44:02 +00:00
auto session = std : : make_unique < internal : : Session > ( _instance , shiftedDcId ) ;
auto it = _sessions . emplace ( shiftedDcId , std : : move ( session ) ) . first ;
it - > second - > start ( ) ;
}
}
2017-08-17 08:31:24 +00:00
not_null < DcOptions * > Instance : : Private : : dcOptions ( ) {
2017-02-24 17:15:41 +00:00
return _dcOptions ;
}
void Instance : : Private : : unpaused ( ) {
for ( auto & session : _sessions ) {
session . second - > unpaused ( ) ;
}
}
2017-12-18 12:40:15 +00:00
void Instance : : Private : : queueQuittingConnection (
std : : unique_ptr < internal : : Connection > & & connection ) {
2017-02-24 17:15:41 +00:00
_quittingConnections . insert ( std : : move ( connection ) ) ;
}
void Instance : : Private : : connectionFinished ( internal : : Connection * connection ) {
auto it = _quittingConnections . find ( connection ) ;
if ( it ! = _quittingConnections . end ( ) ) {
_quittingConnections . erase ( it ) ;
}
}
void Instance : : Private : : configLoadDone ( const MTPConfig & result ) {
2017-06-26 17:38:16 +00:00
Expects ( result . type ( ) = = mtpc_config ) ;
2017-02-24 17:15:41 +00:00
_configLoader . reset ( ) ;
2018-04-24 07:21:19 +00:00
_lastConfigLoadedTime = getms ( true ) ;
2017-02-24 17:15:41 +00:00
2018-05-03 06:39:10 +00:00
const auto & data = result . c_config ( ) ;
2017-03-10 19:46:28 +00:00
DEBUG_LOG ( ( " MTP Info: got config, chat_size_max: %1, date: %2, test_mode: %3, this_dc: %4, dc_options.length: %5 " ) . arg ( data . vchat_size_max . v ) . arg ( data . vdate . v ) . arg ( mtpIsTrue ( data . vtest_mode ) ) . arg ( data . vthis_dc . v ) . arg ( data . vdc_options . v . size ( ) ) ) ;
if ( data . vdc_options . v . empty ( ) ) {
2017-02-24 17:15:41 +00:00
LOG ( ( " MTP Error: config with empty dc_options received! " ) ) ;
} else {
_dcOptions - > setFromList ( data . vdc_options ) ;
}
Global : : SetChatSizeMax ( data . vchat_size_max . v ) ;
Global : : SetMegagroupSizeMax ( data . vmegagroup_size_max . v ) ;
Global : : SetForwardedCountMax ( data . vforwarded_count_max . v ) ;
Global : : SetOnlineUpdatePeriod ( data . vonline_update_period_ms . v ) ;
Global : : SetOfflineBlurTimeout ( data . voffline_blur_timeout_ms . v ) ;
Global : : SetOfflineIdleTimeout ( data . voffline_idle_timeout_ms . v ) ;
Global : : SetOnlineCloudTimeout ( data . vonline_cloud_timeout_ms . v ) ;
Global : : SetNotifyCloudDelay ( data . vnotify_cloud_delay_ms . v ) ;
Global : : SetNotifyDefaultDelay ( data . vnotify_default_delay_ms . v ) ;
2017-04-28 17:16:14 +00:00
Global : : SetPushChatPeriod ( data . vpush_chat_period_ms . v ) ;
Global : : SetPushChatLimit ( data . vpush_chat_limit . v ) ;
2017-02-24 17:15:41 +00:00
Global : : SetSavedGifsLimit ( data . vsaved_gifs_limit . v ) ;
2017-04-28 17:16:14 +00:00
Global : : SetEditTimeLimit ( data . vedit_time_limit . v ) ;
2018-03-11 18:50:24 +00:00
Global : : SetRevokeTimeLimit ( data . vrevoke_time_limit . v ) ;
Global : : SetRevokePrivateTimeLimit ( data . vrevoke_pm_time_limit . v ) ;
Global : : SetRevokePrivateInbox ( data . is_revoke_pm_inbox ( ) ) ;
2017-02-24 17:15:41 +00:00
Global : : SetStickersRecentLimit ( data . vstickers_recent_limit . v ) ;
2017-08-02 15:07:28 +00:00
Global : : SetStickersFavedLimit ( data . vstickers_faved_limit . v ) ;
2017-02-24 17:15:41 +00:00
Global : : SetPinnedDialogsCountMax ( data . vpinned_dialogs_count_max . v ) ;
2017-03-10 17:25:43 +00:00
Messenger : : Instance ( ) . setInternalLinkDomain ( qs ( data . vme_url_prefix ) ) ;
2017-11-20 19:54:05 +00:00
Global : : SetChannelsReadMediaPeriod ( data . vchannels_read_media_period . v ) ;
2018-06-26 13:58:29 +00:00
Global : : SetWebFileDcId ( data . vwebfile_dc_id . v ) ;
Global : : SetTxtDomainString ( qs ( data . vdc_txt_domain_name ) ) ;
2017-04-28 17:16:14 +00:00
Global : : SetCallReceiveTimeoutMs ( data . vcall_receive_timeout_ms . v ) ;
Global : : SetCallRingTimeoutMs ( data . vcall_ring_timeout_ms . v ) ;
Global : : SetCallConnectTimeoutMs ( data . vcall_connect_timeout_ms . v ) ;
Global : : SetCallPacketTimeoutMs ( data . vcall_packet_timeout_ms . v ) ;
if ( Global : : PhoneCallsEnabled ( ) ! = data . is_phonecalls_enabled ( ) ) {
Global : : SetPhoneCallsEnabled ( data . is_phonecalls_enabled ( ) ) ;
Global : : RefPhoneCallsEnabledChanged ( ) . notify ( ) ;
}
2018-05-02 19:52:57 +00:00
Global : : SetBlockedMode ( data . is_blocked_mode ( ) ) ;
2018-05-03 06:39:10 +00:00
const auto lang = data . has_suggested_lang_code ( )
? qs ( data . vsuggested_lang_code )
: QString ( ) ;
Lang : : CurrentCloudManager ( ) . setSuggestedLanguage ( lang ) ;
2017-02-24 17:15:41 +00:00
2018-05-03 06:39:10 +00:00
if ( data . has_autoupdate_url_prefix ( ) ) {
Local : : writeAutoupdatePrefix ( qs ( data . vautoupdate_url_prefix ) ) ;
}
2017-02-24 17:15:41 +00:00
Local : : writeSettings ( ) ;
2018-05-02 19:52:57 +00:00
_configExpiresAt = getms ( true )
+ ( data . vexpires . v - unixtime ( ) ) * TimeMs ( 1000 ) ;
requestConfigIfExpired ( ) ;
2018-09-12 17:02:30 +00:00
if ( AuthSession : : Exists ( ) ) {
using PeerToPeer = Calls : : PeerToPeer ;
const auto current = Auth ( ) . settings ( ) . callsPeerToPeer ( ) ;
if ( current = = PeerToPeer : : DefaultContacts
| | current = = PeerToPeer : : DefaultEveryone ) {
Auth ( ) . settings ( ) . setCallsPeerToPeer (
( data . is_default_p2p_contacts ( )
? PeerToPeer : : DefaultContacts
: PeerToPeer : : DefaultEveryone ) ) ;
}
}
2017-02-24 17:15:41 +00:00
emit _instance - > configLoaded ( ) ;
}
bool Instance : : Private : : configLoadFail ( const RPCError & error ) {
if ( isDefaultHandledError ( error ) ) return false ;
// loadingConfig = false;
LOG ( ( " MTP Error: failed to get config! " ) ) ;
return false ;
}
2018-09-21 16:28:46 +00:00
std : : optional < ShiftedDcId > Instance : : Private : : queryRequestByDc (
2018-04-27 13:08:12 +00:00
mtpRequestId requestId ) const {
QMutexLocker locker ( & _requestByDcLock ) ;
auto it = _requestsByDc . find ( requestId ) ;
if ( it ! = _requestsByDc . cend ( ) ) {
return it - > second ;
}
2018-09-21 16:28:46 +00:00
return std : : nullopt ;
2018-04-27 13:08:12 +00:00
}
2018-09-21 16:28:46 +00:00
std : : optional < ShiftedDcId > Instance : : Private : : changeRequestByDc (
2018-04-27 13:08:12 +00:00
mtpRequestId requestId ,
DcId newdc ) {
QMutexLocker locker ( & _requestByDcLock ) ;
auto it = _requestsByDc . find ( requestId ) ;
if ( it ! = _requestsByDc . cend ( ) ) {
if ( it - > second < 0 ) {
it - > second = - newdc ;
} else {
2018-06-11 18:35:27 +00:00
it - > second = ShiftDcId ( newdc , GetDcIdShift ( it - > second ) ) ;
2018-04-27 13:08:12 +00:00
}
return it - > second ;
}
2018-09-21 16:28:46 +00:00
return std : : nullopt ;
2018-04-27 13:08:12 +00:00
}
2017-02-24 17:15:41 +00:00
void Instance : : Private : : checkDelayedRequests ( ) {
auto now = getms ( true ) ;
while ( ! _delayedRequests . empty ( ) & & now > = _delayedRequests . front ( ) . second ) {
auto requestId = _delayedRequests . front ( ) . first ;
_delayedRequests . pop_front ( ) ;
auto dcWithShift = ShiftedDcId ( 0 ) ;
2018-04-27 13:08:12 +00:00
if ( const auto shiftedDcId = queryRequestByDc ( requestId ) ) {
dcWithShift = * shiftedDcId ;
} else {
LOG ( ( " MTP Error: could not find request dc for delayed resend, requestId %1 " ) . arg ( requestId ) ) ;
continue ;
2017-02-24 17:15:41 +00:00
}
2018-06-25 18:55:27 +00:00
auto request = SecureRequest ( ) ;
2017-02-24 17:15:41 +00:00
{
QReadLocker locker ( & _requestMapLock ) ;
auto it = _requestMap . find ( requestId ) ;
if ( it = = _requestMap . cend ( ) ) {
DEBUG_LOG ( ( " MTP Error: could not find request %1 " ) . arg ( requestId ) ) ;
continue ;
}
request = it - > second ;
}
2018-06-02 14:29:21 +00:00
const auto session = getSession ( qAbs ( dcWithShift ) ) ;
session - > sendPrepared ( request ) ;
2017-02-24 17:15:41 +00:00
}
if ( ! _delayedRequests . empty ( ) ) {
2017-04-13 17:59:05 +00:00
_checkDelayedTimer . callOnce ( _delayedRequests . front ( ) . second - now ) ;
2017-02-24 17:15:41 +00:00
}
}
2018-06-02 14:29:21 +00:00
void Instance : : Private : : sendRequest (
mtpRequestId requestId ,
2018-06-25 18:55:27 +00:00
SecureRequest & & request ,
2018-06-02 14:29:21 +00:00
RPCResponseHandler & & callbacks ,
ShiftedDcId shiftedDcId ,
TimeMs msCanWait ,
bool needsLayer ,
mtpRequestId afterRequestId ) {
const auto session = getSession ( shiftedDcId ) ;
request - > requestId = requestId ;
storeRequest ( requestId , request , std : : move ( callbacks ) ) ;
const auto toMainDc = ( shiftedDcId = = 0 ) ;
const auto realShiftedDcId = session - > getDcWithShift ( ) ;
const auto signedDcId = toMainDc ? - realShiftedDcId : realShiftedDcId ;
registerRequest ( requestId , signedDcId ) ;
if ( afterRequestId ) {
request - > after = getRequest ( afterRequestId ) ;
}
request - > msDate = getms ( true ) ; // > 0 - can send without container
request - > needsLayer = needsLayer ;
session - > sendPrepared ( request , msCanWait ) ;
}
2018-01-02 13:44:12 +00:00
void Instance : : Private : : registerRequest (
mtpRequestId requestId ,
2018-06-02 14:29:21 +00:00
ShiftedDcId shiftedDcId ) {
2018-01-02 13:44:12 +00:00
QMutexLocker locker ( & _requestByDcLock ) ;
2018-06-12 13:30:00 +00:00
_requestsByDc [ requestId ] = shiftedDcId ;
2017-02-24 17:15:41 +00:00
}
void Instance : : Private : : unregisterRequest ( mtpRequestId requestId ) {
2018-06-24 13:19:49 +00:00
DEBUG_LOG ( ( " MTP Info: unregistering request %1. " ) . arg ( requestId ) ) ;
2017-02-24 17:15:41 +00:00
_requestsDelays . erase ( requestId ) ;
{
QWriteLocker locker ( & _requestMapLock ) ;
_requestMap . erase ( requestId ) ;
}
QMutexLocker locker ( & _requestByDcLock ) ;
_requestsByDc . erase ( requestId ) ;
}
2018-06-02 14:29:21 +00:00
void Instance : : Private : : storeRequest (
mtpRequestId requestId ,
2018-06-25 18:55:27 +00:00
const SecureRequest & request ,
2017-12-18 12:40:15 +00:00
RPCResponseHandler & & callbacks ) {
if ( callbacks . onDone | | callbacks . onFail ) {
2017-02-24 17:15:41 +00:00
QMutexLocker locker ( & _parserMapLock ) ;
2017-12-18 12:40:15 +00:00
_parserMap . emplace ( requestId , std : : move ( callbacks ) ) ;
2017-02-24 17:15:41 +00:00
}
{
QWriteLocker locker ( & _requestMapLock ) ;
2017-12-18 12:40:15 +00:00
_requestMap . emplace ( requestId , request ) ;
2017-02-24 17:15:41 +00:00
}
}
2018-06-25 18:55:27 +00:00
SecureRequest Instance : : Private : : getRequest ( mtpRequestId requestId ) {
auto result = SecureRequest ( ) ;
2017-02-24 17:15:41 +00:00
{
QReadLocker locker ( & _requestMapLock ) ;
auto it = _requestMap . find ( requestId ) ;
if ( it ! = _requestMap . cend ( ) ) {
result = it - > second ;
}
}
return result ;
}
void Instance : : Private : : clearCallbacks ( mtpRequestId requestId , int32 errorCode ) {
RPCResponseHandler h ;
bool found = false ;
{
QMutexLocker locker ( & _parserMapLock ) ;
auto it = _parserMap . find ( requestId ) ;
if ( it ! = _parserMap . end ( ) ) {
h = it - > second ;
found = true ;
_parserMap . erase ( it ) ;
}
}
if ( errorCode & & found ) {
2018-07-18 19:21:09 +00:00
LOG ( ( " API Error: callbacks cleared without handling! "
" Request: %1, error code: %2 "
) . arg ( requestId
) . arg ( errorCode ) ) ;
2017-02-24 17:15:41 +00:00
rpcErrorOccured ( requestId , h , internal : : rpcClientError ( " CLEAR_CALLBACK " , QString ( " did not handle request %1, error code %2 " ) . arg ( requestId ) . arg ( errorCode ) ) ) ;
}
}
2018-01-02 13:44:12 +00:00
void Instance : : Private : : clearCallbacksDelayed (
std : : vector < RPCCallbackClear > & & ids ) {
if ( ids . empty ( ) ) {
return ;
}
2017-02-24 17:15:41 +00:00
2018-06-05 13:32:26 +00:00
if ( Logs : : DebugEnabled ( ) ) {
2018-01-02 13:44:12 +00:00
auto idsString = QStringList ( ) ;
idsString . reserve ( ids . size ( ) ) ;
for ( auto & value : ids ) {
idsString . push_back ( QString : : number ( value . requestId ) ) ;
2017-02-24 17:15:41 +00:00
}
2018-01-02 13:44:12 +00:00
DEBUG_LOG ( ( " RPC Info: clear callbacks delayed, msgIds: %1 "
) . arg ( idsString . join ( " , " ) ) ) ;
2017-02-24 17:15:41 +00:00
}
2018-01-02 13:44:12 +00:00
crl : : on_main ( _instance , [ this , list = std : : move ( ids ) ] {
clearCallbacks ( list ) ;
} ) ;
2017-02-24 17:15:41 +00:00
}
2018-01-02 13:44:12 +00:00
void Instance : : Private : : clearCallbacks (
const std : : vector < RPCCallbackClear > & ids ) {
Expects ( ! ids . empty ( ) ) ;
for ( const auto & clearRequest : ids ) {
2018-06-05 13:32:26 +00:00
if ( Logs : : DebugEnabled ( ) ) {
2018-01-02 13:44:12 +00:00
QMutexLocker locker ( & _parserMapLock ) ;
2018-06-24 13:19:49 +00:00
const auto hasParsers = ( _parserMap . find ( clearRequest . requestId )
! = _parserMap . end ( ) ) ;
DEBUG_LOG ( ( " RPC Info: "
" clearing delayed callback %1, error code %2, parsers: %3 "
) . arg ( clearRequest . requestId
) . arg ( clearRequest . errorCode
) . arg ( Logs : : b ( hasParsers ) ) ) ;
2017-02-24 17:15:41 +00:00
}
2018-01-02 13:44:12 +00:00
clearCallbacks ( clearRequest . requestId , clearRequest . errorCode ) ;
unregisterRequest ( clearRequest . requestId ) ;
2017-02-24 17:15:41 +00:00
}
}
2018-01-02 13:44:12 +00:00
void Instance : : Private : : execCallback (
mtpRequestId requestId ,
const mtpPrime * from ,
const mtpPrime * end ) {
2017-02-24 17:15:41 +00:00
RPCResponseHandler h ;
{
QMutexLocker locker ( & _parserMapLock ) ;
auto it = _parserMap . find ( requestId ) ;
if ( it ! = _parserMap . cend ( ) ) {
h = it - > second ;
_parserMap . erase ( it ) ;
DEBUG_LOG ( ( " RPC Info: found parser for request %1, trying to parse response... " ) . arg ( requestId ) ) ;
}
}
if ( h . onDone | | h . onFail ) {
2018-06-24 13:19:49 +00:00
const auto handleError = [ & ] ( const MTPRpcError & error ) {
const auto wrapped = RPCError ( error ) ;
DEBUG_LOG ( ( " RPC Info: "
" error received, code %1, type %2, description: %3 "
) . arg ( wrapped . code ( )
) . arg ( wrapped . type ( )
) . arg ( wrapped . description ( ) ) ) ;
if ( rpcErrorOccured ( requestId , h , wrapped ) ) {
unregisterRequest ( requestId ) ;
} else {
QMutexLocker locker ( & _parserMapLock ) ;
_parserMap . emplace ( requestId , h ) ;
}
} ;
2017-02-24 17:15:41 +00:00
try {
if ( from > = end ) throw mtpErrorInsufficient ( ) ;
if ( * from = = mtpc_rpc_error ) {
2018-06-24 13:19:49 +00:00
auto error = MTPRpcError ( ) ;
error . read ( from , end ) ;
handleError ( error ) ;
2017-02-24 17:15:41 +00:00
} else {
if ( h . onDone ) {
( * h . onDone ) ( requestId , from , end ) ;
}
2018-06-24 13:19:49 +00:00
unregisterRequest ( requestId ) ;
2017-02-24 17:15:41 +00:00
}
} catch ( Exception & e ) {
2018-06-24 13:19:49 +00:00
handleError ( internal : : rpcClientError (
" RESPONSE_PARSE_FAILED " ,
QString ( " exception text: " ) + e . what ( ) ) ) ;
2017-02-24 17:15:41 +00:00
}
} else {
DEBUG_LOG ( ( " RPC Info: parser not found for %1 " ) . arg ( requestId ) ) ;
2018-06-24 13:19:49 +00:00
unregisterRequest ( requestId ) ;
2017-02-24 17:15:41 +00:00
}
}
bool Instance : : Private : : hasCallbacks ( mtpRequestId requestId ) {
QMutexLocker locker ( & _parserMapLock ) ;
auto it = _parserMap . find ( requestId ) ;
return ( it ! = _parserMap . cend ( ) ) ;
}
void Instance : : Private : : globalCallback ( const mtpPrime * from , const mtpPrime * end ) {
if ( _globalHandler . onDone ) {
( * _globalHandler . onDone ) ( 0 , from , end ) ; // some updates were received
}
}
void Instance : : Private : : onStateChange ( int32 dcWithShift , int32 state ) {
if ( _stateChangedHandler ) {
_stateChangedHandler ( dcWithShift , state ) ;
}
}
void Instance : : Private : : onSessionReset ( int32 dcWithShift ) {
if ( _sessionResetHandler ) {
_sessionResetHandler ( dcWithShift ) ;
}
}
bool Instance : : Private : : rpcErrorOccured ( mtpRequestId requestId , const RPCFailHandlerPtr & onFail , const RPCError & err ) { // return true if need to clean request data
if ( isDefaultHandledError ( err ) ) {
if ( onFail & & ( * onFail ) ( requestId , err ) ) return true ;
}
if ( onErrorDefault ( requestId , err ) ) {
return false ;
}
LOG ( ( " RPC Error: request %1 got fail with code %2, error %3%4 " ) . arg ( requestId ) . arg ( err . code ( ) ) . arg ( err . type ( ) ) . arg ( err . description ( ) . isEmpty ( ) ? QString ( ) : QString ( " : %1 " ) . arg ( err . description ( ) ) ) ) ;
onFail & & ( * onFail ) ( requestId , err ) ;
return true ;
}
bool Instance : : Private : : hasAuthorization ( ) {
2017-03-04 19:36:59 +00:00
return AuthSession : : Exists ( ) ;
2017-02-24 17:15:41 +00:00
}
void Instance : : Private : : importDone ( const MTPauth_Authorization & result , mtpRequestId requestId ) {
2018-04-27 13:08:12 +00:00
const auto shiftedDcId = queryRequestByDc ( requestId ) ;
if ( ! shiftedDcId ) {
2017-02-24 17:15:41 +00:00
LOG ( ( " MTP Error: auth import request not found in requestsByDC, requestId: %1 " ) . arg ( requestId ) ) ;
2018-05-13 08:42:25 +00:00
//
// Don't log out on export/import problems, perhaps this is a server side error.
//
//RPCError error(internal::rpcClientError("AUTH_IMPORT_FAIL", QString("did not find import request in requestsByDC, request %1").arg(requestId)));
//if (_globalHandler.onFail && hasAuthorization()) {
// (*_globalHandler.onFail)(requestId, error); // auth failed in main dc
//}
2017-02-24 17:15:41 +00:00
return ;
}
2018-06-11 18:35:27 +00:00
auto newdc = BareDcId ( * shiftedDcId ) ;
2017-02-24 17:15:41 +00:00
DEBUG_LOG ( ( " MTP Info: auth import to dc %1 succeeded " ) . arg ( newdc ) ) ;
auto & waiters = _authWaiters [ newdc ] ;
if ( waiters . size ( ) ) {
QReadLocker locker ( & _requestMapLock ) ;
for ( auto waitedRequestId : waiters ) {
auto it = _requestMap . find ( waitedRequestId ) ;
if ( it = = _requestMap . cend ( ) ) {
LOG ( ( " MTP Error: could not find request %1 for resending " ) . arg ( waitedRequestId ) ) ;
continue ;
}
2018-04-27 13:08:12 +00:00
const auto shiftedDcId = changeRequestByDc ( waitedRequestId , newdc ) ;
if ( ! shiftedDcId ) {
LOG ( ( " MTP Error: could not find request %1 by dc for resending " ) . arg ( waitedRequestId ) ) ;
continue ;
} else if ( * shiftedDcId < 0 ) {
_instance - > setMainDcId ( newdc ) ;
2017-02-24 17:15:41 +00:00
}
2018-04-27 13:08:12 +00:00
DEBUG_LOG ( ( " MTP Info: resending request %1 to dc %2 after import auth " ) . arg ( waitedRequestId ) . arg ( * shiftedDcId ) ) ;
2018-06-02 14:29:21 +00:00
const auto session = getSession ( * shiftedDcId ) ;
session - > sendPrepared ( it - > second ) ;
2017-02-24 17:15:41 +00:00
}
waiters . clear ( ) ;
}
}
bool Instance : : Private : : importFail ( const RPCError & error , mtpRequestId requestId ) {
if ( isDefaultHandledError ( error ) ) return false ;
2018-05-13 08:42:25 +00:00
//
// Don't log out on export/import problems, perhaps this is a server side error.
//
//if (_globalHandler.onFail && hasAuthorization()) {
// (*_globalHandler.onFail)(requestId, error); // auth import failed
//}
2017-02-24 17:15:41 +00:00
return true ;
}
void Instance : : Private : : exportDone ( const MTPauth_ExportedAuthorization & result , mtpRequestId requestId ) {
auto it = _authExportRequests . find ( requestId ) ;
if ( it = = _authExportRequests . cend ( ) ) {
LOG ( ( " MTP Error: auth export request target dcWithShift not found, requestId: %1 " ) . arg ( requestId ) ) ;
2018-05-13 08:42:25 +00:00
//
// Don't log out on export/import problems, perhaps this is a server side error.
//
//RPCError error(internal::rpcClientError("AUTH_IMPORT_FAIL", QString("did not find target dcWithShift, request %1").arg(requestId)));
//if (_globalHandler.onFail && hasAuthorization()) {
// (*_globalHandler.onFail)(requestId, error); // auth failed in main dc
//}
2017-02-24 17:15:41 +00:00
return ;
}
auto & data = result . c_auth_exportedAuthorization ( ) ;
_instance - > send ( MTPauth_ImportAuthorization ( data . vid , data . vbytes ) , rpcDone ( [ this ] ( const MTPauth_Authorization & result , mtpRequestId requestId ) {
importDone ( result , requestId ) ;
} ) , rpcFail ( [ this ] ( const RPCError & error , mtpRequestId requestId ) {
return importFail ( error , requestId ) ;
} ) , it - > second ) ;
_authExportRequests . erase ( requestId ) ;
}
bool Instance : : Private : : exportFail ( const RPCError & error , mtpRequestId requestId ) {
if ( isDefaultHandledError ( error ) ) return false ;
auto it = _authExportRequests . find ( requestId ) ;
if ( it ! = _authExportRequests . cend ( ) ) {
2018-06-11 18:35:27 +00:00
_authWaiters [ BareDcId ( it - > second ) ] . clear ( ) ;
2017-02-24 17:15:41 +00:00
}
2018-05-13 08:42:25 +00:00
//
// Don't log out on export/import problems, perhaps this is a server side error.
//
//if (_globalHandler.onFail && hasAuthorization()) {
// (*_globalHandler.onFail)(requestId, error); // auth failed in main dc
//}
2017-02-24 17:15:41 +00:00
return true ;
}
bool Instance : : Private : : onErrorDefault ( mtpRequestId requestId , const RPCError & error ) {
auto & err ( error . type ( ) ) ;
auto code = error . code ( ) ;
if ( ! isFloodError ( error ) & & err ! = qstr ( " AUTH_KEY_UNREGISTERED " ) ) {
int breakpoint = 0 ;
}
auto badGuestDc = ( code = = 400 ) & & ( err = = qsl ( " FILE_ID_INVALID " ) ) ;
QRegularExpressionMatch m ;
if ( ( m = QRegularExpression ( " ^(FILE|PHONE|NETWORK|USER)_MIGRATE_( \\ d+)$ " ) . match ( err ) ) . hasMatch ( ) ) {
if ( ! requestId ) return false ;
2018-04-27 13:08:12 +00:00
auto dcWithShift = ShiftedDcId ( 0 ) ;
auto newdcWithShift = ShiftedDcId ( m . captured ( 2 ) . toInt ( ) ) ;
if ( const auto shiftedDcId = queryRequestByDc ( requestId ) ) {
dcWithShift = * shiftedDcId ;
} else {
LOG ( ( " MTP Error: could not find request %1 for migrating to %2 " ) . arg ( requestId ) . arg ( newdcWithShift ) ) ;
2017-02-24 17:15:41 +00:00
}
if ( ! dcWithShift | | ! newdcWithShift ) return false ;
DEBUG_LOG ( ( " MTP Info: changing request %1 from dcWithShift%2 to dc%3 " ) . arg ( requestId ) . arg ( dcWithShift ) . arg ( newdcWithShift ) ) ;
if ( dcWithShift < 0 ) { // newdc shift = 0
if ( false & & hasAuthorization ( ) & & _authExportRequests . find ( requestId ) = = _authExportRequests . cend ( ) ) {
//
// migrate not supported at this moment
// this was not tested even once
//
//DEBUG_LOG(("MTP Info: importing auth to dc %1").arg(newdcWithShift));
//auto &waiters(_authWaiters[newdcWithShift]);
//if (waiters.empty()) {
// auto exportRequestId = _instance->send(MTPauth_ExportAuthorization(MTP_int(newdcWithShift)), rpcDone([this](const MTPauth_ExportedAuthorization &result, mtpRequestId requestId) {
// exportDone(result, requestId);
// }), rpcFail([this](const RPCError &error, mtpRequestId requestId) {
// return exportFail(error, requestId);
// }));
// _authExportRequests.emplace(exportRequestId, newdcWithShift);
//}
//waiters.push_back(requestId);
//return true;
} else {
_instance - > setMainDcId ( newdcWithShift ) ;
}
} else {
2018-06-11 18:35:27 +00:00
newdcWithShift = ShiftDcId ( newdcWithShift , GetDcIdShift ( dcWithShift ) ) ;
2017-02-24 17:15:41 +00:00
}
2018-06-25 18:55:27 +00:00
auto request = SecureRequest ( ) ;
2017-02-24 17:15:41 +00:00
{
QReadLocker locker ( & _requestMapLock ) ;
auto it = _requestMap . find ( requestId ) ;
if ( it = = _requestMap . cend ( ) ) {
LOG ( ( " MTP Error: could not find request %1 " ) . arg ( requestId ) ) ;
return false ;
}
request = it - > second ;
}
2018-06-02 14:29:21 +00:00
const auto session = getSession ( newdcWithShift ) ;
registerRequest (
requestId ,
( dcWithShift < 0 ) ? - newdcWithShift : newdcWithShift ) ;
session - > sendPrepared ( request ) ;
2017-02-24 17:15:41 +00:00
return true ;
} else if ( code < 0 | | code > = 500 | | ( m = QRegularExpression ( " ^FLOOD_WAIT_( \\ d+) $ " ).match(err)).hasMatch()) {
if ( ! requestId ) return false ;
int32 secs = 1 ;
if ( code < 0 | | code > = 500 ) {
auto it = _requestsDelays . find ( requestId ) ;
if ( it ! = _requestsDelays . cend ( ) ) {
secs = ( it - > second > 60 ) ? it - > second : ( it - > second * = 2 ) ;
} else {
_requestsDelays . emplace ( requestId , secs ) ;
}
} else {
secs = m . captured ( 1 ) . toInt ( ) ;
// if (secs >= 60) return false;
}
auto sendAt = getms ( true ) + secs * 1000 + 10 ;
auto it = _delayedRequests . begin ( ) , e = _delayedRequests . end ( ) ;
for ( ; it ! = e ; + + it ) {
if ( it - > first = = requestId ) return true ;
if ( it - > second > sendAt ) break ;
}
_delayedRequests . insert ( it , std : : make_pair ( requestId , sendAt ) ) ;
checkDelayedRequests ( ) ;
return true ;
} else if ( code = = 401 | | ( badGuestDc & & _badGuestDcRequests . find ( requestId ) = = _badGuestDcRequests . cend ( ) ) ) {
auto dcWithShift = ShiftedDcId ( 0 ) ;
2018-04-27 13:08:12 +00:00
if ( const auto shiftedDcId = queryRequestByDc ( requestId ) ) {
dcWithShift = * shiftedDcId ;
} else {
LOG ( ( " MTP Error: unauthorized request without dc info, requestId %1 " ) . arg ( requestId ) ) ;
2017-02-24 17:15:41 +00:00
}
2018-06-11 18:35:27 +00:00
auto newdc = BareDcId ( qAbs ( dcWithShift ) ) ;
2017-02-24 17:15:41 +00:00
if ( ! newdc | | newdc = = mainDcId ( ) | | ! hasAuthorization ( ) ) {
if ( ! badGuestDc & & _globalHandler . onFail ) {
( * _globalHandler . onFail ) ( requestId , error ) ; // auth failed in main dc
}
return false ;
}
DEBUG_LOG ( ( " MTP Info: importing auth to dcWithShift %1 " ) . arg ( dcWithShift ) ) ;
auto & waiters ( _authWaiters [ newdc ] ) ;
if ( ! waiters . size ( ) ) {
auto exportRequestId = _instance - > send ( MTPauth_ExportAuthorization ( MTP_int ( newdc ) ) , rpcDone ( [ this ] ( const MTPauth_ExportedAuthorization & result , mtpRequestId requestId ) {
exportDone ( result , requestId ) ;
} ) , rpcFail ( [ this ] ( const RPCError & error , mtpRequestId requestId ) {
return exportFail ( error , requestId ) ;
} ) ) ;
_authExportRequests . emplace ( exportRequestId , abs ( dcWithShift ) ) ;
}
waiters . push_back ( requestId ) ;
if ( badGuestDc ) _badGuestDcRequests . insert ( requestId ) ;
return true ;
} else if ( err = = qstr ( " CONNECTION_NOT_INITED " ) | | err = = qstr ( " CONNECTION_LAYER_INVALID " ) ) {
2018-06-25 18:55:27 +00:00
SecureRequest request ;
2017-02-24 17:15:41 +00:00
{
QReadLocker locker ( & _requestMapLock ) ;
auto it = _requestMap . find ( requestId ) ;
if ( it = = _requestMap . cend ( ) ) {
LOG ( ( " MTP Error: could not find request %1 " ) . arg ( requestId ) ) ;
return false ;
}
request = it - > second ;
}
auto dcWithShift = ShiftedDcId ( 0 ) ;
2018-04-27 13:08:12 +00:00
if ( const auto shiftedDcId = queryRequestByDc ( requestId ) ) {
dcWithShift = * shiftedDcId ;
} else {
LOG ( ( " MTP Error: could not find request %1 for resending with init connection " ) . arg ( requestId ) ) ;
2017-02-24 17:15:41 +00:00
}
if ( ! dcWithShift ) return false ;
2018-06-02 14:29:21 +00:00
const auto session = getSession ( qAbs ( dcWithShift ) ) ;
request - > needsLayer = true ;
session - > sendPrepared ( request ) ;
2017-02-24 17:15:41 +00:00
return true ;
2017-05-30 09:31:32 +00:00
} else if ( err = = qstr ( " CONNECTION_LANG_CODE_INVALID " ) ) {
2017-05-30 17:58:25 +00:00
Lang : : CurrentCloudManager ( ) . resetToDefault ( ) ;
2017-02-24 17:15:41 +00:00
} else if ( err = = qstr ( " MSG_WAIT_FAILED " ) ) {
2018-06-25 18:55:27 +00:00
SecureRequest request ;
2017-02-24 17:15:41 +00:00
{
QReadLocker locker ( & _requestMapLock ) ;
auto it = _requestMap . find ( requestId ) ;
if ( it = = _requestMap . cend ( ) ) {
LOG ( ( " MTP Error: could not find request %1 " ) . arg ( requestId ) ) ;
return false ;
}
request = it - > second ;
}
if ( ! request - > after ) {
LOG ( ( " MTP Error: wait failed for not dependent request %1 " ) . arg ( requestId ) ) ;
return false ;
}
auto dcWithShift = ShiftedDcId ( 0 ) ;
2018-04-27 13:08:12 +00:00
if ( const auto shiftedDcId = queryRequestByDc ( requestId ) ) {
if ( const auto afterDcId = queryRequestByDc ( request - > after - > requestId ) ) {
dcWithShift = * shiftedDcId ;
if ( * shiftedDcId ! = * afterDcId ) {
2018-06-25 18:55:27 +00:00
request - > after = SecureRequest ( ) ;
2017-02-24 17:15:41 +00:00
}
2018-04-27 13:08:12 +00:00
} else {
LOG ( ( " MTP Error: could not find dependent request %1 by dc " ) . arg ( request - > after - > requestId ) ) ;
2017-02-24 17:15:41 +00:00
}
2018-04-27 13:08:12 +00:00
} else {
LOG ( ( " MTP Error: could not find request %1 by dc " ) . arg ( requestId ) ) ;
2017-02-24 17:15:41 +00:00
}
if ( ! dcWithShift ) return false ;
if ( ! request - > after ) {
2018-06-02 14:29:21 +00:00
const auto session = getSession ( qAbs ( dcWithShift ) ) ;
request - > needsLayer = true ;
session - > sendPrepared ( request ) ;
2017-02-24 17:15:41 +00:00
} else {
2018-06-11 18:35:27 +00:00
auto newdc = BareDcId ( qAbs ( dcWithShift ) ) ;
2017-02-24 17:15:41 +00:00
auto & waiters ( _authWaiters [ newdc ] ) ;
if ( base : : contains ( waiters , request - > after - > requestId ) ) {
if ( ! base : : contains ( waiters , requestId ) ) {
waiters . push_back ( requestId ) ;
}
if ( _badGuestDcRequests . find ( request - > after - > requestId ) ! = _badGuestDcRequests . cend ( ) ) {
if ( _badGuestDcRequests . find ( requestId ) = = _badGuestDcRequests . cend ( ) ) {
_badGuestDcRequests . insert ( requestId ) ;
}
}
} else {
auto i = _delayedRequests . begin ( ) , e = _delayedRequests . end ( ) ;
for ( ; i ! = e ; + + i ) {
if ( i - > first = = requestId ) return true ;
if ( i - > first = = request - > after - > requestId ) break ;
}
if ( i ! = e ) {
_delayedRequests . insert ( i , std : : make_pair ( requestId , i - > second ) ) ;
}
checkDelayedRequests ( ) ;
}
}
return true ;
}
if ( badGuestDc ) _badGuestDcRequests . erase ( requestId ) ;
return false ;
}
2018-06-02 14:29:21 +00:00
not_null < internal : : Session * > Instance : : Private : : getSession (
ShiftedDcId shiftedDcId ) {
2017-02-24 17:15:41 +00:00
if ( ! shiftedDcId ) {
2017-08-17 09:06:26 +00:00
Assert ( _mainSession ! = nullptr ) ;
2017-02-24 17:15:41 +00:00
return _mainSession ;
}
2018-06-11 18:35:27 +00:00
if ( ! BareDcId ( shiftedDcId ) ) {
2017-08-17 09:06:26 +00:00
Assert ( _mainSession ! = nullptr ) ;
2018-06-11 18:35:27 +00:00
shiftedDcId + = BareDcId ( _mainSession - > getDcWithShift ( ) ) ;
2017-02-24 17:15:41 +00:00
}
auto it = _sessions . find ( shiftedDcId ) ;
if ( it = = _sessions . cend ( ) ) {
2017-08-17 09:06:26 +00:00
Assert ( ! MustNotCreateSessions ) ;
2017-02-24 17:15:41 +00:00
it = _sessions . emplace ( shiftedDcId , std : : make_unique < internal : : Session > ( _instance , shiftedDcId ) ) . first ;
2017-02-25 16:44:02 +00:00
it - > second - > start ( ) ;
2017-02-24 17:15:41 +00:00
}
return it - > second . get ( ) ;
}
2017-02-25 16:44:02 +00:00
void Instance : : Private : : scheduleKeyDestroy ( ShiftedDcId shiftedDcId ) {
2017-06-26 17:38:16 +00:00
Expects ( isKeysDestroyer ( ) ) ;
2017-02-25 16:44:02 +00:00
2018-05-18 16:41:59 +00:00
if ( dcOptions ( ) - > dcType ( shiftedDcId ) = = DcType : : Cdn ) {
2017-02-25 16:44:02 +00:00
performKeyDestroy ( shiftedDcId ) ;
2018-05-18 16:41:59 +00:00
} else {
_instance - > send ( MTPauth_LogOut ( ) , rpcDone ( [ = ] ( const MTPBool & ) {
performKeyDestroy ( shiftedDcId ) ;
} ) , rpcFail ( [ = ] ( const RPCError & error ) {
if ( isDefaultHandledError ( error ) ) return false ;
performKeyDestroy ( shiftedDcId ) ;
return true ;
} ) , shiftedDcId ) ;
}
2017-02-25 16:44:02 +00:00
}
void Instance : : Private : : performKeyDestroy ( ShiftedDcId shiftedDcId ) {
2017-06-26 17:38:16 +00:00
Expects ( isKeysDestroyer ( ) ) ;
2017-02-25 16:44:02 +00:00
_instance - > send ( MTPDestroy_auth_key ( ) , rpcDone ( [ this , shiftedDcId ] ( const MTPDestroyAuthKeyRes & result ) {
switch ( result . type ( ) ) {
case mtpc_destroy_auth_key_ok : LOG ( ( " MTP Info: key %1 destroyed. " ) . arg ( shiftedDcId ) ) ; break ;
case mtpc_destroy_auth_key_fail : {
LOG ( ( " MTP Error: key %1 destruction fail, leave it for now. " ) . arg ( shiftedDcId ) ) ;
killSession ( shiftedDcId ) ;
} break ;
case mtpc_destroy_auth_key_none : LOG ( ( " MTP Info: key %1 already destroyed. " ) . arg ( shiftedDcId ) ) ; break ;
}
emit _instance - > keyDestroyed ( shiftedDcId ) ;
} ) , rpcFail ( [ this , shiftedDcId ] ( const RPCError & error ) {
LOG ( ( " MTP Error: key %1 destruction resulted in error: %2 " ) . arg ( shiftedDcId ) . arg ( error . type ( ) ) ) ;
emit _instance - > keyDestroyed ( shiftedDcId ) ;
return true ;
} ) , shiftedDcId ) ;
}
void Instance : : Private : : completedKeyDestroy ( ShiftedDcId shiftedDcId ) {
2017-06-26 17:38:16 +00:00
Expects ( isKeysDestroyer ( ) ) ;
2017-02-25 16:44:02 +00:00
_dcenters . erase ( shiftedDcId ) ;
{
QWriteLocker lock ( & _keysForWriteLock ) ;
_keysForWrite . erase ( shiftedDcId ) ;
}
killSession ( shiftedDcId ) ;
if ( _dcenters . empty ( ) ) {
emit _instance - > allKeysDestroyed ( ) ;
}
}
2017-02-24 17:15:41 +00:00
void Instance : : Private : : setUpdatesHandler ( RPCDoneHandlerPtr onDone ) {
_globalHandler . onDone = onDone ;
}
void Instance : : Private : : setGlobalFailHandler ( RPCFailHandlerPtr onFail ) {
_globalHandler . onFail = onFail ;
}
2018-06-04 15:35:11 +00:00
void Instance : : Private : : setStateChangedHandler ( Fn < void ( ShiftedDcId shiftedDcId , int32 state ) > handler ) {
2017-02-24 17:15:41 +00:00
_stateChangedHandler = std : : move ( handler ) ;
}
2018-06-04 15:35:11 +00:00
void Instance : : Private : : setSessionResetHandler ( Fn < void ( ShiftedDcId shiftedDcId ) > handler ) {
2017-02-24 17:15:41 +00:00
_sessionResetHandler = std : : move ( handler ) ;
}
void Instance : : Private : : clearGlobalHandlers ( ) {
setUpdatesHandler ( RPCDoneHandlerPtr ( ) ) ;
setGlobalFailHandler ( RPCFailHandlerPtr ( ) ) ;
2018-06-04 15:35:11 +00:00
setStateChangedHandler ( Fn < void ( ShiftedDcId , int32 ) > ( ) ) ;
setSessionResetHandler ( Fn < void ( ShiftedDcId ) > ( ) ) ;
2017-02-24 17:15:41 +00:00
}
2017-02-25 17:55:11 +00:00
void Instance : : Private : : prepareToDestroy ( ) {
2017-02-27 18:47:29 +00:00
// It accesses Instance in destructor, so it should be destroyed first.
_configLoader . reset ( ) ;
2017-03-23 16:11:35 +00:00
requestCancellingDiscard ( ) ;
2017-02-24 17:15:41 +00:00
for ( auto & session : base : : take ( _sessions ) ) {
session . second - > kill ( ) ;
}
2017-02-27 18:47:29 +00:00
_mainSession = nullptr ;
2017-02-25 16:44:02 +00:00
2017-02-27 18:47:29 +00:00
MustNotCreateSessions = true ;
2017-02-24 17:15:41 +00:00
}
2018-05-11 14:03:53 +00:00
Instance : : Instance ( not_null < DcOptions * > options , Mode mode , Config & & config )
: QObject ( )
2017-02-25 16:44:02 +00:00
, _private ( std : : make_unique < Private > ( this , options , mode ) ) {
2017-02-24 17:15:41 +00:00
_private - > start ( std : : move ( config ) ) ;
}
2018-05-17 19:58:00 +00:00
void Instance : : resolveProxyDomain ( const QString & host ) {
_private - > resolveProxyDomain ( host ) ;
}
void Instance : : setGoodProxyDomain ( const QString & host , const QString & ip ) {
_private - > setGoodProxyDomain ( host , ip ) ;
}
2017-02-24 17:15:41 +00:00
void Instance : : suggestMainDcId ( DcId mainDcId ) {
_private - > suggestMainDcId ( mainDcId ) ;
}
void Instance : : setMainDcId ( DcId mainDcId ) {
_private - > setMainDcId ( mainDcId ) ;
}
DcId Instance : : mainDcId ( ) const {
return _private - > mainDcId ( ) ;
}
2017-05-30 09:31:32 +00:00
QString Instance : : systemLangCode ( ) const {
return Lang : : Current ( ) . systemLangCode ( ) ;
}
2017-04-13 17:59:05 +00:00
QString Instance : : cloudLangCode ( ) const {
return Lang : : Current ( ) . cloudLangCode ( ) ;
}
2018-08-20 11:31:40 +00:00
QString Instance : : langPackName ( ) const {
return Lang : : Current ( ) . langPackName ( ) ;
}
2017-04-13 17:59:05 +00:00
void Instance : : requestConfig ( ) {
_private - > requestConfig ( ) ;
}
2018-05-02 19:27:03 +00:00
void Instance : : setUserPhone ( const QString & phone ) {
_private - > setUserPhone ( phone ) ;
}
2018-05-24 13:40:19 +00:00
void Instance : : badConfigurationError ( ) {
_private - > badConfigurationError ( ) ;
}
2018-04-24 07:21:19 +00:00
void Instance : : requestConfigIfOld ( ) {
_private - > requestConfigIfOld ( ) ;
}
2017-04-13 17:59:05 +00:00
void Instance : : requestCDNConfig ( ) {
_private - > requestCDNConfig ( ) ;
}
2017-02-24 17:15:41 +00:00
void Instance : : connectionFinished ( internal : : Connection * connection ) {
_private - > connectionFinished ( connection ) ;
}
void Instance : : restart ( ) {
_private - > restart ( ) ;
}
void Instance : : restart ( ShiftedDcId shiftedDcId ) {
_private - > restart ( shiftedDcId ) ;
}
int32 Instance : : dcstate ( ShiftedDcId shiftedDcId ) {
return _private - > dcstate ( shiftedDcId ) ;
}
QString Instance : : dctransport ( ShiftedDcId shiftedDcId ) {
return _private - > dctransport ( shiftedDcId ) ;
}
void Instance : : ping ( ) {
_private - > ping ( ) ;
}
void Instance : : cancel ( mtpRequestId requestId ) {
_private - > cancel ( requestId ) ;
}
int32 Instance : : state ( mtpRequestId requestId ) { // < 0 means waiting for such count of ms
return _private - > state ( requestId ) ;
}
void Instance : : killSession ( ShiftedDcId shiftedDcId ) {
_private - > killSession ( shiftedDcId ) ;
}
void Instance : : stopSession ( ShiftedDcId shiftedDcId ) {
_private - > stopSession ( shiftedDcId ) ;
}
2017-04-18 15:21:03 +00:00
void Instance : : reInitConnection ( DcId dcId ) {
_private - > reInitConnection ( dcId ) ;
}
2017-02-24 17:15:41 +00:00
void Instance : : logout ( RPCDoneHandlerPtr onDone , RPCFailHandlerPtr onFail ) {
_private - > logout ( onDone , onFail ) ;
}
2017-06-26 17:38:16 +00:00
std : : shared_ptr < internal : : Dcenter > Instance : : getDcById ( ShiftedDcId shiftedDcId ) {
2017-02-25 16:44:02 +00:00
return _private - > getDcById ( shiftedDcId ) ;
2017-02-24 17:15:41 +00:00
}
void Instance : : setKeyForWrite ( DcId dcId , const AuthKeyPtr & key ) {
_private - > setKeyForWrite ( dcId , key ) ;
}
2017-02-25 16:44:02 +00:00
AuthKeysList Instance : : getKeysForWrite ( ) const {
2017-02-24 17:15:41 +00:00
return _private - > getKeysForWrite ( ) ;
}
2017-02-25 16:44:02 +00:00
void Instance : : addKeysForDestroy ( AuthKeysList & & keys ) {
_private - > addKeysForDestroy ( std : : move ( keys ) ) ;
}
2017-08-17 08:31:24 +00:00
not_null < DcOptions * > Instance : : dcOptions ( ) {
2017-02-24 17:15:41 +00:00
return _private - > dcOptions ( ) ;
}
void Instance : : unpaused ( ) {
_private - > unpaused ( ) ;
}
2017-12-18 12:40:15 +00:00
void Instance : : queueQuittingConnection (
std : : unique_ptr < internal : : Connection > & & connection ) {
2017-02-24 17:15:41 +00:00
_private - > queueQuittingConnection ( std : : move ( connection ) ) ;
}
void Instance : : setUpdatesHandler ( RPCDoneHandlerPtr onDone ) {
_private - > setUpdatesHandler ( onDone ) ;
}
void Instance : : setGlobalFailHandler ( RPCFailHandlerPtr onFail ) {
_private - > setGlobalFailHandler ( onFail ) ;
}
2018-06-04 15:35:11 +00:00
void Instance : : setStateChangedHandler ( Fn < void ( ShiftedDcId shiftedDcId , int32 state ) > handler ) {
2017-02-24 17:15:41 +00:00
_private - > setStateChangedHandler ( std : : move ( handler ) ) ;
}
2018-06-04 15:35:11 +00:00
void Instance : : setSessionResetHandler ( Fn < void ( ShiftedDcId shiftedDcId ) > handler ) {
2017-02-24 17:15:41 +00:00
_private - > setSessionResetHandler ( std : : move ( handler ) ) ;
}
void Instance : : clearGlobalHandlers ( ) {
_private - > clearGlobalHandlers ( ) ;
}
2018-06-02 14:29:21 +00:00
void Instance : : onStateChange ( ShiftedDcId shiftedDcId , int32 state ) {
_private - > onStateChange ( shiftedDcId , state ) ;
2017-02-24 17:15:41 +00:00
}
2018-06-02 14:29:21 +00:00
void Instance : : onSessionReset ( ShiftedDcId shiftedDcId ) {
_private - > onSessionReset ( shiftedDcId ) ;
2017-02-24 17:15:41 +00:00
}
2018-01-02 13:44:12 +00:00
void Instance : : clearCallbacksDelayed ( std : : vector < RPCCallbackClear > & & ids ) {
_private - > clearCallbacksDelayed ( std : : move ( ids ) ) ;
2017-02-24 17:15:41 +00:00
}
void Instance : : execCallback ( mtpRequestId requestId , const mtpPrime * from , const mtpPrime * end ) {
_private - > execCallback ( requestId , from , end ) ;
}
bool Instance : : hasCallbacks ( mtpRequestId requestId ) {
return _private - > hasCallbacks ( requestId ) ;
}
void Instance : : globalCallback ( const mtpPrime * from , const mtpPrime * end ) {
_private - > globalCallback ( from , end ) ;
}
bool Instance : : rpcErrorOccured ( mtpRequestId requestId , const RPCFailHandlerPtr & onFail , const RPCError & err ) {
return _private - > rpcErrorOccured ( requestId , onFail , err ) ;
}
2017-02-25 16:44:02 +00:00
bool Instance : : isKeysDestroyer ( ) const {
return _private - > isKeysDestroyer ( ) ;
}
void Instance : : scheduleKeyDestroy ( ShiftedDcId shiftedDcId ) {
_private - > scheduleKeyDestroy ( shiftedDcId ) ;
}
void Instance : : onKeyDestroyed ( qint32 shiftedDcId ) {
_private - > completedKeyDestroy ( shiftedDcId ) ;
}
2018-06-02 14:29:21 +00:00
void Instance : : sendRequest (
mtpRequestId requestId ,
2018-06-25 18:55:27 +00:00
SecureRequest & & request ,
2017-12-18 12:40:15 +00:00
RPCResponseHandler & & callbacks ,
2018-06-02 14:29:21 +00:00
ShiftedDcId shiftedDcId ,
2017-12-18 12:40:15 +00:00
TimeMs msCanWait ,
2018-06-02 14:29:21 +00:00
bool needsLayer ,
mtpRequestId afterRequestId ) {
return _private - > sendRequest (
requestId ,
std : : move ( request ) ,
std : : move ( callbacks ) ,
shiftedDcId ,
msCanWait ,
needsLayer ,
afterRequestId ) ;
}
void Instance : : sendAnything ( ShiftedDcId shiftedDcId , TimeMs msCanWait ) {
const auto session = _private - > getSession ( shiftedDcId ) ;
session - > sendAnything ( msCanWait ) ;
2017-12-18 12:40:15 +00:00
}
2017-02-25 17:55:11 +00:00
Instance : : ~ Instance ( ) {
_private - > prepareToDestroy ( ) ;
}
2017-02-24 17:15:41 +00:00
} // namespace MTP