init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
242
Telegram/SourceFiles/mtproto/config_loader.cpp
Normal file
242
Telegram/SourceFiles/mtproto/config_loader.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "mtproto/config_loader.h"
|
||||
|
||||
#include "base/random.h"
|
||||
#include "mtproto/special_config_request.h"
|
||||
#include "mtproto/facade.h"
|
||||
#include "mtproto/mtproto_dc_options.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "mtproto/mtp_instance.h"
|
||||
|
||||
namespace MTP {
|
||||
namespace details {
|
||||
namespace {
|
||||
|
||||
constexpr auto kEnumerateDcTimeout = 8000; // 8 seconds timeout for help_getConfig to work (then move to other dc)
|
||||
constexpr auto kSpecialRequestTimeoutMs = 6000; // 4 seconds timeout for it to work in a specially requested dc.
|
||||
|
||||
} // namespace
|
||||
|
||||
ConfigLoader::ConfigLoader(
|
||||
not_null<Instance*> instance,
|
||||
const QString &phone,
|
||||
Fn<void(const MTPConfig &result)> onDone,
|
||||
FailHandler onFail,
|
||||
bool proxyEnabled)
|
||||
: _instance(instance)
|
||||
, _phone(phone)
|
||||
, _proxyEnabled(proxyEnabled)
|
||||
, _doneHandler(onDone)
|
||||
, _failHandler(onFail) {
|
||||
_enumDCTimer.setCallback([this] { enumerate(); });
|
||||
_specialEnumTimer.setCallback([this] { sendSpecialRequest(); });
|
||||
}
|
||||
|
||||
void ConfigLoader::load() {
|
||||
if (!_instance->isKeysDestroyer()) {
|
||||
sendRequest(_instance->mainDcId());
|
||||
_enumDCTimer.callOnce(kEnumerateDcTimeout);
|
||||
} else {
|
||||
auto ids = _instance->dcOptions().configEnumDcIds();
|
||||
Assert(!ids.empty());
|
||||
_enumCurrent = ids.front();
|
||||
enumerate();
|
||||
}
|
||||
}
|
||||
|
||||
mtpRequestId ConfigLoader::sendRequest(ShiftedDcId shiftedDcId) {
|
||||
auto done = [done = _doneHandler](const Response &response) {
|
||||
auto from = response.reply.constData();
|
||||
auto result = MTPConfig();
|
||||
if (!result.read(from, from + response.reply.size())) {
|
||||
return false;
|
||||
}
|
||||
done(result);
|
||||
return true;
|
||||
};
|
||||
return _instance->send(
|
||||
MTPhelp_GetConfig(),
|
||||
std::move(done),
|
||||
base::duplicate(_failHandler),
|
||||
shiftedDcId);
|
||||
}
|
||||
|
||||
DcId ConfigLoader::specialToRealDcId(DcId specialDcId) {
|
||||
return getTemporaryIdFromRealDcId(specialDcId);
|
||||
}
|
||||
|
||||
void ConfigLoader::terminateRequest() {
|
||||
if (_enumRequest) {
|
||||
_instance->cancel(base::take(_enumRequest));
|
||||
}
|
||||
if (_enumCurrent) {
|
||||
_instance->killSession(MTP::configDcId(_enumCurrent));
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigLoader::terminateSpecialRequest() {
|
||||
if (_specialEnumRequest) {
|
||||
_instance->cancel(base::take(_specialEnumRequest));
|
||||
}
|
||||
if (_specialEnumCurrent) {
|
||||
_instance->killSession(_specialEnumCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
ConfigLoader::~ConfigLoader() {
|
||||
terminateRequest();
|
||||
terminateSpecialRequest();
|
||||
}
|
||||
|
||||
void ConfigLoader::enumerate() {
|
||||
terminateRequest();
|
||||
if (!_enumCurrent) {
|
||||
_enumCurrent = _instance->mainDcId();
|
||||
}
|
||||
auto ids = _instance->dcOptions().configEnumDcIds();
|
||||
Assert(!ids.empty());
|
||||
|
||||
auto i = std::find(ids.cbegin(), ids.cend(), _enumCurrent);
|
||||
if (i == ids.cend() || (++i) == ids.cend()) {
|
||||
_enumCurrent = ids.front();
|
||||
} else {
|
||||
_enumCurrent = *i;
|
||||
}
|
||||
_enumRequest = sendRequest(MTP::configDcId(_enumCurrent));
|
||||
|
||||
_enumDCTimer.callOnce(kEnumerateDcTimeout);
|
||||
|
||||
refreshSpecialLoader();
|
||||
}
|
||||
|
||||
void ConfigLoader::refreshSpecialLoader() {
|
||||
if (_proxyEnabled || _instance->isKeysDestroyer()) {
|
||||
_specialLoader.reset();
|
||||
return;
|
||||
}
|
||||
if (!_specialLoader
|
||||
|| (!_specialEnumRequest && _specialEndpoints.empty())) {
|
||||
createSpecialLoader();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigLoader::setPhone(const QString &phone) {
|
||||
if (_phone != phone) {
|
||||
_phone = phone;
|
||||
if (_specialLoader) {
|
||||
createSpecialLoader();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigLoader::createSpecialLoader() {
|
||||
const auto testMode = _instance->isTestMode();
|
||||
_triedSpecialEndpoints.clear();
|
||||
_specialLoader = std::make_unique<SpecialConfigRequest>([=](
|
||||
DcId dcId,
|
||||
const std::string &ip,
|
||||
int port,
|
||||
bytes::const_span secret) {
|
||||
if (ip.empty()) {
|
||||
_specialLoader = nullptr;
|
||||
} else {
|
||||
addSpecialEndpoint(dcId, ip, port, secret);
|
||||
}
|
||||
}, testMode, _instance->configValues().txtDomainString, _phone);
|
||||
}
|
||||
|
||||
void ConfigLoader::addSpecialEndpoint(
|
||||
DcId dcId,
|
||||
const std::string &ip,
|
||||
int port,
|
||||
bytes::const_span secret) {
|
||||
const auto endpoint = SpecialEndpoint {
|
||||
dcId,
|
||||
ip,
|
||||
port,
|
||||
bytes::make_vector(secret)
|
||||
};
|
||||
if (base::contains(_specialEndpoints, endpoint)
|
||||
|| base::contains(_triedSpecialEndpoints, endpoint)) {
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG(("MTP Info: Special endpoint received, '%1:%2'").arg(ip.c_str()).arg(port));
|
||||
_specialEndpoints.push_back(endpoint);
|
||||
|
||||
if (!_specialEnumTimer.isActive()) {
|
||||
_specialEnumTimer.callOnce(1);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigLoader::sendSpecialRequest() {
|
||||
terminateSpecialRequest();
|
||||
if (_proxyEnabled) {
|
||||
_specialLoader.reset();
|
||||
return;
|
||||
}
|
||||
if (_specialEndpoints.empty()) {
|
||||
refreshSpecialLoader();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto weak = base::make_weak(this);
|
||||
const auto index = base::RandomValue<uint32>() % _specialEndpoints.size();
|
||||
const auto endpoint = _specialEndpoints.begin() + index;
|
||||
_specialEnumCurrent = specialToRealDcId(endpoint->dcId);
|
||||
|
||||
using Flag = MTPDdcOption::Flag;
|
||||
const auto flags = Flag::f_tcpo_only
|
||||
| (endpoint->secret.empty() ? Flag(0) : Flag::f_secret);
|
||||
_instance->dcOptions().constructAddOne(
|
||||
_specialEnumCurrent,
|
||||
flags,
|
||||
endpoint->ip,
|
||||
endpoint->port,
|
||||
endpoint->secret);
|
||||
_specialEnumRequest = _instance->send(
|
||||
MTPhelp_GetConfig(),
|
||||
[weak](const Response &response) {
|
||||
auto result = MTPConfig();
|
||||
auto from = response.reply.constData();
|
||||
if (!result.read(from, from + response.reply.size())) {
|
||||
return false;
|
||||
}
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->specialConfigLoaded(result);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
base::duplicate(_failHandler),
|
||||
_specialEnumCurrent);
|
||||
_triedSpecialEndpoints.push_back(*endpoint);
|
||||
_specialEndpoints.erase(endpoint);
|
||||
|
||||
_specialEnumTimer.callOnce(kSpecialRequestTimeoutMs);
|
||||
}
|
||||
|
||||
void ConfigLoader::specialConfigLoaded(const MTPConfig &result) {
|
||||
Expects(result.type() == mtpc_config);
|
||||
|
||||
const auto &data = result.c_config();
|
||||
if (data.vdc_options().v.empty()) {
|
||||
LOG(("MTP Error: config with empty dc_options received!"));
|
||||
return;
|
||||
}
|
||||
|
||||
// We use special config only for dc options.
|
||||
// For everything else we wait for normal config from main dc.
|
||||
_instance->dcOptions().setFromList(data.vdc_options());
|
||||
}
|
||||
|
||||
void ConfigLoader::setProxyEnabled(bool value) {
|
||||
_proxyEnabled = value;
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace MTP
|
||||
Reference in New Issue
Block a user