From 06f5f7f7d93ab0de9df4bb67237055135fd1dcf0 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 27 Nov 2019 13:41:17 +0300 Subject: [PATCH] Don't always restart connection on config change. --- Telegram/SourceFiles/core/application.cpp | 20 +++++++++------ Telegram/SourceFiles/mtproto/connection.cpp | 24 +++++++++++++----- Telegram/SourceFiles/mtproto/connection.h | 3 ++- Telegram/SourceFiles/mtproto/dc_options.cpp | 25 +++++++++++-------- Telegram/SourceFiles/mtproto/dc_options.h | 11 +++----- Telegram/SourceFiles/mtproto/mtp_instance.cpp | 2 -- Telegram/SourceFiles/mtproto/mtp_instance.h | 1 - 7 files changed, 50 insertions(+), 36 deletions(-) diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 048a6794e..04a167751 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -399,14 +399,18 @@ void Application::badMtprotoConfigurationError() { void Application::startLocalStorage() { Local::start(); - subscribe(_dcOptions->changed(), [this](const MTP::DcOptions::Ids &ids) { - Local::writeSettings(); - if (const auto instance = activeAccount().mtp()) { - for (const auto id : ids) { - instance->restart(id); - } - } - }); + + const auto writing = _lifetime.make_state(false); + _dcOptions->changed( + ) | rpl::filter([=] { + return !*writing; + }) | rpl::start_with_next([=] { + *writing = true; + Ui::PostponeCall(this, [=] { + Local::writeSettings(); + }); + }, _lifetime); + _saveSettingsTimer.setCallback([=] { Local::writeSettings(); }); } diff --git a/Telegram/SourceFiles/mtproto/connection.cpp b/Telegram/SourceFiles/mtproto/connection.cpp index 80f4e478e..8e35f8977 100644 --- a/Telegram/SourceFiles/mtproto/connection.cpp +++ b/Telegram/SourceFiles/mtproto/connection.cpp @@ -126,7 +126,9 @@ Connection::~Connection() { } } -void Connection::start(std::shared_ptr sessionData, ShiftedDcId shiftedDcId) { +void Connection::start( + std::shared_ptr sessionData, + ShiftedDcId shiftedDcId) { Expects(_thread == nullptr && _private == nullptr); _thread = std::make_unique(); @@ -137,6 +139,16 @@ void Connection::start(std::shared_ptr sessionData, ShiftedDcId shi std::move(sessionData), shiftedDcId); + _instance->dcOptions()->changed( + ) | rpl::filter([=](DcId dcId) { + return (BareDcId(shiftedDcId) == dcId) && (_private != nullptr); + }) | rpl::start_with_next([=] { + const auto raw = _private; + InvokeQueued(raw, [=] { + raw->dcOptionsChanged(); + }); + }, _lifetime); + // will be deleted in the thread::finished signal _private = newData.release(); _thread->start(); @@ -329,10 +341,6 @@ ConnectionPrivate::~ConnectionPrivate() { Expects(_testConnections.empty()); } -void ConnectionPrivate::onConfigLoaded() { - connectToServer(true); -} - void ConnectionPrivate::onCDNConfigLoaded() { restart(); } @@ -341,6 +349,11 @@ int32 ConnectionPrivate::getShiftedDcId() const { return _shiftedDcId; } +void ConnectionPrivate::dcOptionsChanged() { + _retryTimeout = 1; + connectToServer(true); +} + int32 ConnectionPrivate::getState() const { QReadLocker lock(&_stateMutex); int32 result = _state; @@ -1004,7 +1017,6 @@ void ConnectionPrivate::connectToServer(bool afterConfig) { return restart(); } DEBUG_LOG(("MTP Info: DC %1 options not found, waiting for config").arg(_shiftedDcId)); - connect(_instance, SIGNAL(configLoaded()), this, SLOT(onConfigLoaded()), Qt::UniqueConnection); InvokeQueued(_instance, [instance = _instance] { instance->requestConfig(); }); diff --git a/Telegram/SourceFiles/mtproto/connection.h b/Telegram/SourceFiles/mtproto/connection.h index 2715bb640..fddd75bd7 100644 --- a/Telegram/SourceFiles/mtproto/connection.h +++ b/Telegram/SourceFiles/mtproto/connection.h @@ -58,6 +58,7 @@ private: not_null _instance; std::unique_ptr _thread; ConnectionPrivate *_private = nullptr; + rpl::lifetime _lifetime; }; @@ -76,6 +77,7 @@ public: void stop(); int32 getShiftedDcId() const; + void dcOptionsChanged(); int32 getState() const; QString transport() const; @@ -90,7 +92,6 @@ public slots: void updateAuthKey(); - void onConfigLoaded(); void onCDNConfigLoaded(); private: diff --git a/Telegram/SourceFiles/mtproto/dc_options.cpp b/Telegram/SourceFiles/mtproto/dc_options.cpp index 7e22e4c5b..cbac04e31 100644 --- a/Telegram/SourceFiles/mtproto/dc_options.cpp +++ b/Telegram/SourceFiles/mtproto/dc_options.cpp @@ -170,7 +170,7 @@ void DcOptions::processFromList( ApplyOneOption(data, dcId, flags, ip, port, secret); } - auto difference = [&] { + const auto difference = [&] { WriteLocker lock(this); auto result = CountOptionsDifference(_data, data); if (!result.empty()) { @@ -178,8 +178,8 @@ void DcOptions::processFromList( } return result; }(); - if (!difference.empty()) { - _changed.notify(std::move(difference)); + for (const auto dcId : difference) { + _changed.fire_copy(dcId); } } @@ -232,9 +232,8 @@ void DcOptions::addFromOther(DcOptions &&options) { } } } - - if (!idsChanged.empty()) { - _changed.notify(std::move(idsChanged)); + for (const auto dcId : idsChanged) { + _changed.fire_copy(dcId); } } @@ -280,10 +279,10 @@ bool DcOptions::ApplyOneOption( return true; } -auto DcOptions::CountOptionsDifference( +std::vector DcOptions::CountOptionsDifference( const std::map> &a, - const std::map> &b) -> Ids { - auto result = Ids(); + const std::map> &b) { + auto result = std::vector(); const auto find = []( const std::vector &where, const Endpoint &what) { @@ -514,8 +513,12 @@ void DcOptions::constructFromSerialized(const QByteArray &serialized) { } } -DcOptions::Ids DcOptions::configEnumDcIds() const { - auto result = Ids(); +rpl::producer DcOptions::changed() const { + return _changed.events(); +} + +std::vector DcOptions::configEnumDcIds() const { + auto result = std::vector(); { ReadLocker lock(this); result.reserve(_data.size()); diff --git a/Telegram/SourceFiles/mtproto/dc_options.h b/Telegram/SourceFiles/mtproto/dc_options.h index 70b7a79dd..4c21e5567 100644 --- a/Telegram/SourceFiles/mtproto/dc_options.h +++ b/Telegram/SourceFiles/mtproto/dc_options.h @@ -66,15 +66,12 @@ public: const bytes::vector &secret); QByteArray serialize() const; - using Ids = std::vector; - base::Observable &changed() const { - return _changed; - } + [[nodiscard]] rpl::producer changed() const; void setFromList(const MTPVector &options); void addFromList(const MTPVector &options); void addFromOther(DcOptions &&options); - Ids configEnumDcIds() const; + [[nodiscard]] std::vector configEnumDcIds() const; struct Variants { enum Address { @@ -119,7 +116,7 @@ private: const std::string &ip, int port, const bytes::vector &secret); - static Ids CountOptionsDifference( + static std::vector CountOptionsDifference( const std::map> &a, const std::map> &b); static void FilterIfHasWithFlag(Variants &variants, Flag flag); @@ -143,7 +140,7 @@ private: std::map> _cdnPublicKeys; mutable QReadWriteLock _useThroughLockers; - mutable base::Observable _changed; + rpl::event_stream _changed; // True when we have overriden options from a .tdesktop-endpoints file. bool _immutable = false; diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.cpp b/Telegram/SourceFiles/mtproto/mtp_instance.cpp index 5bef40a88..3f4a91e63 100644 --- a/Telegram/SourceFiles/mtproto/mtp_instance.cpp +++ b/Telegram/SourceFiles/mtproto/mtp_instance.cpp @@ -860,8 +860,6 @@ void Instance::Private::configLoadDone(const MTPConfig &result) { _configExpiresAt = crl::now() + (data.vexpires().v - base::unixtime::now()) * crl::time(1000); requestConfigIfExpired(); - - emit _instance->configLoaded(); } bool Instance::Private::configLoadFail(const RPCError &error) { diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.h b/Telegram/SourceFiles/mtproto/mtp_instance.h index 17e2f5889..f28f635cc 100644 --- a/Telegram/SourceFiles/mtproto/mtp_instance.h +++ b/Telegram/SourceFiles/mtproto/mtp_instance.h @@ -199,7 +199,6 @@ public: } signals: - void configLoaded(); void cdnConfigLoaded(); void allKeysDestroyed(); void proxyDomainResolved(