From 1f6cd37169943413029763652550d8ddb32e8af2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 14 Apr 2021 13:50:22 +0400 Subject: [PATCH 001/350] Test linking with TDLib on Windows. --- Telegram/CMakeLists.txt | 2 + Telegram/SourceFiles/intro/intro_widget.cpp | 18 ++ Telegram/SourceFiles/tdb/tdb_instance.cpp | 240 ++++++++++++++++++++ Telegram/SourceFiles/tdb/tdb_instance.h | 37 +++ Telegram/SourceFiles/tdb/tdb_pch.h | 17 ++ Telegram/build/prepare/prepare.py | 48 ++++ Telegram/cmake/td_tdb.cmake | 28 +++ 7 files changed, 390 insertions(+) create mode 100644 Telegram/SourceFiles/tdb/tdb_instance.cpp create mode 100644 Telegram/SourceFiles/tdb/tdb_instance.h create mode 100644 Telegram/SourceFiles/tdb/tdb_pch.h create mode 100644 Telegram/cmake/td_tdb.cmake diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index bd1035359b992..29330692ae5a6 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -33,6 +33,7 @@ include(cmake/td_export.cmake) include(cmake/td_mtproto.cmake) include(cmake/td_lang.cmake) include(cmake/td_scheme.cmake) +include(cmake/td_tdb.cmake) include(cmake/td_ui.cmake) include(cmake/generate_appdata_changelog.cmake) @@ -65,6 +66,7 @@ PRIVATE tdesktop::td_mtproto tdesktop::td_lang tdesktop::td_scheme + tdesktop::td_tdb tdesktop::td_ui desktop-app::lib_webrtc desktop-app::lib_base diff --git a/Telegram/SourceFiles/intro/intro_widget.cpp b/Telegram/SourceFiles/intro/intro_widget.cpp index 13ba4837b7dc2..3164aa0573a11 100644 --- a/Telegram/SourceFiles/intro/intro_widget.cpp +++ b/Telegram/SourceFiles/intro/intro_widget.cpp @@ -46,6 +46,9 @@ For license and copyright information please follow this link: #include "styles/style_intro.h" #include "base/qt/qt_common_adapters.h" +#include "tdb/tdb_instance.h" +#include "ui/toast/toast.h" + namespace Intro { namespace { @@ -65,6 +68,8 @@ using namespace ::Intro::details; return Platform::SystemCountry(); } +std::unique_ptr Instance; + } // namespace Widget::Widget( @@ -92,6 +97,18 @@ Widget::Widget( rpl::single(true))) { controller->setDefaultFloatPlayerDelegate(floatPlayerDelegate()); + Instance = std::make_unique(Tdb::InstanceConfig{ + .apiId = ApiId, + .apiHash = ApiHash, + .systemLanguageCode = Lang::GetInstance().systemLangCode(), + .deviceModel = Platform::DeviceModelPretty(), + .systemVersion = Platform::SystemVersionPretty(), + .applicationVersion = QString::fromLatin1(AppVersionStr), + }); + Instance->testNetwork([](bool success) { + Ui::Toast::Show(u"TDLib Network "_q + (success ? "OK!" : "Fail :(")); + }); + getData()->country = ComputeNewAccountCountry(); _account->mtpValue( @@ -856,6 +873,7 @@ void Widget::backRequested() { } Widget::~Widget() { + Instance = nullptr; for (auto step : base::take(_stepHistory)) { delete step; } diff --git a/Telegram/SourceFiles/tdb/tdb_instance.cpp b/Telegram/SourceFiles/tdb/tdb_instance.cpp new file mode 100644 index 0000000000000..64ec677a0c6fe --- /dev/null +++ b/Telegram/SourceFiles/tdb/tdb_instance.cpp @@ -0,0 +1,240 @@ +/* +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 "tdb/tdb_instance.h" + +#include "td/actor/actor.h" +#include "td/telegram/Client.h" + +#include + +namespace Tdb { +namespace { + +using namespace td; +using ClientId = ClientManager::ClientId; +using RequestId = ClientManager::RequestId; + +namespace api = td_api; + +} // namespace + +class Instance::Manager final + : public std::enable_shared_from_this { + struct PrivateTag { + }; + +public: + Manager(PrivateTag); + [[nodiscard]] static std::shared_ptr Instance(); + + [[nodiscard]] ClientId createClient(not_null impl); + void destroyClient(ClientId id); + + RequestId send( + ClientId id, + api::object_ptr request); + +private: + void loop(); + + const not_null _manager; + std::jthread _thread; + base::flat_map> _clients; + RequestId _requestId = 0; + std::atomic _closingId = 0; + crl::semaphore _closing; + +}; + +class Instance::Impl final { +public: + explicit Impl(InstanceConfig &&config); + ~Impl(); + + void testNetwork(Fn done); + + void received(RequestId id, api::object_ptr result); + +private: + RequestId send(api::object_ptr request); + + void sendTdlibParameters(InstanceConfig &&config); + + void handleUpdateAuthorizationState( + api::object_ptr state); + + const std::shared_ptr _manager; + ClientManager::ClientId _client; + base::flat_map> _callbacks; + +}; + +std::weak_ptr Instance::ManagerInstance; + +Instance::Manager::Manager(PrivateTag) +: _manager(ClientManager::get_manager_singleton()) +, _thread([=] { loop(); }) { +} + +std::shared_ptr Instance::Manager::Instance() { + auto result = ManagerInstance.lock(); + if (!result) { + ManagerInstance = result = std::make_shared(PrivateTag{}); + } + return result; +} + +[[nodiscard]] ClientId Instance::Manager::createClient( + not_null impl) { + const auto result = _manager->create_client_id(); + _clients.emplace(result, impl); + return result; +} + +void Instance::Manager::destroyClient(ClientId id) { + Expects(!_closingId); + + _closingId = id; + _manager->send(id, ++_requestId, api::make_object()); + _closing.acquire(); + _clients.erase(id); + + if (_clients.empty()) { + _thread.request_stop(); + + // Force wake. + _manager->send( + id, + ++_requestId, + api::make_object()); + } +} + +RequestId Instance::Manager::send( + ClientId id, + api::object_ptr request) { + Expects(_clients.contains(id)); + + _manager->send(id, ++_requestId, std::move(request)); + return _requestId; +} + +void Instance::Manager::loop() { + while (!_thread.get_stop_source().stop_requested()) { + auto response = _manager->receive(60.); + if (!response.object) { + continue; + } + if (response.object->get_id() == api::updateAuthorizationState::ID) { + const auto update = static_cast( + response.object.get()); + const auto state = update->authorization_state_.get(); + if (state->get_id() == api::authorizationStateClosed::ID) { + Assert(_closingId == response.client_id); + _closingId = 0; + _closing.release(); + continue; + } + } else if (response.object->get_id() == api::error::ID) { + const auto error = static_cast( + response.object.get()); + if (error->code_ == 500 + && error->message_ == "Request aborted.") { + continue; + } + } + auto handleOnMain = [this, data = std::move(response)]() mutable { + const auto i = _clients.find(data.client_id); + if (i == end(_clients)) { + return; + } + i->second->received(data.request_id, std::move(data.object)); + }; + crl::on_main(weak_from_this(), std::move(handleOnMain)); + } +} + +Instance::Impl::Impl(InstanceConfig &&config) +: _manager(Manager::Instance()) +, _client(_manager->createClient(this)) { + sendTdlibParameters(std::move(config)); +} + +Instance::Impl::~Impl() { + _manager->destroyClient(_client); +} + +void Instance::Impl::testNetwork(Fn done) { + const auto id = _manager->send( + _client, + api::make_object()); + _callbacks.emplace(id, std::move(done)); +} + +void Instance::Impl::received( + RequestId id, + api::object_ptr result) { + if (!id) { + if (result->get_id() == api::updateAuthorizationState::ID) { + handleUpdateAuthorizationState( + std::move(static_cast( + result.get())->authorization_state_)); + } + } else if (const auto callback = _callbacks.take(id)) { + (*callback)(result->get_id() != api::error::ID); + } +} + +RequestId Instance::Impl::send(api::object_ptr request) { + return _manager->send(_client, std::move(request)); +} + +void Instance::Impl::sendTdlibParameters(InstanceConfig &&config) { + send(api::make_object( + api::make_object( + false, // use_test_dc + std::string(), // database_directory + std::string(), // files_directory + true, // use_file_database + true, // use_chat_info_database + true, // use_message_database + false, // use_secret_chats + config.apiId, + config.apiHash.toStdString(), + config.systemLanguageCode.toStdString(), + config.deviceModel.toStdString(), + config.systemVersion.toStdString(), + config.applicationVersion.toStdString(), + true, // enable_storage_optimizer + false))); // ignore_file_names +} + +void Instance::Impl::handleUpdateAuthorizationState( + api::object_ptr state) { + switch (state->get_id()) { + case api::authorizationStateWaitTdlibParameters::ID: + //sendTdlibParameters(); // Should happen only once. + break; + + case api::authorizationStateWaitEncryptionKey::ID: + send(api::make_object()); + break; + } +} + +Instance::Instance(InstanceConfig &&config) +: _impl(std::make_unique(std::move(config))) { +} + +Instance::~Instance() = default; + +void Instance::testNetwork(Fn done) { + _impl->testNetwork(std::move(done)); +} + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/tdb_instance.h b/Telegram/SourceFiles/tdb/tdb_instance.h new file mode 100644 index 0000000000000..3b8b9764c70be --- /dev/null +++ b/Telegram/SourceFiles/tdb/tdb_instance.h @@ -0,0 +1,37 @@ +/* +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 +*/ +#pragma once + +namespace Tdb { + +struct InstanceConfig { + int32 apiId = 0; + QString apiHash; + QString systemLanguageCode; + QString deviceModel; + QString systemVersion; + QString applicationVersion; +}; + +class Instance final { +public: + explicit Instance(InstanceConfig &&config); + ~Instance(); + + void testNetwork(Fn done); + +private: + class Manager; + class Impl; + const std::unique_ptr _impl; + + static std::weak_ptr ManagerInstance; + +}; + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/tdb_pch.h b/Telegram/SourceFiles/tdb/tdb_pch.h new file mode 100644 index 0000000000000..ff199ddb6bf28 --- /dev/null +++ b/Telegram/SourceFiles/tdb/tdb_pch.h @@ -0,0 +1,17 @@ +/* +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 + +#include + +#include +#include + +#include "base/basic_types.h" +#include "base/flat_map.h" +#include "base/flat_set.h" diff --git a/Telegram/build/prepare/prepare.py b/Telegram/build/prepare/prepare.py index 67a570d0249f5..fbd60140920a9 100644 --- a/Telegram/build/prepare/prepare.py +++ b/Telegram/build/prepare/prepare.py @@ -1568,6 +1568,54 @@ def runStages(): # -Dprotobuf_WITH_ZLIB_DEFAULT=OFF # cmake --build . $MAKE_THREADS_CNT +stage('td', """ +win: + git clone https://github.com/tdlib/td.git + cd td + git checkout c582ab0bbf +depends:patches/tdlib/*.patch + for /r %%i in (..\\patches\\tdlib\\*) do git apply %%i + SET OPENSSL_DIR=%LIBS_DIR%\\openssl + SET OPENSSL_LIBS_DIR=%OPENSSL_DIR%\\out + SET ZLIB_DIR=%LIBS_DIR%\\zlib + SET ZLIB_LIBS_DIR=%LIBS_DIR%\\zlib\\contrib\\vstudio\\vc14\\%X8664% + mkdir out + cd out + mkdir Debug + cd Debug + cmake -A Win32 ^ + -DOPENSSL_FOUND=1 ^ + -DOPENSSL_INCLUDE_DIR=%OPENSSL_DIR%\include ^ + -DOPENSSL_CRYPTO_LIBRARY="%OPENSSL_LIBS_DIR%.dbg\libcrypto.lib" ^ + -DZLIB_FOUND=1 ^ + -DZLIB_INCLUDE_DIR=%ZLIB_DIR% ^ + -DZLIB_LIBRARIES="%ZLIB_LIBS_DIR%\ZlibStatDebug\zlibstat.lib" ^ + -DCMAKE_CXX_FLAGS_DEBUG="/DZLIB_WINAPI /DNDEBUG /MTd /Zi /Od /Ob0" ^ + -DCMAKE_C_FLAGS_DEBUG="/DNDEBUG /MTd /Zi /Od /Ob0" ^ + -DCMAKE_EXE_LINKER_FLAGS="/SAFESEH:NO Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib %OPENSSL_LIBS_DIR%.dbg\libssl.lib" ^ + -DCMAKE_SHARED_LINKER_FLAGS="/SAFESEH:NO Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib %OPENSSL_LIBS_DIR%.dbg\libssl.lib" ^ + -DTD_ENABLE_MULTI_PROCESSOR_COMPILATION=ON ^ + ../.. + cmake --build . --config Debug --target tdclient + cd .. + mkdir Release + cd Release + cmake -A Win32 ^ + -DOPENSSL_FOUND=1 ^ + -DOPENSSL_INCLUDE_DIR=%OPENSSL_DIR%\include ^ + -DOPENSSL_CRYPTO_LIBRARY="%OPENSSL_LIBS_DIR%\libcrypto.lib" ^ + -DZLIB_FOUND=1 ^ + -DZLIB_INCLUDE_DIR=%ZLIB_DIR% ^ + -DZLIB_LIBRARIES="%ZLIB_LIBS_DIR%\ZlibStatDebug\zlibstat.lib" ^ + -DCMAKE_CXX_FLAGS_RELEASE="/DZLIB_WINAPI /MT /Ob2" ^ + -DCMAKE_C_FLAGS_RELEASE="/MT /Ob2" ^ + -DCMAKE_EXE_LINKER_FLAGS="/SAFESEH:NO Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib %OPENSSL_LIBS_DIR%\libssl.lib" ^ + -DCMAKE_SHARED_LINKER_FLAGS="/SAFESEH:NO Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib %OPENSSL_LIBS_DIR%\libssl.lib" ^ + -DTD_ENABLE_MULTI_PROCESSOR_COMPILATION=ON ^ + ../.. + cmake --build . --config Release --target tdclient +""") + if win: currentCodePage = subprocess.run('chcp', capture_output=True, shell=True, text=True, env=modifiedEnv).stdout.strip().split()[-1] subprocess.run('chcp 65001 > nul', shell=True, env=modifiedEnv) diff --git a/Telegram/cmake/td_tdb.cmake b/Telegram/cmake/td_tdb.cmake new file mode 100644 index 0000000000000..8f9d5b9bae82d --- /dev/null +++ b/Telegram/cmake/td_tdb.cmake @@ -0,0 +1,28 @@ +# 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 + +add_library(td_tdb OBJECT) +init_target(td_tdb) +add_library(tdesktop::td_tdb ALIAS td_tdb) + +target_precompile_headers(td_tdb PRIVATE ${src_loc}/tdb/tdb_pch.h) +nice_target_sources(td_tdb ${src_loc} +PRIVATE + tdb/tdb_instance.cpp + tdb/tdb_instance.h +) + +target_include_directories(td_tdb +PUBLIC + ${src_loc} +) + +target_link_libraries(td_tdb +PUBLIC + desktop-app::lib_base +PRIVATE + desktop-app::external_td +) From e6b2049b872ed11aa9a48cd44a7aa50e0210b836 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 15 Apr 2021 12:17:24 +0400 Subject: [PATCH 002/350] Use lib_tl codegen for TDLib API. --- Telegram/SourceFiles/intro/intro_widget.cpp | 6 +- .../SourceFiles/tdb/details/tdb_tl_core.h | 130 +++++++++ .../details/tdb_tl_core_conversion_from.cpp | 32 +++ .../tdb/details/tdb_tl_core_conversion_from.h | 45 +++ .../tdb/details/tdb_tl_core_conversion_to.cpp | 32 +++ .../tdb/details/tdb_tl_core_conversion_to.h | 79 +++++ .../tdb/details/tdb_tl_generate.py | 66 +++++ Telegram/SourceFiles/tdb/tdb_instance.cpp | 271 ++++++++++++------ Telegram/SourceFiles/tdb/tdb_instance.h | 66 ++++- Telegram/SourceFiles/tdb/tdb_pch.h | 2 + Telegram/SourceFiles/tdb/tdb_tl_scheme.h | 37 +++ Telegram/cmake/generate_tdb_tl.cmake | 41 +++ Telegram/cmake/td_tdb.cmake | 15 + 13 files changed, 731 insertions(+), 91 deletions(-) create mode 100644 Telegram/SourceFiles/tdb/details/tdb_tl_core.h create mode 100644 Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp create mode 100644 Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h create mode 100644 Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp create mode 100644 Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h create mode 100644 Telegram/SourceFiles/tdb/details/tdb_tl_generate.py create mode 100644 Telegram/SourceFiles/tdb/tdb_tl_scheme.h create mode 100644 Telegram/cmake/generate_tdb_tl.cmake diff --git a/Telegram/SourceFiles/intro/intro_widget.cpp b/Telegram/SourceFiles/intro/intro_widget.cpp index 3164aa0573a11..f276792426ec4 100644 --- a/Telegram/SourceFiles/intro/intro_widget.cpp +++ b/Telegram/SourceFiles/intro/intro_widget.cpp @@ -105,8 +105,10 @@ Widget::Widget( .systemVersion = Platform::SystemVersionPretty(), .applicationVersion = QString::fromLatin1(AppVersionStr), }); - Instance->testNetwork([](bool success) { - Ui::Toast::Show(u"TDLib Network "_q + (success ? "OK!" : "Fail :(")); + Instance->send(Tdb::TLtestNetwork(), [](const Tdb::TLok &result) { + Ui::Toast::Show(u"TDLib Network OK!"_q); + }, [](const Tdb::Error &error) { + Ui::Toast::Show(u"TDLib Network Fail: "_q + error.message); }); getData()->country = ComputeNewAccountCountry(); diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h new file mode 100644 index 0000000000000..c1f907472136f --- /dev/null +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h @@ -0,0 +1,130 @@ +/* +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 +*/ +#pragma once + +#include "tl/tl_basic_types.h" +#include "base/match_method.h" + +namespace td::tl { +template +class unique_ptr; +} // namespace td::tl + +namespace td::td_api { +class Object; +class Function; +} // namespace td::td_api + +namespace Tdb { + +using TLint32 = tl::int_type; +using TLint53 = tl::int64_type; +using TLint64 = tl::int64_type; +using TLdouble = tl::double_type; +using TLstring = tl::string_type; +using TLbytes = tl::bytes_type; +template +using TLvector = tl::vector_type; + +inline TLint32 tl_int32(int32 value) { + return tl::make_int(value); +} +inline TLint53 tl_int53(int64 value) { + return tl::make_int64(value); +} +inline TLint64 tl_int64(int64 value) { + return tl::make_int64(value); +} +inline TLdouble tl_double(float64 value) { + return tl::make_double(value); +} +inline TLstring tl_string(const std::string &v) { + return tl::make_string(v); +} +inline TLstring tl_string(const QString &v) { + return tl::make_string(v); +} +inline TLbytes tl_string(const QByteArray &v) { + return tl::make_string(v); +} +inline TLstring tl_string(const char *v) { + return tl::make_string(v); +} +inline TLstring tl_string() { + return tl::make_string(); +} +inline TLbytes tl_bytes(const QByteArray &v) { + return tl::make_bytes(v); +} +inline TLbytes tl_bytes(QByteArray &&v) { + return tl::make_bytes(std::move(v)); +} +inline TLbytes tl_bytes() { + return tl::make_bytes(); +} +inline TLbytes tl_bytes(bytes::const_span buffer) { + return tl::make_bytes(buffer); +} +inline TLbytes tl_bytes(const bytes::vector &buffer) { + return tl::make_bytes(buffer); +} +template +inline TLvector tl_vector(uint32 count) { + return tl::make_vector(count); +} +template +inline TLvector tl_vector(uint32 count, const T &value) { + return tl::make_vector(count, value); +} +template +inline TLvector tl_vector(const QVector &v) { + return tl::make_vector(v); +} +template +inline TLvector tl_vector(QVector &&v) { + return tl::make_vector(std::move(v)); +} +template +inline TLvector tl_vector() { + return tl::make_vector(); +} + +using ExternalRequest = ::td::td_api::Function*; +using ExternalResponse = const ::td::td_api::Object*; +using ExternalGenerator = Fn; +using ExternalCallback = FnMut(ExternalResponse)>; + +template +[[nodiscard]] ExternalGenerator tl_to_generator(Request &&); + +template +[[nodiscard]] Response tl_from(ExternalResponse); + +template +struct is_TLvector : std::bool_constant { +}; + +template +struct is_TLvector> : std::bool_constant { +}; + +template +inline constexpr bool is_TLvector_v = is_TLvector::value; + +template +struct in_TLvector; + +template +struct in_TLvector> { + using type = T; +}; + +template +using in_TLvector_t = typename in_TLvector::type; + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp new file mode 100644 index 0000000000000..f014f00363f90 --- /dev/null +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp @@ -0,0 +1,32 @@ +/* +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 "tdb/details/tdb_tl_core_conversion_from.h" + +namespace Tdb { + +TLstring tl_from_simple(const std::string &value) { + return tl_string(value); +} + +TLint32 tl_from_simple(std::int32_t value) { + return tl_int32(value); +} + +TLint64 tl_from_simple(std::int64_t value) { + return tl_int64(value); +} + +TLdouble tl_from_simple(double value) { + return tl_double(value); +} + +TLbool tl_from_simple(bool value) { + return value ? tl_boolTrue() : tl_boolFalse(); +} + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h new file mode 100644 index 0000000000000..505f0f9178a3e --- /dev/null +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h @@ -0,0 +1,45 @@ +/* +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 +*/ +#pragma once + +#include "td/telegram/td_api.h" +#include "tdb/details/tdb_tl_core.h" +#include "tdb_tl-scheme.h" + +namespace Tdb { + +TLstring tl_from_simple(const std::string &value); +TLint32 tl_from_simple(std::int32_t value); +TLint64 tl_from_simple(std::int64_t value); +TLdouble tl_from_simple(double value); +TLbool tl_from_simple(bool value); + +template +auto tl_from_vector(const std::vector &value) { + using I = in_TLvector_t; + auto result = QVector(); + result.reserve(value.size()); + constexpr bool simple = std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v; + constexpr bool vector = !simple && is_TLvector_v; + for (const auto &element : value) { + if constexpr (simple) { + result.push_back(tl_from_simple(element)); + } else if constexpr (vector) { + result.push_back(tl_from_vector(element)); + } else { + result.push_back(tl_from(element.get())); + } + } + return tl_vector(std::move(result)); +} + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp new file mode 100644 index 0000000000000..f67f30307396d --- /dev/null +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp @@ -0,0 +1,32 @@ +/* +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 "tdb/details/tdb_tl_core_conversion_to.h" + +namespace Tdb { + +std::string tl_to_simple(const TLstring &value) { + return std::string(value.v.data(), value.v.size()); +} + +std::int32_t tl_to_simple(const TLint32 &value) { + return value.v; +} + +std::int64_t tl_to_simple(const TLint64 &value) { + return value.v; +} + +double tl_to_simple(const TLdouble &value) { + return value.v; +} + +bool tl_to_simple(const TLbool &value) { + return (value.type() == id_boolTrue); +} + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h new file mode 100644 index 0000000000000..76679eb4ab8bd --- /dev/null +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h @@ -0,0 +1,79 @@ +/* +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 +*/ +#pragma once + +#include "tdb/details/tdb_tl_core.h" +#include "tdb_tl-scheme.h" + +namespace Tdb { + +std::string tl_to_simple(const TLstring &value); +std::int32_t tl_to_simple(const TLint32 &value); +std::int64_t tl_to_simple(const TLint64 &value); +double tl_to_simple(const TLdouble &value); +bool tl_to_simple(const TLbool &value); + +template +struct tl_to_type + : std::type_identity< + ::td::tl::unique_ptr< + std::remove_pointer_t()))>>> { +}; + +template +using tl_to_type_t = typename tl_to_type::type; + +template <> +struct tl_to_type : std::type_identity { +}; + +template <> +struct tl_to_type : std::type_identity { +}; + +template <> +struct tl_to_type : std::type_identity { +}; + +template <> +struct tl_to_type : std::type_identity { +}; + +template <> +struct tl_to_type : std::type_identity { +}; + +template +struct tl_to_type> + : std::type_identity>> { +}; + +template +auto tl_to_vector(const TLvector &value) { + constexpr bool simple = std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v; + constexpr bool vector = !simple && is_TLvector_v; + using U = tl_to_type_t; + auto result = std::vector(); + result.reserve(value.v.size()); + for (const auto &element : value.v) { + if constexpr (simple) { + result.push_back(tl_to_simple(element)); + } else if constexpr (vector) { + result.push_back(tl_to_vector(element)); + } else { + result.push_back(U(tl_to(element))); + } + } + return result; +} + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_generate.py b/Telegram/SourceFiles/tdb/details/tdb_tl_generate.py new file mode 100644 index 0000000000000..aac583e079a8f --- /dev/null +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_generate.py @@ -0,0 +1,66 @@ +# 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 + +import glob, re, binascii, os, sys + +sys.dont_write_bytecode = True +scriptPath = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(scriptPath + '/../../../lib_tl/tl') +from generate_tl import generate + +generate({ + 'namespaces': { + 'global': 'Tdb', + }, + 'prefixes': { + 'type': 'TL', + 'data': 'TLD', + 'id': 'id', + 'construct': 'tl_', + }, + 'types': { + 'typeId': 'uint32', + }, + 'sections': [ + ], + + 'skip': [ + 'double ? = Double;', + 'string ? = String;', + + 'int32 = Int32;', + 'int53 = Int53;', + 'int64 = Int64;', + 'bytes = Bytes;', + + 'vector {t:Type} # [ t ] = Vector t;', + ], + 'builtin': [ + 'double', + 'string', + 'int32', + 'int53', + 'int64', + 'bytes', + ], + 'builtinTemplates': [ + 'vector', + ], + 'builtinInclude': 'tdb/details/tdb_tl_core.h', + 'nullable': [ + ], + + 'conversion': { + 'include': 'td/telegram/td_api.h', + 'namespace': 'td::td_api', + 'builtinAdditional': [ + 'bool', + ], + 'builtinIncludeFrom': 'tdb/details/tdb_tl_core_conversion_from.h', + 'builtinIncludeTo': 'tdb/details/tdb_tl_core_conversion_to.h', + }, + +}) diff --git a/Telegram/SourceFiles/tdb/tdb_instance.cpp b/Telegram/SourceFiles/tdb/tdb_instance.cpp index 64ec677a0c6fe..3c05f801c4c19 100644 --- a/Telegram/SourceFiles/tdb/tdb_instance.cpp +++ b/Telegram/SourceFiles/tdb/tdb_instance.cpp @@ -7,22 +7,32 @@ For license and copyright information please follow this link: */ #include "tdb/tdb_instance.h" -#include "td/actor/actor.h" -#include "td/telegram/Client.h" - +#include #include +#include +#include -namespace Tdb { namespace { -using namespace td; +using namespace ::td; using ClientId = ClientManager::ClientId; -using RequestId = ClientManager::RequestId; - namespace api = td_api; } // namespace +namespace Tdb::details { + +std::optional ParseError(ExternalResponse response) { + if (response->get_id() != api::error::ID) { + return std::nullopt; + } + return Error(tl_from(response)); +} + +} // namespace Tdb::details + +namespace Tdb { + class Instance::Manager final : public std::enable_shared_from_this { struct PrivateTag { @@ -35,17 +45,29 @@ class Instance::Manager final [[nodiscard]] ClientId createClient(not_null impl); void destroyClient(ClientId id); - RequestId send( + // Thread-safe. + [[nodiscard]] RequestId allocateRequestId(); + void send( ClientId id, - api::object_ptr request); + RequestId allocatedRequestId, + ExternalGenerator &&request, + ExternalCallback &&callback); private: + void sendToExternal( + ClientId id, + api::object_ptr request, + RequestId requestId = 0); void loop(); const not_null _manager; std::jthread _thread; base::flat_map> _clients; - RequestId _requestId = 0; + + QMutex _mutex; + base::flat_map _callbacks; + + std::atomic _requestIdCounter = 0; std::atomic _closingId = 0; crl::semaphore _closing; @@ -56,21 +78,34 @@ class Instance::Impl final { explicit Impl(InstanceConfig &&config); ~Impl(); - void testNetwork(Fn done); + RequestId sendPrepared( + ExternalGenerator &&request, + ExternalCallback &&callback); + void cancel(RequestId requestId); + [[nodiscard]] bool shouldInvokeHandler(RequestId requestId); + + template < + typename Request, + typename = std::enable_if_t>> + RequestId send( + Request &&request, + FnMut &&done, + FnMut &&fail) { + return sendPrepared( + tl_to_generator(std::move(request)), + details::PrepareCallback( + std::move(done), + std::move(fail))); + } - void received(RequestId id, api::object_ptr result); + void handleUpdate(const TLupdate &update); private: - RequestId send(api::object_ptr request); - void sendTdlibParameters(InstanceConfig &&config); - void handleUpdateAuthorizationState( - api::object_ptr state); - const std::shared_ptr _manager; ClientManager::ClientId _client; - base::flat_map> _callbacks; + base::flat_set _activeRequests; }; @@ -100,28 +135,45 @@ void Instance::Manager::destroyClient(ClientId id) { Expects(!_closingId); _closingId = id; - _manager->send(id, ++_requestId, api::make_object()); + sendToExternal(id, api::make_object()); _closing.acquire(); - _clients.erase(id); + _clients.remove(id); if (_clients.empty()) { _thread.request_stop(); // Force wake. - _manager->send( - id, - ++_requestId, - api::make_object()); + sendToExternal(id, api::make_object()); } } -RequestId Instance::Manager::send( - ClientId id, - api::object_ptr request) { - Expects(_clients.contains(id)); +RequestId Instance::Manager::allocateRequestId() { + return ++_requestIdCounter; +} - _manager->send(id, ++_requestId, std::move(request)); - return _requestId; +void Instance::Manager::send( + ClientId clientId, + RequestId allocatedRequestId, + ExternalGenerator &&request, + ExternalCallback &&callback) { + if (callback) { + QMutexLocker lock(&_mutex); + _callbacks.emplace(allocatedRequestId, std::move(callback)); + } + sendToExternal( + clientId, + api::object_ptr(request()), + allocatedRequestId); +} + +void Instance::Manager::sendToExternal( + ClientId id, + api::object_ptr request, + RequestId requestId) { + if (!requestId) { + requestId = allocateRequestId(); + } + _manager->send(id, requestId, std::move(request)); } void Instance::Manager::loop() { @@ -148,14 +200,42 @@ void Instance::Manager::loop() { continue; } } - auto handleOnMain = [this, data = std::move(response)]() mutable { - const auto i = _clients.find(data.client_id); - if (i == end(_clients)) { - return; + const auto clientId = response.client_id; + const auto requestId = response.request_id; + const auto object = response.object.get(); + if (!requestId) { + crl::on_main(weak_from_this(), [ + this, + clientId, + update = tl_from(object) + ] { + const auto i = _clients.find(clientId); + if (i != end(_clients)) { + i->second->handleUpdate(update); + } + }); + continue; + } + QMutexLocker lock(&_mutex); + auto callback = _callbacks.take(requestId); + lock.unlock(); + + if (!callback) { + continue; + } + crl::on_main(weak_from_this(), [ + this, + clientId, + requestId, + handler = (*callback)({ object }) + ]() mutable { + const auto i = _clients.find(clientId); + if (i != end(_clients) + && i->second->shouldInvokeHandler(requestId) + && handler) { + handler(); } - i->second->received(data.request_id, std::move(data.object)); - }; - crl::on_main(weak_from_this(), std::move(handleOnMain)); + }); } } @@ -169,62 +249,71 @@ Instance::Impl::~Impl() { _manager->destroyClient(_client); } -void Instance::Impl::testNetwork(Fn done) { - const auto id = _manager->send( - _client, - api::make_object()); - _callbacks.emplace(id, std::move(done)); +RequestId Instance::Impl::sendPrepared( + ExternalGenerator &&request, + ExternalCallback &&callback) { + const auto requestId = _manager->allocateRequestId(); + if (callback) { + _activeRequests.emplace(requestId); + } + crl::async([ + manager = _manager, + clientId = _client, + requestId, + request = std::move(request), + callback = std::move(callback) + ]() mutable { + manager->send( + clientId, + requestId, + std::move(request), + std::move(callback)); + }); + return requestId; } -void Instance::Impl::received( - RequestId id, - api::object_ptr result) { - if (!id) { - if (result->get_id() == api::updateAuthorizationState::ID) { - handleUpdateAuthorizationState( - std::move(static_cast( - result.get())->authorization_state_)); - } - } else if (const auto callback = _callbacks.take(id)) { - (*callback)(result->get_id() != api::error::ID); - } +void Instance::Impl::cancel(RequestId requestId) { + _activeRequests.remove(requestId); } -RequestId Instance::Impl::send(api::object_ptr request) { - return _manager->send(_client, std::move(request)); +bool Instance::Impl::shouldInvokeHandler(RequestId requestId) { + return _activeRequests.remove(requestId); +} + +void Instance::Impl::handleUpdate(const TLupdate &update) { + update.match([&](const TLDupdateAuthorizationState &data) { + data.vauthorization_state().match([]( + const TLDauthorizationStateWaitTdlibParameters &) { + }, [&](const TLDauthorizationStateWaitEncryptionKey &data) { + send(TLcheckDatabaseEncryptionKey(tl_bytes()), nullptr, nullptr); + }, [](const auto &) { + + }); + }, [](const auto &) { + }); } void Instance::Impl::sendTdlibParameters(InstanceConfig &&config) { - send(api::make_object( - api::make_object( - false, // use_test_dc - std::string(), // database_directory - std::string(), // files_directory - true, // use_file_database - true, // use_chat_info_database - true, // use_message_database - false, // use_secret_chats - config.apiId, - config.apiHash.toStdString(), - config.systemLanguageCode.toStdString(), - config.deviceModel.toStdString(), - config.systemVersion.toStdString(), - config.applicationVersion.toStdString(), - true, // enable_storage_optimizer - false))); // ignore_file_names -} - -void Instance::Impl::handleUpdateAuthorizationState( - api::object_ptr state) { - switch (state->get_id()) { - case api::authorizationStateWaitTdlibParameters::ID: - //sendTdlibParameters(); // Should happen only once. - break; - - case api::authorizationStateWaitEncryptionKey::ID: - send(api::make_object()); - break; - } + send( + TLsetTdlibParameters( + tl_tdlibParameters( + tl_bool(false), // use_test_dc + tl_string(), // database_directory + tl_string(), // files_directory + tl_bool(true), // use_file_database + tl_bool(true), // use_chat_info_database + tl_bool(true), // use_message_database + tl_bool(false), // use_secret_chats + tl_int32(config.apiId), + tl_string(config.apiHash), + tl_string(config.systemLanguageCode), + tl_string(config.deviceModel), + tl_string(config.systemVersion), + tl_string(config.applicationVersion), + tl_bool(true), // enable_storage_optimizer + tl_bool(false))), // ignore_file_names + nullptr, + nullptr); } Instance::Instance(InstanceConfig &&config) @@ -233,8 +322,14 @@ Instance::Instance(InstanceConfig &&config) Instance::~Instance() = default; -void Instance::testNetwork(Fn done) { - _impl->testNetwork(std::move(done)); +RequestId Instance::sendPrepared( + ExternalGenerator &&request, + ExternalCallback &&callback) { + return _impl->sendPrepared(std::move(request), std::move(callback)); +} + +void Instance::cancel(RequestId requestId) { + _impl->cancel(requestId); } } // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/tdb_instance.h b/Telegram/SourceFiles/tdb/tdb_instance.h index 3b8b9764c70be..5a1b4be2b5723 100644 --- a/Telegram/SourceFiles/tdb/tdb_instance.h +++ b/Telegram/SourceFiles/tdb/tdb_instance.h @@ -7,8 +7,54 @@ For license and copyright information please follow this link: */ #pragma once +#include "tdb/tdb_tl_scheme.h" + +namespace Tdb::details { + +[[nodiscard]] std::optional ParseError(ExternalResponse); + +template +[[nodiscard]] ExternalCallback PrepareCallback( + FnMut done, + FnMut fail) { + if (!done && !fail) { + return nullptr; + } + return [ + done = std::move(done), + fail = std::move(fail) + ](ExternalResponse external) mutable -> FnMut { + if (auto error = ParseError(external)) { + if (!fail) { + return nullptr; + } + // #TODO tdlib log error + return [ + fail = std::move(fail), + error = *error + ]() mutable { + fail(error); + }; + } else { + if (!done) { + return nullptr; + } + return [ + done = std::move(done), + response = tl_from(external) + ]() mutable { + done(response); + }; + } + }; +} + +} // namespace Tdb::details + namespace Tdb { +using RequestId = uint64; + struct InstanceConfig { int32 apiId = 0; QString apiHash; @@ -23,11 +69,29 @@ class Instance final { explicit Instance(InstanceConfig &&config); ~Instance(); - void testNetwork(Fn done); + template < + typename Request, + typename = std::enable_if_t>> + RequestId send( + Request &&request, + FnMut &&done, + FnMut &&fail) { + return sendPrepared( + tl_to_generator(std::move(request)), + details::PrepareCallback( + std::move(done), + std::move(fail))); + } + void cancel(RequestId requestId); private: class Manager; class Impl; + + RequestId sendPrepared( + ExternalGenerator &&request, + ExternalCallback &&callback); + const std::unique_ptr _impl; static std::weak_ptr ManagerInstance; diff --git a/Telegram/SourceFiles/tdb/tdb_pch.h b/Telegram/SourceFiles/tdb/tdb_pch.h index ff199ddb6bf28..f4f87cd01f884 100644 --- a/Telegram/SourceFiles/tdb/tdb_pch.h +++ b/Telegram/SourceFiles/tdb/tdb_pch.h @@ -15,3 +15,5 @@ For license and copyright information please follow this link: #include "base/basic_types.h" #include "base/flat_map.h" #include "base/flat_set.h" + +#include "tdb_tl-scheme.h" diff --git a/Telegram/SourceFiles/tdb/tdb_tl_scheme.h b/Telegram/SourceFiles/tdb/tdb_tl_scheme.h new file mode 100644 index 0000000000000..0c32a3134f7de --- /dev/null +++ b/Telegram/SourceFiles/tdb/tdb_tl_scheme.h @@ -0,0 +1,37 @@ +/* +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 +*/ +#pragma once + +#include "tdb_tl-scheme.h" + +namespace Tdb { + +[[nodiscard]] inline TLbool tl_bool(bool value) { + return value ? tl_boolTrue() : tl_boolFalse(); +} + +[[nodiscard]] inline bool tl_is_true(const TLbool &value) { + return (value.type() == id_boolTrue); +} + +struct Error { + explicit Error(const TLerror &error) + : code(error.c_error().vcode().v) + , message(tl::utf16(error.c_error().vmessage())) { + } + Error(int code, const QString &message) + : code(code) + , message(message) { + } + + int code = 0; + QString message; + +}; + +} // namespace Tdb diff --git a/Telegram/cmake/generate_tdb_tl.cmake b/Telegram/cmake/generate_tdb_tl.cmake new file mode 100644 index 0000000000000..af0dd7be8b8a5 --- /dev/null +++ b/Telegram/cmake/generate_tdb_tl.cmake @@ -0,0 +1,41 @@ +# 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 + +function(generate_tdb_tl target_name script scheme_file) + find_package(Python REQUIRED) + + set(gen_dst ${CMAKE_CURRENT_BINARY_DIR}/gen) + file(MAKE_DIRECTORY ${gen_dst}) + + set(gen_timestamp ${gen_dst}/tdb_tl-scheme.timestamp) + set(gen_files + ${gen_dst}/tdb_tl-scheme.cpp + ${gen_dst}/tdb_tl-scheme.h + ${gen_dst}/tdb_tl-scheme-conversion-from.cpp + ${gen_dst}/tdb_tl-scheme-conversion-from.h + ${gen_dst}/tdb_tl-scheme-conversion-to.cpp + ${gen_dst}/tdb_tl-scheme-conversion-to.h + ) + + add_custom_command( + OUTPUT + ${gen_timestamp} + BYPRODUCTS + ${gen_files} + COMMAND + ${Python_EXECUTABLE} + ${script} + -o${gen_dst}/tdb_tl-scheme + ${scheme_file} + COMMENT "Generating scheme (${target_name})" + DEPENDS + ${script} + ${submodules_loc}/lib_tl/tl/generate_tl.py + ${scheme_file} + ) + generate_target(${target_name} scheme ${gen_timestamp} "${gen_files}" ${gen_dst}) + target_sources(${target_name} PRIVATE ${scheme_file}) +endfunction() diff --git a/Telegram/cmake/td_tdb.cmake b/Telegram/cmake/td_tdb.cmake index 8f9d5b9bae82d..9e7cec9b5e72f 100644 --- a/Telegram/cmake/td_tdb.cmake +++ b/Telegram/cmake/td_tdb.cmake @@ -8,11 +8,25 @@ add_library(td_tdb OBJECT) init_target(td_tdb) add_library(tdesktop::td_tdb ALIAS td_tdb) +include(cmake/generate_tdb_tl.cmake) + +generate_tdb_tl(td_tdb ${src_loc}/tdb/details/tdb_tl_generate.py ${libs_loc}/td/td/generate/scheme/td_api.tl) + target_precompile_headers(td_tdb PRIVATE ${src_loc}/tdb/tdb_pch.h) nice_target_sources(td_tdb ${src_loc} PRIVATE tdb/tdb_instance.cpp tdb/tdb_instance.h + tdb/tdb_tl_scheme.h + + tdb/tdb_pch.h + + tdb/details/tdb_tl_core.h + tdb/details/tdb_tl_core_conversion_from.cpp + tdb/details/tdb_tl_core_conversion_from.h + tdb/details/tdb_tl_core_conversion_to.cpp + tdb/details/tdb_tl_core_conversion_to.h + tdb/details/tdb_tl_generate.py ) target_include_directories(td_tdb @@ -23,6 +37,7 @@ PUBLIC target_link_libraries(td_tdb PUBLIC desktop-app::lib_base + desktop-app::lib_tl PRIVATE desktop-app::external_td ) From 31398cbdd95e9d5f9b101032ba1157b52721de81 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 15 Apr 2021 14:10:05 +0400 Subject: [PATCH 003/350] Support nullable fields. --- Telegram/SourceFiles/mtproto/core_types.h | 16 ++++++++-------- Telegram/SourceFiles/tdb/details/tdb_tl_core.h | 12 ++++++++---- .../tdb/details/tdb_tl_core_conversion_from.h | 14 +++++++++++++- .../tdb/details/tdb_tl_core_conversion_to.h | 11 +++++++++++ 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h index 75287cebaefa4..701a86e59b2d2 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -131,7 +131,7 @@ static const uint32 mtpLayerMaxSingle = sizeof(mtpLayers) / sizeof(mtpLayers[0]) using MTPint = tl::int_type; -inline MTPint MTP_int(int32 v) { +inline constexpr MTPint MTP_int(int32 v) noexcept { return tl::make_int(v); } @@ -139,40 +139,40 @@ template using MTPflags = tl::flags_type; template -inline MTPflags> MTP_flags(base::flags v) { +inline constexpr MTPflags> MTP_flags(base::flags v) noexcept { return tl::make_flags(v); } template ::value>> -inline MTPflags> MTP_flags(T v) { +inline constexpr MTPflags> MTP_flags(T v) noexcept { return tl::make_flags(v); } -inline tl::details::zero_flags_helper MTP_flags(void(tl::details::zero_flags_helper::*)()) { +inline constexpr tl::details::zero_flags_helper MTP_flags(void(tl::details::zero_flags_helper::*)()) noexcept { return tl::details::zero_flags_helper(); } using MTPlong = tl::long_type; -inline MTPlong MTP_long(uint64 v) { +inline constexpr MTPlong MTP_long(uint64 v) noexcept { return tl::make_long(v); } using MTPint128 = tl::int128_type; -inline MTPint128 MTP_int128(uint64 l, uint64 h) { +inline constexpr MTPint128 MTP_int128(uint64 l, uint64 h) noexcept { return tl::make_int128(l, h); } using MTPint256 = tl::int256_type; -inline MTPint256 MTP_int256(const MTPint128 &l, const MTPint128 &h) { +inline constexpr MTPint256 MTP_int256(const MTPint128 &l, const MTPint128 &h) noexcept { return tl::make_int256(l, h); } using MTPdouble = tl::double_type; -inline MTPdouble MTP_double(float64 v) { +inline constexpr MTPdouble MTP_double(float64 v) noexcept { return tl::make_double(v); } diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h index c1f907472136f..79d42cc0a77fe 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core.h +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h @@ -10,6 +10,8 @@ For license and copyright information please follow this link: #include "tl/tl_basic_types.h" #include "base/match_method.h" +#include + namespace td::tl { template class unique_ptr; @@ -22,6 +24,8 @@ class Function; namespace Tdb { +inline constexpr auto null = std::nullopt; + using TLint32 = tl::int_type; using TLint53 = tl::int64_type; using TLint64 = tl::int64_type; @@ -31,16 +35,16 @@ using TLbytes = tl::bytes_type; template using TLvector = tl::vector_type; -inline TLint32 tl_int32(int32 value) { +inline constexpr TLint32 tl_int32(int32 value) noexcept { return tl::make_int(value); } -inline TLint53 tl_int53(int64 value) { +inline constexpr TLint53 tl_int53(int64 value) noexcept { return tl::make_int64(value); } -inline TLint64 tl_int64(int64 value) { +inline constexpr TLint64 tl_int64(int64 value) noexcept { return tl::make_int64(value); } -inline TLdouble tl_double(float64 value) { +inline constexpr TLdouble tl_double(float64 value) noexcept { return tl::make_double(value); } inline TLstring tl_string(const std::string &v) { diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h index 505f0f9178a3e..83bdc413e6044 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h @@ -7,7 +7,6 @@ For license and copyright information please follow this link: */ #pragma once -#include "td/telegram/td_api.h" #include "tdb/details/tdb_tl_core.h" #include "tdb_tl-scheme.h" @@ -19,6 +18,19 @@ TLint64 tl_from_simple(std::int64_t value); TLdouble tl_from_simple(double value); TLbool tl_from_simple(bool value); +template +auto tl_from_vector_optional(const std::vector &value) { + using I = in_TLvector_t; + auto result = QVector>(); + result.reserve(value.size()); + for (const auto &element : value) { + result.push_back(element.get() + ? std::make_optional(tl_from(element.get())) + : std::nullopt); + } + return tl_vector>(std::move(result)); +} + template auto tl_from_vector(const std::vector &value) { using I = in_TLvector_t; diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h index 76679eb4ab8bd..e7f295ada417a 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h @@ -53,6 +53,17 @@ struct tl_to_type> : std::type_identity>> { }; +template +auto tl_to_vector_optional(const TLvector> &value) { + using U = tl_to_type_t; + auto result = std::vector(); + result.reserve(value.v.size()); + for (const auto &element : value.v) { + result.push_back(U(element ? tl_to(*element) : nullptr)); + } + return result; +} + template auto tl_to_vector(const TLvector &value) { constexpr bool simple = std::is_same_v From 927637becabf84395e13ed9601bc6fbc9a9795a0 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 15 Apr 2021 21:14:00 +0400 Subject: [PATCH 004/350] Support string type separate from bytes. --- .../SourceFiles/tdb/details/tdb_tl_core.h | 61 ++++++++++++++----- .../details/tdb_tl_core_conversion_from.cpp | 6 +- .../tdb/details/tdb_tl_core_conversion_from.h | 20 +++--- .../tdb/details/tdb_tl_core_conversion_to.cpp | 6 +- .../tdb/details/tdb_tl_core_conversion_to.h | 6 ++ Telegram/SourceFiles/tdb/tdb_tl_scheme.h | 2 +- 6 files changed, 74 insertions(+), 27 deletions(-) diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h index 79d42cc0a77fe..5fd0e90f5b911 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core.h +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h @@ -30,7 +30,6 @@ using TLint32 = tl::int_type; using TLint53 = tl::int64_type; using TLint64 = tl::int64_type; using TLdouble = tl::double_type; -using TLstring = tl::string_type; using TLbytes = tl::bytes_type; template using TLvector = tl::vector_type; @@ -47,21 +46,6 @@ inline constexpr TLint64 tl_int64(int64 value) noexcept { inline constexpr TLdouble tl_double(float64 value) noexcept { return tl::make_double(value); } -inline TLstring tl_string(const std::string &v) { - return tl::make_string(v); -} -inline TLstring tl_string(const QString &v) { - return tl::make_string(v); -} -inline TLbytes tl_string(const QByteArray &v) { - return tl::make_string(v); -} -inline TLstring tl_string(const char *v) { - return tl::make_string(v); -} -inline TLstring tl_string() { - return tl::make_string(); -} inline TLbytes tl_bytes(const QByteArray &v) { return tl::make_bytes(v); } @@ -98,6 +82,51 @@ inline TLvector tl_vector() { return tl::make_vector(); } +class TLstring { +public: + TLstring() noexcept = default; + + uint32 type() const noexcept { + return tl::id_string; + } + + QString v; + +private: + explicit TLstring(QString &&data) noexcept : v(std::move(data)) { + } + + friend TLstring tl_string(const std::string &v); + friend TLstring tl_string(const QString &v); + friend TLstring tl_string(QString &&v); + friend TLstring tl_string(const char *v); + friend TLstring tl_string(); + +}; + +inline TLstring tl_string(const std::string &v) { + return TLstring(QString::fromStdString(v)); +} +inline TLstring tl_string(const QString &v) { + return TLstring(QString(v)); +} +inline TLstring tl_string(QString &&v) { + return TLstring(std::move(v)); +} +inline TLstring tl_string(const char *v) { + return TLstring(QString::fromUtf8(v)); +} +inline TLstring tl_string() { + return TLstring(QString()); +} + +inline bool operator==(const TLstring &a, const TLstring &b) { + return a.v == b.v; +} +inline bool operator!=(const TLstring &a, const TLstring &b) { + return a.v != b.v; +} + using ExternalRequest = ::td::td_api::Function*; using ExternalResponse = const ::td::td_api::Object*; using ExternalGenerator = Fn; diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp index f014f00363f90..9d29628015aaa 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp @@ -9,10 +9,14 @@ For license and copyright information please follow this link: namespace Tdb { -TLstring tl_from_simple(const std::string &value) { +TLstring tl_from_string(const std::string &value) { return tl_string(value); } +TLbytes tl_from_simple(const std::string &value) { + return tl_bytes(QByteArray::fromStdString(value)); +} + TLint32 tl_from_simple(std::int32_t value) { return tl_int32(value); } diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h index 83bdc413e6044..459065a2b2b19 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.h @@ -12,7 +12,8 @@ For license and copyright information please follow this link: namespace Tdb { -TLstring tl_from_simple(const std::string &value); +TLstring tl_from_string(const std::string &value); +TLbytes tl_from_simple(const std::string &value); TLint32 tl_from_simple(std::int32_t value); TLint64 tl_from_simple(std::int64_t value); TLdouble tl_from_simple(double value); @@ -36,14 +37,17 @@ auto tl_from_vector(const std::vector &value) { using I = in_TLvector_t; auto result = QVector(); result.reserve(value.size()); - constexpr bool simple = std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v; - constexpr bool vector = !simple && is_TLvector_v; + constexpr bool simple = std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v; + constexpr bool string = !simple && std::is_same_v; + constexpr bool vector = !simple && !string && is_TLvector_v; for (const auto &element : value) { - if constexpr (simple) { + if constexpr (string) { + result.push_back(tl_from_string(element)); + } else if constexpr (simple) { result.push_back(tl_from_simple(element)); } else if constexpr (vector) { result.push_back(tl_from_vector(element)); diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp index f67f30307396d..c1f22b9f90966 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp @@ -10,7 +10,11 @@ For license and copyright information please follow this link: namespace Tdb { std::string tl_to_simple(const TLstring &value) { - return std::string(value.v.data(), value.v.size()); + return value.v.toStdString(); +} + +std::string tl_to_simple(const TLbytes &value) { + return value.v.toStdString(); } std::int32_t tl_to_simple(const TLint32 &value) { diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h index e7f295ada417a..d788af4f234d8 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.h @@ -13,6 +13,7 @@ For license and copyright information please follow this link: namespace Tdb { std::string tl_to_simple(const TLstring &value); +std::string tl_to_simple(const TLbytes &value); std::int32_t tl_to_simple(const TLint32 &value); std::int64_t tl_to_simple(const TLint64 &value); double tl_to_simple(const TLdouble &value); @@ -32,6 +33,10 @@ template <> struct tl_to_type : std::type_identity { }; +template <> +struct tl_to_type : std::type_identity { +}; + template <> struct tl_to_type : std::type_identity { }; @@ -68,6 +73,7 @@ template auto tl_to_vector(const TLvector &value) { constexpr bool simple = std::is_same_v || std::is_same_v + || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; diff --git a/Telegram/SourceFiles/tdb/tdb_tl_scheme.h b/Telegram/SourceFiles/tdb/tdb_tl_scheme.h index 0c32a3134f7de..fab20f72746f7 100644 --- a/Telegram/SourceFiles/tdb/tdb_tl_scheme.h +++ b/Telegram/SourceFiles/tdb/tdb_tl_scheme.h @@ -22,7 +22,7 @@ namespace Tdb { struct Error { explicit Error(const TLerror &error) : code(error.c_error().vcode().v) - , message(tl::utf16(error.c_error().vmessage())) { + , message(error.c_error().vmessage().v) { } Error(int code, const QString &message) : code(code) From 12394117ab129d396e60e2b10f06af869516043c Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 20 Apr 2021 23:03:19 +0400 Subject: [PATCH 005/350] Disable TDLib logging. --- Telegram/SourceFiles/tdb/tdb_instance.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Telegram/SourceFiles/tdb/tdb_instance.cpp b/Telegram/SourceFiles/tdb/tdb_instance.cpp index 3c05f801c4c19..304e9d495e240 100644 --- a/Telegram/SourceFiles/tdb/tdb_instance.cpp +++ b/Telegram/SourceFiles/tdb/tdb_instance.cpp @@ -119,6 +119,8 @@ Instance::Manager::Manager(PrivateTag) std::shared_ptr Instance::Manager::Instance() { auto result = ManagerInstance.lock(); if (!result) { + ClientManager::execute( + td_api::make_object(0)); ManagerInstance = result = std::make_shared(PrivateTag{}); } return result; From 7e1be1adeb07d09182ddfc2bbac34233864da03a Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 21 Apr 2021 13:28:37 +0400 Subject: [PATCH 006/350] Show QR login code from TDLib updates. --- Telegram/SourceFiles/intro/intro_code.cpp | 12 + .../intro/intro_password_check.cpp | 10 + Telegram/SourceFiles/intro/intro_phone.cpp | 4 + Telegram/SourceFiles/intro/intro_qr.cpp | 80 +++-- Telegram/SourceFiles/intro/intro_qr.h | 15 +- Telegram/SourceFiles/intro/intro_signup.cpp | 2 + Telegram/SourceFiles/intro/intro_start.cpp | 2 + Telegram/SourceFiles/intro/intro_step.cpp | 6 +- Telegram/SourceFiles/intro/intro_step.h | 5 +- Telegram/SourceFiles/intro/intro_widget.cpp | 65 ++-- Telegram/SourceFiles/intro/intro_widget.h | 9 +- Telegram/SourceFiles/main/main_account.cpp | 32 +- Telegram/SourceFiles/main/main_account.h | 17 + Telegram/SourceFiles/mtproto/core_types.h | 3 + Telegram/SourceFiles/mtproto/mtp_instance.cpp | 18 +- .../tdb/{ => details}/tdb_instance.cpp | 84 +++-- .../tdb/{ => details}/tdb_instance.h | 30 +- Telegram/SourceFiles/tdb/tdb_account.cpp | 43 +++ Telegram/SourceFiles/tdb/tdb_account.h | 42 +++ Telegram/SourceFiles/tdb/tdb_pch.h | 3 +- Telegram/SourceFiles/tdb/tdb_sender.cpp | 79 +++++ Telegram/SourceFiles/tdb/tdb_sender.h | 320 ++++++++++++++++++ Telegram/SourceFiles/tdb/tdb_tl_scheme.h | 4 + Telegram/cmake/td_tdb.cmake | 10 +- 24 files changed, 764 insertions(+), 131 deletions(-) rename Telegram/SourceFiles/tdb/{ => details}/tdb_instance.cpp (82%) rename Telegram/SourceFiles/tdb/{ => details}/tdb_instance.h (82%) create mode 100644 Telegram/SourceFiles/tdb/tdb_account.cpp create mode 100644 Telegram/SourceFiles/tdb/tdb_account.h create mode 100644 Telegram/SourceFiles/tdb/tdb_sender.cpp create mode 100644 Telegram/SourceFiles/tdb/tdb_sender.h diff --git a/Telegram/SourceFiles/intro/intro_code.cpp b/Telegram/SourceFiles/intro/intro_code.cpp index d2192fdffe421..ed1e55fd16752 100644 --- a/Telegram/SourceFiles/intro/intro_code.cpp +++ b/Telegram/SourceFiles/intro/intro_code.cpp @@ -237,12 +237,14 @@ void CodeWidget::finished() { } void CodeWidget::cancelled() { +#if 0 // #TODO tdlib api().request(base::take(_sentRequest)).cancel(); api().request(base::take(_callRequestId)).cancel(); api().request(MTPauth_CancelCode( MTP_string(getData()->phone), MTP_bytes(getData()->phoneHash) )).send(); +#endif } void CodeWidget::stopCheck() { @@ -250,6 +252,7 @@ void CodeWidget::stopCheck() { } void CodeWidget::checkRequest() { +#if 0 // #TODO legacy auto status = api().instance().state(_sentRequest); if (status < 0) { auto leftms = -status; @@ -263,6 +266,7 @@ void CodeWidget::checkRequest() { if (!_sentRequest && status == MTP::RequestSent) { stopCheck(); } +#endif } void CodeWidget::codeSubmitDone(const MTPauth_Authorization &result) { @@ -289,6 +293,7 @@ void CodeWidget::codeSubmitFail(const MTP::Error &error) { } else if (err == u"PHONE_CODE_EMPTY"_q || err == u"PHONE_CODE_INVALID"_q) { showCodeError(tr::lng_bad_code()); } else if (err == u"SESSION_PASSWORD_NEEDED"_q) { +#if 0 // #TODO tdlib _checkRequestTimer.callEach(1000); _sentRequest = api().request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { @@ -296,6 +301,7 @@ void CodeWidget::codeSubmitFail(const MTP::Error &error) { }).fail([=](const MTP::Error &error) { codeSubmitFail(error); }).handleFloodErrors().send(); +#endif } else if (Logs::DebugEnabled()) { // internal server error showCodeError(rpl::single(err + ": " + error.description())); } else { @@ -313,12 +319,14 @@ void CodeWidget::sendCall() { if (--_callTimeout <= 0) { _callStatus = CallStatus::Calling; _callTimer.cancel(); +#if 0 // #TODO tdlib _callRequestId = api().request(MTPauth_ResendCode( MTP_string(getData()->phone), MTP_bytes(getData()->phoneHash) )).done([=](const MTPauth_SentCode &result) { callDone(result); }).send(); +#endif } else { getData()->callStatus = _callStatus; getData()->callTimeout = _callTimeout; @@ -395,6 +403,7 @@ void CodeWidget::submitCode() { _sentCode = text; getData()->pwdState = Core::CloudPasswordState(); +#if 0 // #TODO tdlib _sentRequest = api().request(MTPauth_SignIn( MTP_flags(MTPauth_SignIn::Flag::f_phone_code), MTP_string(getData()->phone), @@ -406,6 +415,7 @@ void CodeWidget::submitCode() { }).fail([=](const MTP::Error &error) { codeSubmitFail(error); }).handleFloodErrors().send(); +#endif } rpl::producer CodeWidget::nextButtonText() const { @@ -428,6 +438,7 @@ void CodeWidget::noTelegramCode() { if (_noTelegramCodeRequestId) { return; } +#if 0 // #TODO tdlib _noTelegramCodeRequestId = api().request(MTPauth_ResendCode( MTP_string(getData()->phone), MTP_bytes(getData()->phoneHash) @@ -436,6 +447,7 @@ void CodeWidget::noTelegramCode() { }).fail([=](const MTP::Error &error) { noTelegramCodeFail(error); }).handleFloodErrors().send(); +#endif } void CodeWidget::noTelegramCodeDone(const MTPauth_SentCode &result) { diff --git a/Telegram/SourceFiles/intro/intro_password_check.cpp b/Telegram/SourceFiles/intro/intro_password_check.cpp index cd73d9867facc..1c4b4379964e5 100644 --- a/Telegram/SourceFiles/intro/intro_password_check.cpp +++ b/Telegram/SourceFiles/intro/intro_password_check.cpp @@ -187,6 +187,7 @@ void PasswordCheckWidget::checkPasswordHash() { void PasswordCheckWidget::requestPasswordData() { api().request(base::take(_sentRequest)).cancel(); +#if 0 // #TODO tdlib _sentRequest = api().request( MTPaccount_GetPassword() ).done([=](const MTPaccount_Password &result) { @@ -197,6 +198,7 @@ void PasswordCheckWidget::requestPasswordData() { passwordChecked(); }); }).send(); +#endif } void PasswordCheckWidget::passwordChecked() { @@ -207,6 +209,7 @@ void PasswordCheckWidget::passwordChecked() { return serverError(); } _passwordState.mtp.request.id = 0; +#if 0 // #TODO tdlib _sentRequest = api().request( MTPauth_CheckPassword(check.result) ).done([=](const MTPauth_Authorization &result) { @@ -214,6 +217,7 @@ void PasswordCheckWidget::passwordChecked() { }).fail([=](const MTP::Error &error) { pwdSubmitFail(error); }).handleFloodErrors().send(); +#endif } void PasswordCheckWidget::serverError() { @@ -223,6 +227,7 @@ void PasswordCheckWidget::serverError() { void PasswordCheckWidget::codeSubmitDone( const QString &code, const MTPBool &result) { +#if 0 // #TODO tdlib auto fields = PasscodeBox::CloudFields::From(_passwordState); fields.fromRecoveryCode = code; fields.hasRecovery = false; @@ -240,6 +245,7 @@ void PasswordCheckWidget::codeSubmitDone( }, lifetime()); *boxShared = Ui::show(std::move(box)); +#endif } void PasswordCheckWidget::codeSubmitFail(const MTP::Error &error) { @@ -303,6 +309,7 @@ void PasswordCheckWidget::toRecover() { _codeField->setFocus(); updateDescriptionText(); if (_emailPattern.isEmpty()) { +#if 0 // #TODO tdlib api().request( MTPauth_RequestPasswordRecovery() ).done([=](const MTPauth_PasswordRecovery &result) { @@ -310,6 +317,7 @@ void PasswordCheckWidget::toRecover() { }).fail([=](const MTP::Error &error) { recoverStartFail(error); }).send(); +#endif } } else { const auto box = Ui::show( @@ -365,6 +373,7 @@ void PasswordCheckWidget::submit() { return; } const auto send = crl::guard(this, [=] { +#if 0 // #TODO tdlib _sentRequest = api().request(MTPauth_CheckRecoveryPassword( MTP_string(code) )).done([=](const MTPBool &result) { @@ -372,6 +381,7 @@ void PasswordCheckWidget::submit() { }).fail([=](const MTP::Error &error) { codeSubmitFail(error); }).handleFloodErrors().send(); +#endif }); if (_passwordState.notEmptyPassport) { diff --git a/Telegram/SourceFiles/intro/intro_phone.cpp b/Telegram/SourceFiles/intro/intro_phone.cpp index bf8a355bcd602..5616853ca5fc2 100644 --- a/Telegram/SourceFiles/intro/intro_phone.cpp +++ b/Telegram/SourceFiles/intro/intro_phone.cpp @@ -165,6 +165,7 @@ void PhoneWidget::submit() { return; } +#if 0 // #TODO tdlib cancelNearestDcRequest(); // Check if such account is authorized already. @@ -205,6 +206,7 @@ void PhoneWidget::submit() { }).fail([=](const MTP::Error &error) { phoneSubmitFail(error); }).handleFloodErrors().send(); +#endif } void PhoneWidget::stopCheck() { @@ -212,6 +214,7 @@ void PhoneWidget::stopCheck() { } void PhoneWidget::checkRequest() { +#if 0 // #TODO legacy auto status = api().instance().state(_sentRequest); if (status < 0) { auto leftms = -status; @@ -222,6 +225,7 @@ void PhoneWidget::checkRequest() { if (!_sentRequest && status == MTP::RequestSent) { stopCheck(); } +#endif } void PhoneWidget::phoneSubmitDone(const MTPauth_SentCode &result) { diff --git a/Telegram/SourceFiles/intro/intro_qr.cpp b/Telegram/SourceFiles/intro/intro_qr.cpp index 3ad8aead8d967..06cacee6c0039 100644 --- a/Telegram/SourceFiles/intro/intro_qr.cpp +++ b/Telegram/SourceFiles/intro/intro_qr.cpp @@ -27,12 +27,15 @@ For license and copyright information please follow this link: #include "core/update_checker.h" #include "base/unixtime.h" #include "qr/qr_generate.h" +#include "tdb/tdb_account.h" #include "styles/style_intro.h" namespace Intro { namespace details { namespace { +using namespace Tdb; + [[nodiscard]] QImage TelegramQrExact(const Qr::Data &data, int pixel) { return Qr::Generate(data, pixel, Qt::black); } @@ -59,7 +62,7 @@ namespace { [[nodiscard]] not_null PrepareQrWidget( not_null parent, - rpl::producer codes) { + rpl::producer links) { struct State { explicit State(Fn callback) : waiting(callback, st::defaultInfiniteRadialAnimation) { @@ -72,9 +75,9 @@ namespace { Ui::InfiniteRadialAnimation waiting; }; auto qrs = std::move( - codes - ) | rpl::map([](const QByteArray &code) { - return Qr::Encode(code, Qr::Redundancy::Quartile); + links + ) | rpl::map([](const QString &link) { + return Qr::Encode(link, Qr::Redundancy::Quartile); }); auto palettes = rpl::single(rpl::empty) | rpl::then( style::PaletteChanged() @@ -176,18 +179,27 @@ QrWidget::QrWidget( QWidget *parent, not_null account, not_null data) -: Step(parent, account, data) +: Step(parent, account, data) { +#if 0 // #TODO legacy , _refreshTimer([=] { refreshCode(); }) { +#endif setTitleText(rpl::single(QString())); setDescriptionText(rpl::single(QString())); setErrorCentered(true); +#if 0 // #TODO legacy cancelNearestDcRequest(); account->mtpUpdates( ) | rpl::start_with_next([=](const MTPUpdates &updates) { checkForTokenUpdate(updates); }, lifetime()); +#endif + + account->tdb().updates( + ) | rpl::start_with_next([=](const TLupdate &update) { + handleUpdate(update); + }, lifetime()); setupControls(); account->mtp().mainDcIdValue( @@ -201,6 +213,7 @@ int QrWidget::errorTop() const { return contentTop() + st::introQrErrorTop; } +#if 0 // #TODO legacy void QrWidget::checkForTokenUpdate(const MTPUpdates &updates) { updates.match([&](const MTPDupdateShort &data) { checkForTokenUpdate(data.vupdate()); @@ -225,6 +238,18 @@ void QrWidget::checkForTokenUpdate(const MTPUpdate &update) { } }, [](const auto &) {}); } +#endif + +void QrWidget::handleUpdate(const TLupdate &update) { + update.match([&](const TLDupdateAuthorizationState &data) { + data.vauthorization_state().match( + [&](const TLDauthorizationStateWaitOtherDeviceConfirmation &data) { + _qrLinks.fire_copy(data.vlink().v); + }, [](const auto &) { + }); + }, [](const auto &) { + }); +} void QrWidget::submit() { goReplace(Animate::Forward); @@ -235,7 +260,7 @@ rpl::producer QrWidget::nextButtonText() const { } void QrWidget::setupControls() { - const auto code = PrepareQrWidget(this, _qrCodes.events()); + const auto code = PrepareQrWidget(this, _qrLinks.events()); rpl::combine( sizeValue(), code->widthValue() @@ -314,20 +339,27 @@ void QrWidget::setupControls() { } void QrWidget::refreshCode() { - if (_requestId) { - return; - } - _requestId = api().request(MTPauth_ExportLoginToken( - MTP_int(ApiId), - MTP_string(ApiHash), - MTP_vector(0) - )).done([=](const MTPauth_LoginToken &result) { - handleTokenResult(result); - }).fail([=](const MTP::Error &error) { + api().request( + TLgetAuthorizationState() + ).done([=](const TLauthorizationState &result) { + result.match( + [&](const TLDauthorizationStateWaitOtherDeviceConfirmation &data) { + _qrLinks.fire_copy(data.vlink().v); + }, [&](const TLDauthorizationStateWaitPhoneNumber &data) { + api().request(TLrequestQrCodeAuthentication( + tl_vector(0) + )).fail([=](const Error &error) { + showTokenError(error); + }).send(); + }, [&](const auto &) { + showTokenError(Error::Local("Wrong authorizationState.")); + }); + }).fail([=](const Error &error) { showTokenError(error); }).send(); } +#if 0 // #TODO legacy void QrWidget::handleTokenResult(const MTPauth_LoginToken &result) { result.match([&](const MTPDauth_loginToken &data) { _requestId = 0; @@ -345,18 +377,13 @@ void QrWidget::handleTokenResult(const MTPauth_LoginToken &result) { done(data.vauthorization()); }); } +#endif -void QrWidget::showTokenError(const MTP::Error &error) { - _requestId = 0; - if (error.type() == u"SESSION_PASSWORD_NEEDED"_q) { - sendCheckPasswordRequest(); - } else if (base::take(_forceRefresh)) { - refreshCode(); - } else { - showError(rpl::single(error.type())); - } +void QrWidget::showTokenError(const Error &error) { + showError(rpl::single(error.message)); } +#if 0 // #TODO legacy void QrWidget::showToken(const QByteArray &token) { const auto encoded = token.toBase64(QByteArray::Base64UrlEncoding); _qrCodes.fire_copy("tg://login?token=" + encoded); @@ -406,6 +433,7 @@ void QrWidget::sendCheckPasswordRequest() { showTokenError(error); }).send(); } +#endif void QrWidget::activate() { Step::activate(); @@ -414,13 +442,11 @@ void QrWidget::activate() { void QrWidget::finished() { Step::finished(); - _refreshTimer.cancel(); apiClear(); cancelled(); } void QrWidget::cancelled() { - api().request(base::take(_requestId)).cancel(); } QImage TelegramLogoImage() { diff --git a/Telegram/SourceFiles/intro/intro_qr.h b/Telegram/SourceFiles/intro/intro_qr.h index 7cc166a4bc18a..61718e3974454 100644 --- a/Telegram/SourceFiles/intro/intro_qr.h +++ b/Telegram/SourceFiles/intro/intro_qr.h @@ -37,19 +37,26 @@ class QrWidget final : public Step { void sendCheckPasswordRequest(); void setupControls(); void refreshCode(); +#if 0 // #TODO legacy void checkForTokenUpdate(const MTPUpdates &updates); void checkForTokenUpdate(const MTPUpdate &update); void handleTokenResult(const MTPauth_LoginToken &result); - void showTokenError(const MTP::Error &error); +#endif + void showTokenError(const Tdb::Error &error); +#if 0 // #TODO legacy void importTo(MTP::DcId dcId, const QByteArray &token); +#endif void showToken(const QByteArray &token); void done(const MTPauth_Authorization &authorization); - rpl::event_stream _qrCodes; + void handleUpdate(const Tdb::TLupdate &update); + + rpl::event_stream _qrLinks; +#if 0 // #TODO legacy base::Timer _refreshTimer; - mtpRequestId _requestId = 0; + Tdb::RequestId _requestId = 0; bool _forceRefresh = false; - +#endif }; [[nodiscard]] QImage TelegramLogoImage(); diff --git a/Telegram/SourceFiles/intro/intro_signup.cpp b/Telegram/SourceFiles/intro/intro_signup.cpp index bb8bc46da2f38..892da77b1a64d 100644 --- a/Telegram/SourceFiles/intro/intro_signup.cpp +++ b/Telegram/SourceFiles/intro/intro_signup.cpp @@ -182,6 +182,7 @@ void SignupWidget::submit() { _firstName = _first->getLastText().trimmed(); _lastName = _last->getLastText().trimmed(); +#if 0 // #TODO tdlib _sentRequest = api().request(MTPauth_SignUp( MTP_string(getData()->phone), MTP_bytes(getData()->phoneHash), @@ -192,6 +193,7 @@ void SignupWidget::submit() { }).fail([=](const MTP::Error &error) { nameSubmitFail(error); }).handleFloodErrors().send(); +#endif }; if (_termsAccepted || getData()->termsLock.text.text.isEmpty() diff --git a/Telegram/SourceFiles/intro/intro_start.cpp b/Telegram/SourceFiles/intro/intro_start.cpp index d4ebdec0b77aa..1dc687e4af73e 100644 --- a/Telegram/SourceFiles/intro/intro_start.cpp +++ b/Telegram/SourceFiles/intro/intro_start.cpp @@ -30,7 +30,9 @@ StartWidget::StartWidget( } void StartWidget::submit() { +#if 0 // #TODO tdlib account().destroyStaleAuthorizationKeys(); +#endif goNext(); } diff --git a/Telegram/SourceFiles/intro/intro_step.cpp b/Telegram/SourceFiles/intro/intro_step.cpp index 68ec48cdbed0d..c76fccae24084 100644 --- a/Telegram/SourceFiles/intro/intro_step.cpp +++ b/Telegram/SourceFiles/intro/intro_step.cpp @@ -106,9 +106,9 @@ Step::Step( Step::~Step() = default; -MTP::Sender &Step::api() const { +Tdb::Sender &Step::api() const { if (!_api) { - _api.emplace(&_account->mtp()); + _api.emplace(_account->sender()); } return *_api; } @@ -192,12 +192,14 @@ void Step::finish(const MTPUser &user, QImage &&photo) { } } +#if 0 // #TODO tdlib api().request(MTPmessages_GetDialogFilters( )).done([=](const MTPVector &result) { createSession(user, photo, result.v); }).fail([=] { createSession(user, photo, QVector()); }).send(); +#endif } void Step::createSession( diff --git a/Telegram/SourceFiles/intro/intro_step.h b/Telegram/SourceFiles/intro/intro_step.h index 660e2c367e899..4ccf54e784f38 100644 --- a/Telegram/SourceFiles/intro/intro_step.h +++ b/Telegram/SourceFiles/intro/intro_step.h @@ -9,6 +9,7 @@ For license and copyright information please follow this link: #include "base/object_ptr.h" #include "mtproto/sender.h" +#include "tdb/tdb_sender.h" #include "ui/rp_widget.h" #include "ui/effects/animations.h" @@ -50,7 +51,7 @@ class Step : public Ui::RpWidget { // It should not be called in StartWidget, in other steps it should be // present and not changing. - [[nodiscard]] MTP::Sender &api() const; + [[nodiscard]] Tdb::Sender &api() const; void apiClear(); virtual void finishInit() { @@ -184,7 +185,7 @@ class Step : public Ui::RpWidget { const not_null _account; const not_null _data; - mutable std::optional _api; + mutable std::optional _api; bool _hasCover = false; Fn _goCallback; diff --git a/Telegram/SourceFiles/intro/intro_widget.cpp b/Telegram/SourceFiles/intro/intro_widget.cpp index f276792426ec4..362664eb9cab7 100644 --- a/Telegram/SourceFiles/intro/intro_widget.cpp +++ b/Telegram/SourceFiles/intro/intro_widget.cpp @@ -46,13 +46,11 @@ For license and copyright information please follow this link: #include "styles/style_intro.h" #include "base/qt/qt_common_adapters.h" -#include "tdb/tdb_instance.h" -#include "ui/toast/toast.h" - namespace Intro { namespace { using namespace ::Intro::details; +using namespace Tdb; [[nodiscard]] QString ComputeNewAccountCountry() { if (const auto parent @@ -68,8 +66,6 @@ using namespace ::Intro::details; return Platform::SystemCountry(); } -std::unique_ptr Instance; - } // namespace Widget::Widget( @@ -79,6 +75,7 @@ Widget::Widget( EnterPoint point) : RpWidget(parent) , _account(account) +, _api(account->sender()) , _data(details::Data{ .controller = controller }) , _nextStyle(&st::introNextButton) , _back(this, object_ptr(this, st::introBackButton)) @@ -97,31 +94,19 @@ Widget::Widget( rpl::single(true))) { controller->setDefaultFloatPlayerDelegate(floatPlayerDelegate()); - Instance = std::make_unique(Tdb::InstanceConfig{ - .apiId = ApiId, - .apiHash = ApiHash, - .systemLanguageCode = Lang::GetInstance().systemLangCode(), - .deviceModel = Platform::DeviceModelPretty(), - .systemVersion = Platform::SystemVersionPretty(), - .applicationVersion = QString::fromLatin1(AppVersionStr), - }); - Instance->send(Tdb::TLtestNetwork(), [](const Tdb::TLok &result) { - Ui::Toast::Show(u"TDLib Network OK!"_q); - }, [](const Tdb::Error &error) { - Ui::Toast::Show(u"TDLib Network Fail: "_q + error.message); - }); - getData()->country = ComputeNewAccountCountry(); - +#if 0 // #TODO legacy _account->mtpValue( ) | rpl::start_with_next([=](not_null instance) { _api.emplace(instance); crl::on_main(this, [=] { createLanguageLink(); }); }, lifetime()); - +#endif switch (point) { case EnterPoint::Start: +#if 0 // #TODO legacy getNearestDC(); +#endif appendStep(new StartWidget(this, _account, getData())); break; case EnterPoint::Phone: @@ -293,17 +278,18 @@ void Widget::createLanguageLink() { createLink( Lang::GetOriginalValue(tr::lng_switch_to_this.base), defaultId); - } else if (!suggested.isEmpty() && suggested != currentId && _api) { - _api->request(MTPlangpack_GetStrings( - MTP_string(Lang::CloudLangPackName()), - MTP_string(suggested), - MTP_vector(1, MTP_string("lng_switch_to_this")) - )).done([=](const MTPVector &result) { + } else if (!suggested.isEmpty() && suggested != currentId/* && _api*/) { + _api.request(TLgetLanguagePackStrings( + tl_string(Lang::CloudLangPackName()), + tl_vector(1, tl_string("lng_switch_to_this")) + )).done([=](const TLlanguagePackStrings &result) { +#if 0 // #TODO tdlib lang const auto strings = Lang::Instance::ParseStrings(result); const auto i = strings.find(tr::lng_switch_to_this.base); if (i != strings.end()) { createLink(i->second, suggested); } +#endif }).send(); } } @@ -465,11 +451,13 @@ void Widget::appendStep(Step *step) { step->setShowTermsCallback([=] { showTerms(); }); +#if 0 // #TODO legacy step->setCancelNearestDcCallback([=] { if (_api) { _api->request(base::take(_nearestDcRequestId)).cancel(); } }); +#endif step->setAcceptTermsCallback([=](Fn callback) { acceptTerms(callback); }); @@ -522,7 +510,7 @@ void Widget::acceptTerms(Fn callback) { } void Widget::resetAccount() { - if (_resetRequest || !_api) { + if (_resetRequest/* || !_api*/) { return; } @@ -530,10 +518,8 @@ void Widget::resetAccount() { if (_resetRequest) { return; } - _resetRequest = _api->request(MTPaccount_DeleteAccount( - MTP_flags(0), - MTP_string("Forgot password"), - MTPInputCheckPasswordSRP() + _resetRequest = _api.request(TLdeleteAccount( + tl_string("Forgot password") )).done([=] { _resetRequest = 0; @@ -549,14 +535,14 @@ void Widget::resetAccount() { StackAction::Replace, Animate::Forward); } - }).fail([=](const MTP::Error &error) { + }).fail([=](const Error &error) { _resetRequest = 0; - const auto &type = error.type(); - if (type.startsWith(u"2FA_CONFIRM_WAIT_"_q)) { + const auto &message = error.message; + if (message.startsWith(qstr("2FA_CONFIRM_WAIT_"))) { // #TODO tdlib errors const auto seconds = base::StringViewMid( - type, - u"2FA_CONFIRM_WAIT_"_q.size()).toInt(); + message, + qstr("2FA_CONFIRM_WAIT_").size()).toInt(); const auto days = (seconds + 59) / 86400; const auto hours = ((seconds + 59) % 86400) / 3600; const auto minutes = ((seconds + 59) % 3600) / 60; @@ -596,7 +582,7 @@ void Widget::resetAccount() { Ui::FormatPhone(getData()->phone), lt_when, when))); - } else if (type == u"2FA_RECENT_CONFIRM"_q) { + } else if (type == u"2FA_RECENT_CONFIRM"_q) { // #TODO tdlib errors Ui::show(Ui::MakeInformBox( tr::lng_signin_reset_cancelled())); } else { @@ -614,6 +600,7 @@ void Widget::resetAccount() { })); } +#if 0 // #TODO legacy void Widget::getNearestDC() { if (!_api) { return; @@ -634,6 +621,7 @@ void Widget::getNearestDC() { } }).send(); } +#endif void Widget::showTerms(Fn callback) { if (getData()->termsLock.text.text.isEmpty()) { @@ -875,7 +863,6 @@ void Widget::backRequested() { } Widget::~Widget() { - Instance = nullptr; for (auto step : base::take(_stepHistory)) { delete step; } diff --git a/Telegram/SourceFiles/intro/intro_widget.h b/Telegram/SourceFiles/intro/intro_widget.h index 8b804c623c24b..964e0a0254610 100644 --- a/Telegram/SourceFiles/intro/intro_widget.h +++ b/Telegram/SourceFiles/intro/intro_widget.h @@ -13,6 +13,7 @@ For license and copyright information please follow this link: #include "window/window_lock_widgets.h" #include "core/core_cloud_password.h" #include "media/player/media_player_float.h" +#include "tdb/tdb_sender.h" namespace Main { class Account; @@ -149,7 +150,9 @@ class Widget details::Animate animate); void appendStep(details::Step *step); +#if 0 // #TODO legacy void getNearestDC(); +#endif void showTerms(Fn callback); // FloatDelegate @@ -173,8 +176,10 @@ class Widget bool floatPlayerHandleWheelEvent(QEvent *e) override; const not_null _account; - std::optional _api; + Tdb::Sender _api; +#if 0 // #TODO legacy mtpRequestId _nearestDcRequestId = 0; +#endif std::unique_ptr _showAnimation; @@ -203,7 +208,7 @@ class Widget bool _nextShown = true; Ui::Animations::Simple _nextShownAnimation; - mtpRequestId _resetRequest = 0; + Tdb::RequestId _resetRequest = 0; }; diff --git a/Telegram/SourceFiles/main/main_account.cpp b/Telegram/SourceFiles/main/main_account.cpp index e39d487985c73..e67857e4408b7 100644 --- a/Telegram/SourceFiles/main/main_account.cpp +++ b/Telegram/SourceFiles/main/main_account.cpp @@ -30,6 +30,8 @@ For license and copyright information please follow this link: #include "main/main_session.h" #include "main/main_domain.h" #include "main/main_session_settings.h" +#include "lang/lang_instance.h" +#include "tdb/tdb_account.h" namespace Main { namespace { @@ -45,9 +47,26 @@ constexpr auto kWideIdsTag = ~uint64(0); return result; } +[[nodiscard]] std::unique_ptr CreateTdbAccount(bool testMode) { + return std::make_unique(Tdb::AccountConfig{ + .apiId = ApiId, + .apiHash = ApiHash, + .systemLanguageCode = Lang::GetInstance().systemLangCode(), + .deviceModel = Platform::DeviceModelPretty(), + .systemVersion = Platform::SystemVersionPretty(), + .applicationVersion = QString::fromLatin1(AppVersionStr), + .databaseDirectory = "", + .filesDirectory = "", + .testDc = testMode, + }); +} + } // namespace -Account::Account(not_null domain, const QString &dataName, int index) +Account::Account( + not_null domain, + const QString &dataName, + int index) : _domain(domain) , _local(std::make_unique( this, @@ -78,6 +97,7 @@ std::unique_ptr Account::prepareToStart( } void Account::start(std::unique_ptr config) { + _tdb = CreateTdbAccount(config ? config->isTestMode() : false); _appConfig = std::make_unique(this); startMtp(config ? std::move(config) @@ -236,6 +256,12 @@ rpl::producer Account::sessionChanges() const { return _sessionValue.changes(); } +Tdb::Sender &Account::sender() const { + Expects(_tdb != nullptr); + + return _tdb->sender(); +} + rpl::producer> Account::mtpValue() const { return _mtpValue.value() | rpl::map([](MTP::Instance *instance) { return not_null{ instance }; @@ -581,6 +607,7 @@ void Account::destroyMtpKeys(MTP::AuthKeysList &&keys) { }, _mtpForKeysDestroy->lifetime()); } +#if 0 // #TODO legacy void Account::suggestMainDcId(MTP::DcId mainDcId) { Expects(_mtp != nullptr); @@ -589,7 +616,9 @@ void Account::suggestMainDcId(MTP::DcId mainDcId) { _mtpFields.mainDcId = mainDcId; } } +#endif +#if 0 // #TODO legacy void Account::destroyStaleAuthorizationKeys() { Expects(_mtp != nullptr); @@ -604,6 +633,7 @@ void Account::destroyStaleAuthorizationKeys() { } } } +#endif void Account::setHandleLoginCode(Fn callback) { _handleLoginCode = std::move(callback); diff --git a/Telegram/SourceFiles/main/main_account.h b/Telegram/SourceFiles/main/main_account.h index ba09159457cae..560ef506597f9 100644 --- a/Telegram/SourceFiles/main/main_account.h +++ b/Telegram/SourceFiles/main/main_account.h @@ -22,6 +22,11 @@ class AuthKey; class Config; } // namespace MTP +namespace Tdb { +class Account; +class Sender; +} // namespace Tdb + namespace Main { class Domain; @@ -78,6 +83,13 @@ class Account final : public base::has_weak_ptr { [[nodiscard]] rpl::producer sessionValue() const; [[nodiscard]] rpl::producer sessionChanges() const; + [[nodiscard]] Tdb::Account &tdb() const { + Expects(_tdb != nullptr); + + return *_tdb; + } + [[nodiscard]] Tdb::Sender &sender() const; + [[nodiscard]] MTP::Instance &mtp() const { return *_mtp; } @@ -107,8 +119,12 @@ class Account final : public base::has_weak_ptr { [[nodiscard]] QByteArray serializeMtpAuthorization() const; void setMtpAuthorization(const QByteArray &serialized); +#if 0 // #TODO legacy void suggestMainDcId(MTP::DcId mainDcId); +#endif +#if 0 // #TODO tdlib void destroyStaleAuthorizationKeys(); +#endif void setHandleLoginCode(Fn callback); void handleLoginCode(const QString &code) const; @@ -143,6 +159,7 @@ class Account final : public base::has_weak_ptr { const not_null _domain; const std::unique_ptr _local; + std::unique_ptr _tdb; std::unique_ptr _mtp; rpl::variable _mtpValue; diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h index 701a86e59b2d2..1009cad280328 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -23,7 +23,10 @@ For license and copyright information please follow this link: #include using mtpPrime = int32; +#if 0 // mtp using mtpRequestId = int32; +#endif +using mtpRequestId = int64; using mtpMsgId = uint64; using mtpPingId = uint64; diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.cpp b/Telegram/SourceFiles/mtproto/mtp_instance.cpp index 1794fe8b2c9ea..b6d1bd93e6346 100644 --- a/Telegram/SourceFiles/mtproto/mtp_instance.cpp +++ b/Telegram/SourceFiles/mtproto/mtp_instance.cpp @@ -2037,18 +2037,18 @@ void Instance::sendRequest( crl::time msCanWait, bool needsLayer, mtpRequestId afterRequestId) { - return _private->sendRequest( - requestId, - std::move(request), - std::move(callbacks), - shiftedDcId, - msCanWait, - needsLayer, - afterRequestId); + //return _private->sendRequest( // While migrating just ignore requests. + // requestId, + // std::move(request), + // std::move(callbacks), + // shiftedDcId, + // msCanWait, + // needsLayer, + // afterRequestId); } void Instance::sendAnything(ShiftedDcId shiftedDcId, crl::time msCanWait) { - _private->getSession(shiftedDcId)->sendAnything(msCanWait); + //_private->getSession(shiftedDcId)->sendAnything(msCanWait); } rpl::lifetime &Instance::lifetime() { diff --git a/Telegram/SourceFiles/tdb/tdb_instance.cpp b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp similarity index 82% rename from Telegram/SourceFiles/tdb/tdb_instance.cpp rename to Telegram/SourceFiles/tdb/details/tdb_instance.cpp index 304e9d495e240..34f19897391d4 100644 --- a/Telegram/SourceFiles/tdb/tdb_instance.cpp +++ b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp @@ -5,13 +5,14 @@ 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 "tdb/tdb_instance.h" +#include "tdb/details/tdb_instance.h" #include #include #include #include +namespace Tdb::details { namespace { using namespace ::td; @@ -20,8 +21,6 @@ namespace api = td_api; } // namespace -namespace Tdb::details { - std::optional ParseError(ExternalResponse response) { if (response->get_id() != api::error::ID) { return std::nullopt; @@ -29,10 +28,6 @@ std::optional ParseError(ExternalResponse response) { return Error(tl_from(response)); } -} // namespace Tdb::details - -namespace Tdb { - class Instance::Manager final : public std::enable_shared_from_this { struct PrivateTag { @@ -78,7 +73,9 @@ class Instance::Impl final { explicit Impl(InstanceConfig &&config); ~Impl(); - RequestId sendPrepared( + [[nodiscard]] RequestId allocateRequestId() const; + void sendPrepared( + RequestId requestId, ExternalGenerator &&request, ExternalCallback &&callback); void cancel(RequestId requestId); @@ -87,25 +84,30 @@ class Instance::Impl final { template < typename Request, typename = std::enable_if_t>> - RequestId send( + void send( + RequestId requestId, Request &&request, FnMut &&done, FnMut &&fail) { return sendPrepared( + requestId, tl_to_generator(std::move(request)), - details::PrepareCallback( + PrepareCallback( std::move(done), std::move(fail))); } - void handleUpdate(const TLupdate &update); + void handleUpdate(TLupdate &&update); + [[nodiscard]] rpl::producer updates() const; private: void sendTdlibParameters(InstanceConfig &&config); const std::shared_ptr _manager; ClientManager::ClientId _client; + QMutex _activeRequestsMutex; base::flat_set _activeRequests; + rpl::event_stream _updates; }; @@ -119,8 +121,6 @@ Instance::Manager::Manager(PrivateTag) std::shared_ptr Instance::Manager::Instance() { auto result = ManagerInstance.lock(); if (!result) { - ClientManager::execute( - td_api::make_object(0)); ManagerInstance = result = std::make_shared(PrivateTag{}); } return result; @@ -203,17 +203,17 @@ void Instance::Manager::loop() { } } const auto clientId = response.client_id; - const auto requestId = response.request_id; + const auto requestId = RequestId(response.request_id); const auto object = response.object.get(); if (!requestId) { crl::on_main(weak_from_this(), [ this, clientId, update = tl_from(object) - ] { + ]() mutable { const auto i = _clients.find(clientId); if (i != end(_clients)) { - i->second->handleUpdate(update); + i->second->handleUpdate(std::move(update)); } }); continue; @@ -251,11 +251,16 @@ Instance::Impl::~Impl() { _manager->destroyClient(_client); } -RequestId Instance::Impl::sendPrepared( +RequestId Instance::Impl::allocateRequestId() const { + return _manager->allocateRequestId(); +} + +void Instance::Impl::sendPrepared( + RequestId requestId, ExternalGenerator &&request, ExternalCallback &&callback) { - const auto requestId = _manager->allocateRequestId(); if (callback) { + QMutexLocker lock(&_activeRequestsMutex); _activeRequests.emplace(requestId); } crl::async([ @@ -271,37 +276,42 @@ RequestId Instance::Impl::sendPrepared( std::move(request), std::move(callback)); }); - return requestId; } void Instance::Impl::cancel(RequestId requestId) { + QMutexLocker lock(&_activeRequestsMutex); _activeRequests.remove(requestId); } bool Instance::Impl::shouldInvokeHandler(RequestId requestId) { + QMutexLocker lock(&_activeRequestsMutex); return _activeRequests.remove(requestId); } -void Instance::Impl::handleUpdate(const TLupdate &update) { +void Instance::Impl::handleUpdate(TLupdate &&update) { update.match([&](const TLDupdateAuthorizationState &data) { data.vauthorization_state().match([]( const TLDauthorizationStateWaitTdlibParameters &) { - }, [&](const TLDauthorizationStateWaitEncryptionKey &data) { - send(TLcheckDatabaseEncryptionKey(tl_bytes()), nullptr, nullptr); - }, [](const auto &) { - + }, [&](const auto &) { + _updates.fire(std::move(update)); }); - }, [](const auto &) { + }, [&](const auto &) { + _updates.fire(std::move(update)); }); } +rpl::producer Instance::Impl::updates() const { + return _updates.events(); +} + void Instance::Impl::sendTdlibParameters(InstanceConfig &&config) { send( + allocateRequestId(), TLsetTdlibParameters( tl_tdlibParameters( - tl_bool(false), // use_test_dc - tl_string(), // database_directory - tl_string(), // files_directory + tl_bool(config.testDc), + tl_string(config.databaseDirectory), + tl_string(config.filesDirectory), // files_directory tl_bool(true), // use_file_database tl_bool(true), // use_chat_info_database tl_bool(true), // use_message_database @@ -324,14 +334,26 @@ Instance::Instance(InstanceConfig &&config) Instance::~Instance() = default; -RequestId Instance::sendPrepared( +RequestId Instance::allocateRequestId() const { + return _impl->allocateRequestId(); +} + +void Instance::sendPrepared( + RequestId requestId, ExternalGenerator &&request, ExternalCallback &&callback) { - return _impl->sendPrepared(std::move(request), std::move(callback)); + _impl->sendPrepared( + requestId, + std::move(request), + std::move(callback)); } void Instance::cancel(RequestId requestId) { _impl->cancel(requestId); } -} // namespace Tdb +rpl::producer Instance::updates() const { + return _impl->updates(); +} + +} // namespace Tdb::details diff --git a/Telegram/SourceFiles/tdb/tdb_instance.h b/Telegram/SourceFiles/tdb/details/tdb_instance.h similarity index 82% rename from Telegram/SourceFiles/tdb/tdb_instance.h rename to Telegram/SourceFiles/tdb/details/tdb_instance.h index 5a1b4be2b5723..65f8953471052 100644 --- a/Telegram/SourceFiles/tdb/tdb_instance.h +++ b/Telegram/SourceFiles/tdb/details/tdb_instance.h @@ -11,6 +11,8 @@ For license and copyright information please follow this link: namespace Tdb::details { +using RequestId = int64; + [[nodiscard]] std::optional ParseError(ExternalResponse); template @@ -49,12 +51,6 @@ template }; } -} // namespace Tdb::details - -namespace Tdb { - -using RequestId = uint64; - struct InstanceConfig { int32 apiId = 0; QString apiHash; @@ -62,33 +58,45 @@ struct InstanceConfig { QString deviceModel; QString systemVersion; QString applicationVersion; + QString databaseDirectory; + QString filesDirectory; + bool testDc = false; }; class Instance final { public: + // Main thread. explicit Instance(InstanceConfig &&config); ~Instance(); + // Thread safe. + [[nodiscard]] RequestId allocateRequestId() const; template < typename Request, typename = std::enable_if_t>> - RequestId send( + void send( + RequestId requestId, Request &&request, FnMut &&done, FnMut &&fail) { - return sendPrepared( + sendPrepared( + requestId, tl_to_generator(std::move(request)), - details::PrepareCallback( + PrepareCallback( std::move(done), std::move(fail))); } void cancel(RequestId requestId); + // Main thread. + [[nodiscard]] rpl::producer updates() const; + private: class Manager; class Impl; - RequestId sendPrepared( + void sendPrepared( + RequestId requestId, ExternalGenerator &&request, ExternalCallback &&callback); @@ -98,4 +106,4 @@ class Instance final { }; -} // namespace Tdb +} // namespace Tdb::details diff --git a/Telegram/SourceFiles/tdb/tdb_account.cpp b/Telegram/SourceFiles/tdb/tdb_account.cpp new file mode 100644 index 0000000000000..4e763e3c1bafc --- /dev/null +++ b/Telegram/SourceFiles/tdb/tdb_account.cpp @@ -0,0 +1,43 @@ +/* +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 "tdb/tdb_account.h" + +namespace Tdb { + +Account::Account(AccountConfig &&config) +: _instance(std::move(config)) +, _sender(&_instance) { + _instance.updates( + ) | rpl::start_with_next([=](TLupdate &&update) { + if (!consumeUpdate(update)) { + _updates.fire(std::move(update)); + } + }, _lifetime); +} + +rpl::producer Account::updates() const { + return _updates.events(); +} + +bool Account::consumeUpdate(const TLupdate &update) { + return update.match([&](const TLDupdateAuthorizationState &data) { + return data.vauthorization_state().match([&]( + const TLDauthorizationStateWaitEncryptionKey &data) { + _sender.request( + TLcheckDatabaseEncryptionKey(tl_bytes()) + ).send(); + return true; + }, [&](const auto &) { + return false; + }); + }, [](const auto &) { + return false; + }); +} + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/tdb_account.h b/Telegram/SourceFiles/tdb/tdb_account.h new file mode 100644 index 0000000000000..d803f431d231d --- /dev/null +++ b/Telegram/SourceFiles/tdb/tdb_account.h @@ -0,0 +1,42 @@ +/* +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 +*/ +#pragma once + +#include "tdb/details/tdb_instance.h" +#include "tdb/tdb_sender.h" + +namespace Tdb { + +using AccountConfig = details::InstanceConfig; + +class Account final { +public: + explicit Account(AccountConfig &&config); + + [[nodiscard]] Sender &sender() { + return _sender; + } + + [[nodiscard]] rpl::producer updates() const; + + [[nodiscard]] rpl::lifetime &lifetime() { + return _lifetime; + } + +private: + [[nodiscard]] bool consumeUpdate(const TLupdate &update); + + details::Instance _instance; + Sender _sender; + rpl::event_stream _updates; + + rpl::lifetime _lifetime; + +}; + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/tdb_pch.h b/Telegram/SourceFiles/tdb/tdb_pch.h index f4f87cd01f884..8375bde3dc68f 100644 --- a/Telegram/SourceFiles/tdb/tdb_pch.h +++ b/Telegram/SourceFiles/tdb/tdb_pch.h @@ -16,4 +16,5 @@ For license and copyright information please follow this link: #include "base/flat_map.h" #include "base/flat_set.h" -#include "tdb_tl-scheme.h" +#include "tdb/tdb_tl_scheme.h" +#include "tdb/details/tdb_instance.h" diff --git a/Telegram/SourceFiles/tdb/tdb_sender.cpp b/Telegram/SourceFiles/tdb/tdb_sender.cpp new file mode 100644 index 0000000000000..c34ed146ada28 --- /dev/null +++ b/Telegram/SourceFiles/tdb/tdb_sender.cpp @@ -0,0 +1,79 @@ +/* +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 "tdb/tdb_sender.h" + +namespace Tdb { + +Sender::RequestBuilder::RequestBuilder(not_null sender) noexcept +: _sender(sender) +, _requestId(_sender->_instance->allocateRequestId()) { +} + +auto Sender::RequestBuilder::takeOnFail() noexcept -> FailHandler { + return std::move(_fail); +} + +not_null Sender::RequestBuilder::sender() const noexcept { + return _sender; +} + +RequestId Sender::RequestBuilder::requestId() const noexcept { + return _requestId; +} + +Sender::SentRequestWrap::SentRequestWrap( + not_null sender, + RequestId requestId) +: _sender(sender) +, _requestId(requestId) { +} + +void Sender::SentRequestWrap::cancel() { + if (_requestId) { + _sender->senderRequestCancel(_requestId); + } +} + +Sender::Sender(not_null instance) noexcept +: _instance(instance) { +} + +Sender::Sender(not_null other) noexcept +: Sender(other->_instance) { +} + +Sender::Sender(Sender &other) noexcept +: Sender(other._instance) { +} + +void Sender::senderRequestRegister(RequestId requestId) { + _requests.emplace(_instance, requestId); +} + +void Sender::senderRequestHandled(RequestId requestId) { + const auto i = _requests.find(requestId); + if (i != end(_requests)) { + i->handled(); + _requests.erase(i); + } +} + +void Sender::senderRequestCancel(RequestId requestId) { + const auto i = _requests.find(requestId); + if (i != end(_requests)) { + _requests.erase(i); + } +} + +void Sender::requestCancellingDiscard() noexcept { + for (auto &request : base::take(_requests)) { + request.handled(); + } +} + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/tdb_sender.h b/Telegram/SourceFiles/tdb/tdb_sender.h new file mode 100644 index 0000000000000..41454c00e8875 --- /dev/null +++ b/Telegram/SourceFiles/tdb/tdb_sender.h @@ -0,0 +1,320 @@ +/* +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 +*/ +#pragma once + +#include "tdb/details/tdb_instance.h" + +namespace Tdb { + +using details::RequestId; + +class Sender final { + class RequestBuilder { + public: + RequestBuilder(const RequestBuilder &other) = delete; + RequestBuilder &operator=(const RequestBuilder &other) = delete; + RequestBuilder &operator=(RequestBuilder &&other) = delete; + + protected: + template + using DoneHandler = FnMut; + using FailHandler = FnMut; + + template + static constexpr bool IsCallable + = rpl::details::is_callable_plain_v; + + explicit RequestBuilder(not_null sender) noexcept; + RequestBuilder(RequestBuilder &&other) = default; + + template + [[nodiscard]] DoneHandler makeDoneHandler( + Handler &&handler) noexcept { + return [ + sender = _sender, + requestId = _requestId, + handler = std::forward(handler) + ](const Result &result) mutable { + auto onstack = std::move(handler); + sender->senderRequestHandled(requestId); + + if (!onstack) { + return; + } else if constexpr (IsCallable< + Handler, + const Result&, + RequestId>) { + onstack(result, requestId); + } else if constexpr (IsCallable) { + onstack(result); + } else if constexpr (IsCallable) { + onstack(); + } else { + static_assert(false_t(Handler{}), "Bad done handler."); + } + }; + } + + template + void setFailHandler(Handler &&handler) noexcept { + _fail = [ + sender = _sender, + requestId = _requestId, + handler = std::forward(handler) + ](const Error &error) mutable { + auto onstack = handler; + sender->senderRequestHandled(requestId); + + if (!onstack) { + return; + } else if constexpr (IsCallable< + Handler, + const Error&, + RequestId>) { + onstack(error, requestId); + } else if constexpr (IsCallable) { + onstack(error); + } else if constexpr (IsCallable) { + onstack(); + } else { + static_assert(false_t(Handler{}), "Bad fail handler."); + } + }; + } + + [[nodiscard]] FailHandler takeOnFail() noexcept; + [[nodiscard]] not_null sender() const noexcept; + RequestId requestId() const noexcept; + + private: + not_null _sender; + RequestId _requestId = 0; + FailHandler _fail; + + }; + +public: + explicit Sender(not_null instance) noexcept; + explicit Sender(not_null other) noexcept; + explicit Sender(Sender &other) noexcept; + + template + class SpecificRequestBuilder final : public RequestBuilder { + private: + friend class Sender; + SpecificRequestBuilder( + not_null sender, + Request &&request) noexcept + : RequestBuilder(sender) + , _request(std::move(request)) { + } + SpecificRequestBuilder(SpecificRequestBuilder &&other) = default; + + public: + using Result = typename Request::ResponseType; + [[nodiscard]] SpecificRequestBuilder &done( + FnMut callback) { + _done = makeDoneHandler(std::move(callback)); + return *this; + } + [[nodiscard]] SpecificRequestBuilder &done( + FnMut callback) { + _done = makeDoneHandler(std::move(callback)); + return *this; + } + [[nodiscard]] SpecificRequestBuilder &done( + FnMut callback) { + _done = makeDoneHandler(std::move(callback)); + return *this; + } + + [[nodiscard]] SpecificRequestBuilder &fail( + Fn callback) noexcept { + setFailHandler(std::move(callback)); + return *this; + } + [[nodiscard]] SpecificRequestBuilder &fail( + Fn callback) noexcept { + setFailHandler(std::move(callback)); + return *this; + } + [[nodiscard]] SpecificRequestBuilder &fail( + Fn callback) noexcept { + setFailHandler(std::move(callback)); + return *this; + } + + RequestId send() noexcept { + const auto id = requestId(); + sender()->_instance->send( + id, + std::move(_request), + std::move(_done), + takeOnFail()); + sender()->senderRequestRegister(id); + return id; + } + + private: + DoneHandler _done; + Request _request; + + }; + + class SentRequestWrap { + private: + friend class Sender; + SentRequestWrap(not_null sender, RequestId requestId); + + public: + void cancel(); + + private: + not_null _sender; + RequestId _requestId = 0; + + }; + + template < + typename Request, + typename = std::enable_if_t>, + typename = typename Request::ResponseType> + [[nodiscard]] SpecificRequestBuilder request( + Request &&request) noexcept; + [[nodiscard]] SentRequestWrap request(RequestId requestId) noexcept; + [[nodiscard]] auto requestCanceller() noexcept; + void requestCancellingDiscard() noexcept; + +private: + class RequestWrap { + public: + constexpr RequestWrap( + not_null instance, + RequestId requestId) noexcept; + + RequestWrap(const RequestWrap &other) = delete; + RequestWrap &operator=(const RequestWrap &other) = delete; + constexpr RequestWrap(RequestWrap &&other) noexcept; + RequestWrap &operator=(RequestWrap &&other) noexcept; + + constexpr RequestId id() const noexcept; + constexpr void handled() const noexcept; + + ~RequestWrap(); + + private: + void cancelRequest() noexcept; + + const not_null _instance; + mutable RequestId _id = 0; + + }; + + struct RequestWrapComparator { + using is_transparent = std::true_type; + + struct helper { + RequestId requestId = 0; + + constexpr helper() noexcept = default; + constexpr helper(const helper &other) noexcept = default; + constexpr helper(RequestId requestId) noexcept + : requestId(requestId) { + } + constexpr helper(const RequestWrap &request) noexcept + : requestId(request.id()) { + } + constexpr bool operator<(helper other) const noexcept { + return requestId < other.requestId; + } + }; + constexpr bool operator()( + const helper &&lhs, + const helper &&rhs) const { + return lhs < rhs; + } + + }; + + template + friend class SpecificRequestBuilder; + friend class RequestBuilder; + friend class RequestWrap; + friend class SentRequestWrap; + + void senderRequestRegister(RequestId requestId); + void senderRequestHandled(RequestId requestId); + void senderRequestCancel(RequestId requestId); + + const not_null _instance; + base::flat_set _requests; + +}; + +template +Sender::SpecificRequestBuilder Sender::request(Request &&request) noexcept { + return SpecificRequestBuilder(this, std::move(request)); +} + +inline Sender::SentRequestWrap Sender::request(RequestId requestId) noexcept { + return SentRequestWrap(this, requestId); +} + +inline auto Sender::requestCanceller() noexcept { + return [this](RequestId requestId) { + request(requestId).cancel(); + }; +} + +inline constexpr Sender::RequestWrap::RequestWrap( + not_null instance, + RequestId requestId) noexcept +: _instance(instance) +, _id(requestId) { +} + +inline constexpr Sender::RequestWrap::RequestWrap( + RequestWrap &&other) noexcept +: _instance(other._instance) +, _id(base::take(other._id)) { +} + +inline auto Sender::RequestWrap::operator=( + RequestWrap &&other) noexcept -> RequestWrap & { + Expects(_instance == other._instance); + + if (_id != other._id) { + cancelRequest(); + _id = base::take(other._id); + } + return *this; +} + +inline constexpr RequestId Sender::RequestWrap::id() const noexcept { + return _id; +} + +inline constexpr void Sender::RequestWrap::handled() const noexcept { + _id = 0; +} + +inline Sender::RequestWrap::~RequestWrap() { + cancelRequest(); +} + +inline void Sender::RequestWrap::cancelRequest() noexcept { + if (_id) { + _instance->cancel(_id); + } +} + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/tdb_tl_scheme.h b/Telegram/SourceFiles/tdb/tdb_tl_scheme.h index fab20f72746f7..d9b59015cf0f6 100644 --- a/Telegram/SourceFiles/tdb/tdb_tl_scheme.h +++ b/Telegram/SourceFiles/tdb/tdb_tl_scheme.h @@ -29,6 +29,10 @@ struct Error { , message(message) { } + [[nodiscard]] static Error Local(const QString &message) { + return Error{ -555, message }; + } + int code = 0; QString message; diff --git a/Telegram/cmake/td_tdb.cmake b/Telegram/cmake/td_tdb.cmake index 9e7cec9b5e72f..de0a929380390 100644 --- a/Telegram/cmake/td_tdb.cmake +++ b/Telegram/cmake/td_tdb.cmake @@ -15,8 +15,10 @@ generate_tdb_tl(td_tdb ${src_loc}/tdb/details/tdb_tl_generate.py ${libs_loc}/td/ target_precompile_headers(td_tdb PRIVATE ${src_loc}/tdb/tdb_pch.h) nice_target_sources(td_tdb ${src_loc} PRIVATE - tdb/tdb_instance.cpp - tdb/tdb_instance.h + tdb/tdb_account.cpp + tdb/tdb_account.h + tdb/tdb_sender.cpp + tdb/tdb_sender.h tdb/tdb_tl_scheme.h tdb/tdb_pch.h @@ -27,8 +29,12 @@ PRIVATE tdb/details/tdb_tl_core_conversion_to.cpp tdb/details/tdb_tl_core_conversion_to.h tdb/details/tdb_tl_generate.py + tdb/details/tdb_instance.cpp + tdb/details/tdb_instance.h ) +target_sources(td_tdb PRIVATE ${libs_loc}/td/td/generate/scheme/td_api.tl) + target_include_directories(td_tdb PUBLIC ${src_loc} From 7ef2dbfe8afdef4e173d62b552689100f1d41f48 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 21 Apr 2021 16:44:44 +0400 Subject: [PATCH 007/350] Add proof-of-concept authorization. --- Telegram/SourceFiles/data/data_peer_id.h | 2 + Telegram/SourceFiles/data/data_session.cpp | 87 +++++++++++++ Telegram/SourceFiles/data/data_session.h | 3 + .../intro/intro_password_check.cpp | 26 +++- .../SourceFiles/intro/intro_password_check.h | 2 + Telegram/SourceFiles/intro/intro_phone.cpp | 28 +++- Telegram/SourceFiles/intro/intro_phone.h | 6 + Telegram/SourceFiles/intro/intro_qr.cpp | 29 ++--- Telegram/SourceFiles/intro/intro_qr.h | 3 +- Telegram/SourceFiles/intro/intro_start.cpp | 21 ++- Telegram/SourceFiles/intro/intro_start.h | 4 + Telegram/SourceFiles/intro/intro_step.cpp | 123 ++++++++++++++++++ Telegram/SourceFiles/intro/intro_step.h | 12 ++ Telegram/SourceFiles/main/main_account.cpp | 96 +++++++++++--- Telegram/SourceFiles/main/main_account.h | 19 +++ Telegram/SourceFiles/main/main_domain.cpp | 23 ++++ Telegram/SourceFiles/main/main_domain.h | 1 + Telegram/SourceFiles/main/main_session.cpp | 2 +- Telegram/SourceFiles/main/main_session.h | 10 ++ .../SourceFiles/storage/storage_account.cpp | 12 ++ .../SourceFiles/storage/storage_account.h | 2 + .../SourceFiles/tdb/details/tdb_instance.cpp | 25 +++- .../SourceFiles/tdb/details/tdb_instance.h | 25 +++- Telegram/SourceFiles/tdb/tdb_account.h | 2 + Telegram/SourceFiles/tdb/tdb_sender.h | 18 +-- 25 files changed, 527 insertions(+), 54 deletions(-) diff --git a/Telegram/SourceFiles/data/data_peer_id.h b/Telegram/SourceFiles/data/data_peer_id.h index 1f99d955f11f3..e4cf6cc55239d 100644 --- a/Telegram/SourceFiles/data/data_peer_id.h +++ b/Telegram/SourceFiles/data/data_peer_id.h @@ -28,6 +28,8 @@ struct ChatIdType { } constexpr ChatIdType(MTPlong value) noexcept : bare(value.v) { } + constexpr ChatIdType(tl::int64_type value) noexcept : bare(value.v) { + } friend inline constexpr auto operator<=>( ChatIdType, diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index bc124d71fbcf9..cc4b0007b563d 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -86,6 +86,7 @@ For license and copyright information please follow this link: namespace Data { namespace { +using namespace Tdb; using ViewElement = HistoryView::Element; // s: box 100x100 @@ -1059,6 +1060,92 @@ not_null Session::processChat(const MTPChat &data) { return result; } +not_null Session::processUser(const TLuser &user) { + const auto &data = user.match([]( + const auto &data) -> const TLDuser& { + return data; + }); + const auto result = this->user(data.vid().v); + auto minimal = false; + + using UpdateFlag = PeerUpdate::Flag; + auto flags = UpdateFlag::None | UpdateFlag::None; + + const auto canShareThisContact = result->canShareThisContactFast(); + + const auto firstName = data.vtype().match([]( + const TLDuserTypeDeleted &) { + return tr::lng_deleted(tr::now); + }, [&](const auto &) { + return TextUtilities::SingleLine(data.vfirst_name().v); + }); + const auto lastName = TextUtilities::SingleLine(data.vlast_name().v); + const auto userName = data.vusername().v; + const auto phone = data.vphone_number().v; + const auto nameChanged = (result->firstName != firstName) + || (result->lastName != lastName); + + const auto phoneChanged = (result->phone() != data.vphone_number().v); + if (phoneChanged) { + result->setPhone(data.vphone_number().v); + flags |= UpdateFlag::PhoneNumber; + } + const auto isSelf = (UserId(data.vid().v) == session().userId()); + const auto showPhone = !result->isServiceUser() + && !tl_is_true(data.vis_support()) + && !isSelf + && !tl_is_true(data.vis_contact()) + && !tl_is_true(data.vis_mutual_contact()); + const auto showPhoneChanged = !result->isServiceUser() + && !isSelf + && ((showPhone && result->isContact()) + || (!showPhone + && !result->isContact() + && !result->phone().isEmpty())); + const auto phoneName = (showPhoneChanged || phoneChanged || nameChanged) + ? ((showPhone && !phone.isEmpty()) + ? Ui::FormatPhone(phone) + : QString()) + : result->nameOrPhone; + result->setName(firstName, lastName, phoneName, userName); + + result->setPhoto(MTP_userProfilePhotoEmpty()); // #TODO tdlib + result->setUnavailableReasons({}); // #TODO tdlib + //result->setFlags(MTPDuser_ClientFlag::f_inaccessible | 0); + //result->setFlags(MTPDuser::Flag::f_deleted); + result->setBotInfoVersion(-1); // #TODO tdlib + result->setIsContact(tl_is_true(data.vis_contact())); + if (canShareThisContact != result->canShareThisContactFast()) { + flags |= UpdateFlag::CanShareContact; + } + + if (minimal) { + if (!result->isMinimalLoaded()) { + result->setLoadedStatus(PeerData::LoadedStatus::Minimal); + } + } else if (!result->isFullLoaded() + && (!result->isSelf() || !result->phone().isEmpty())) { + result->setLoadedStatus(PeerData::LoadedStatus::Full); + } + + //data.vstatus() // #TODO tdlib + //if (status && !minimal) { + // const auto oldOnlineTill = result->onlineTill; + // const auto newOnlineTill = ApiWrap::OnlineTillFromStatus( + // *status, + // oldOnlineTill); + // if (oldOnlineTill != newOnlineTill) { + // result->onlineTill = newOnlineTill; + // flags |= UpdateFlag::OnlineStatus; + // } + //} + + if (flags) { + session().changes().peerUpdated(result, flags); + } + return result; +} + UserData *Session::processUsers(const MTPVector &data) { auto result = (UserData*)nullptr; for (const auto &user : data.v) { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index df6dc5019a14d..bc54330fdfae6 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -16,6 +16,7 @@ For license and copyright information please follow this link: #include "history/history_location_manager.h" #include "base/timer.h" #include "base/flags.h" +#include "tdb/tdb_tl_scheme.h" class Image; class HistoryItem; @@ -185,6 +186,8 @@ class Session final { not_null processUser(const MTPUser &data); not_null processChat(const MTPChat &data); + not_null processUser(const Tdb::TLuser &user); + // Returns last user, if there were any. UserData *processUsers(const MTPVector &data); PeerData *processChats(const MTPVector &data); diff --git a/Telegram/SourceFiles/intro/intro_password_check.cpp b/Telegram/SourceFiles/intro/intro_password_check.cpp index 1c4b4379964e5..090394188304e 100644 --- a/Telegram/SourceFiles/intro/intro_password_check.cpp +++ b/Telegram/SourceFiles/intro/intro_password_check.cpp @@ -24,6 +24,11 @@ For license and copyright information please follow this link: namespace Intro { namespace details { +namespace { + +using namespace Tdb; + +} // namespace PasswordCheckWidget::PasswordCheckWidget( QWidget *parent, @@ -400,11 +405,30 @@ void PasswordCheckWidget::submit() { } else { hideError(); - const auto password = _pwdField->getLastText().toUtf8(); + _sentRequest = true; + const auto password = _pwdField->getLastText(); + api().request(TLcheckAuthenticationPassword( + tl_string(password) + )).fail([=](const Error &error) { + passwordSubmitFail(error); + }).send(); +#if 0 // #TODO legacy _passwordHash = Core::ComputeCloudPasswordHash( _passwordState.mtp.request.algo, bytes::make_span(password)); checkPasswordHash(); +#endif + } +} + +void PasswordCheckWidget::passwordSubmitFail(const Error &error) { + _sentRequest = false; + if (error.message.contains(u"PASSWORD_HASH_INVALID")) { + showError(tr::lng_signin_bad_password()); + _pwdField->selectAll(); + _pwdField->showError(); + } else { + showError(rpl::single(error.message)); } } diff --git a/Telegram/SourceFiles/intro/intro_password_check.h b/Telegram/SourceFiles/intro/intro_password_check.h index ddd11755128bc..29d5f52cb7453 100644 --- a/Telegram/SourceFiles/intro/intro_password_check.h +++ b/Telegram/SourceFiles/intro/intro_password_check.h @@ -63,6 +63,8 @@ class PasswordCheckWidget final : public Step { void passwordChecked(); void serverError(); + void passwordSubmitFail(const Tdb::Error &error); + Core::CloudPasswordState _passwordState; crl::time _lastSrpIdInvalidTime = 0; bytes::vector _passwordHash; diff --git a/Telegram/SourceFiles/intro/intro_phone.cpp b/Telegram/SourceFiles/intro/intro_phone.cpp index 5616853ca5fc2..61bbe3b379a53 100644 --- a/Telegram/SourceFiles/intro/intro_phone.cpp +++ b/Telegram/SourceFiles/intro/intro_phone.cpp @@ -32,7 +32,9 @@ namespace Intro { namespace details { namespace { -bool AllowPhoneAttempt(const QString &phone) { +using namespace Tdb; + +[[nodiscard]] bool AllowPhoneAttempt(const QString &phone) { const auto digits = ranges::count_if( phone, [](QChar ch) { return ch.isNumber(); }); @@ -165,7 +167,6 @@ void PhoneWidget::submit() { return; } -#if 0 // #TODO tdlib cancelNearestDcRequest(); // Check if such account is authorized already. @@ -188,9 +189,22 @@ void PhoneWidget::submit() { hidePhoneError(); +#if 0 // #TODO legacy _checkRequestTimer.callEach(1000); +#endif _sentPhone = phone; + + api().request(TLsetAuthenticationPhoneNumber( + tl_string(phone), + tl_phoneNumberAuthenticationSettings( + tl_bool(false), // allow_flash_call + tl_bool(false), // is_current_phone_number + tl_bool(false)) // allow_sms_retriever_api + )).fail([=](const Error &error) { + phoneSetFail(error); + }).send(); +#if 0 // #TODO legacy api().instance().setUserPhone(_sentPhone); _sentRequest = api().request(MTPauth_SendCode( MTP_string(_sentPhone), @@ -228,6 +242,7 @@ void PhoneWidget::checkRequest() { #endif } +#if 0 // #TODO legacy void PhoneWidget::phoneSubmitDone(const MTPauth_SentCode &result) { stopCheck(); _sentRequest = 0; @@ -273,6 +288,15 @@ void PhoneWidget::phoneSubmitFail(const MTP::Error &error) { showPhoneError(rpl::single(Lang::Hard::ServerError())); } } +#endif + +bool PhoneWidget::handleAuthorizationState( + const TLauthorizationState &state) { + return Step::handleAuthorizationState(state); +} + +void PhoneWidget::phoneSetFail(const Error &error) { +} QString PhoneWidget::fullNumber() const { return _code->getLastText() + _phone->getLastText(); diff --git a/Telegram/SourceFiles/intro/intro_phone.h b/Telegram/SourceFiles/intro/intro_phone.h index 3770df59cfda1..387cdbf8f7fcb 100644 --- a/Telegram/SourceFiles/intro/intro_phone.h +++ b/Telegram/SourceFiles/intro/intro_phone.h @@ -49,8 +49,14 @@ class PhoneWidget final : public Step { void checkRequest(); void countryChanged(); +#if 0 // #TODO legacy void phoneSubmitDone(const MTPauth_SentCode &result); void phoneSubmitFail(const MTP::Error &error); +#endif + + bool handleAuthorizationState( + const Tdb::TLauthorizationState &state) override; + void phoneSetFail(const Tdb::Error &error); QString fullNumber() const; void stopCheck(); diff --git a/Telegram/SourceFiles/intro/intro_qr.cpp b/Telegram/SourceFiles/intro/intro_qr.cpp index 06cacee6c0039..1cc48cd4b6c4a 100644 --- a/Telegram/SourceFiles/intro/intro_qr.cpp +++ b/Telegram/SourceFiles/intro/intro_qr.cpp @@ -27,7 +27,6 @@ For license and copyright information please follow this link: #include "core/update_checker.h" #include "base/unixtime.h" #include "qr/qr_generate.h" -#include "tdb/tdb_account.h" #include "styles/style_intro.h" namespace Intro { @@ -196,11 +195,6 @@ QrWidget::QrWidget( }, lifetime()); #endif - account->tdb().updates( - ) | rpl::start_with_next([=](const TLupdate &update) { - handleUpdate(update); - }, lifetime()); - setupControls(); account->mtp().mainDcIdValue( ) | rpl::start_with_next([=] { @@ -240,15 +234,16 @@ void QrWidget::checkForTokenUpdate(const MTPUpdate &update) { } #endif -void QrWidget::handleUpdate(const TLupdate &update) { - update.match([&](const TLDupdateAuthorizationState &data) { - data.vauthorization_state().match( - [&](const TLDauthorizationStateWaitOtherDeviceConfirmation &data) { - _qrLinks.fire_copy(data.vlink().v); - }, [](const auto &) { - }); - }, [](const auto &) { +bool QrWidget::handleAuthorizationState(const TLauthorizationState &state) { + state.match([&]( + const TLDauthorizationStateWaitOtherDeviceConfirmation &data) { + _qrLinks.fire_copy(data.vlink().v); + }, [&](const auto &) { + if (!Step::handleAuthorizationState(state)) { + goBack(); + } }); + return true; } void QrWidget::submit() { @@ -343,16 +338,14 @@ void QrWidget::refreshCode() { TLgetAuthorizationState() ).done([=](const TLauthorizationState &result) { result.match( - [&](const TLDauthorizationStateWaitOtherDeviceConfirmation &data) { - _qrLinks.fire_copy(data.vlink().v); - }, [&](const TLDauthorizationStateWaitPhoneNumber &data) { + [&](const TLDauthorizationStateWaitPhoneNumber &data) { api().request(TLrequestQrCodeAuthentication( tl_vector(0) )).fail([=](const Error &error) { showTokenError(error); }).send(); }, [&](const auto &) { - showTokenError(Error::Local("Wrong authorizationState.")); + handleAuthorizationState(result); }); }).fail([=](const Error &error) { showTokenError(error); diff --git a/Telegram/SourceFiles/intro/intro_qr.h b/Telegram/SourceFiles/intro/intro_qr.h index 61718e3974454..28a08bab74208 100644 --- a/Telegram/SourceFiles/intro/intro_qr.h +++ b/Telegram/SourceFiles/intro/intro_qr.h @@ -49,7 +49,8 @@ class QrWidget final : public Step { void showToken(const QByteArray &token); void done(const MTPauth_Authorization &authorization); - void handleUpdate(const Tdb::TLupdate &update); + bool handleAuthorizationState( + const Tdb::TLauthorizationState &state) override; rpl::event_stream _qrLinks; #if 0 // #TODO legacy diff --git a/Telegram/SourceFiles/intro/intro_start.cpp b/Telegram/SourceFiles/intro/intro_start.cpp index 1dc687e4af73e..3d6062306c4f8 100644 --- a/Telegram/SourceFiles/intro/intro_start.cpp +++ b/Telegram/SourceFiles/intro/intro_start.cpp @@ -8,8 +8,6 @@ For license and copyright information please follow this link: #include "intro/intro_start.h" #include "lang/lang_keys.h" -#include "intro/intro_qr.h" -#include "intro/intro_phone.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" #include "main/main_account.h" @@ -17,6 +15,11 @@ For license and copyright information please follow this link: namespace Intro { namespace details { +namespace { + +using namespace Tdb; + +} // namespace StartWidget::StartWidget( QWidget *parent, @@ -32,13 +35,25 @@ StartWidget::StartWidget( void StartWidget::submit() { #if 0 // #TODO tdlib account().destroyStaleAuthorizationKeys(); -#endif goNext(); +#endif + + api().request( + TLgetAuthorizationState() + ).done([=](const TLauthorizationState &result) { + Step::handleAuthorizationState(result); + }).fail([=](const Error &error) { + }).send(); } rpl::producer StartWidget::nextButtonText() const { return tr::lng_start_msgs(); } +bool StartWidget::handleAuthorizationState( + const TLauthorizationState &state) { + return true; +} + } // namespace details } // namespace Intro diff --git a/Telegram/SourceFiles/intro/intro_start.h b/Telegram/SourceFiles/intro/intro_start.h index 4b3f072cd1137..4752d62d26c14 100644 --- a/Telegram/SourceFiles/intro/intro_start.h +++ b/Telegram/SourceFiles/intro/intro_start.h @@ -28,6 +28,10 @@ class StartWidget : public Step { void submit() override; rpl::producer nextButtonText() const override; +private: + bool handleAuthorizationState( + const Tdb::TLauthorizationState &state) override; + }; } // namespace details diff --git a/Telegram/SourceFiles/intro/intro_step.cpp b/Telegram/SourceFiles/intro/intro_step.cpp index c76fccae24084..7f948327b6b7e 100644 --- a/Telegram/SourceFiles/intro/intro_step.cpp +++ b/Telegram/SourceFiles/intro/intro_step.cpp @@ -36,13 +36,21 @@ For license and copyright information please follow this link: #include "data/data_session.h" #include "data/data_chat_filters.h" #include "window/window_controller.h" +#include "tdb/tdb_account.h" #include "styles/style_intro.h" #include "styles/style_window.h" +#include "intro/intro_qr.h" +#include "intro/intro_phone.h" +#include "intro/intro_code.h" +#include "intro/intro_password_check.h" + namespace Intro { namespace details { namespace { +using namespace Tdb; + void PrepareSupportMode(not_null session) { using ::Data::AutoDownload::Full; @@ -102,6 +110,11 @@ Step::Step( _description->entity()->setMarkedText(text); updateLabelsPosition(); }, lifetime()); + + account->tdb().updates( + ) | rpl::start_with_next([=](const TLupdate &update) { + handleUpdate(update); + }, lifetime()); } Step::~Step() = default; @@ -166,6 +179,7 @@ void Step::finish(const MTPauth_Authorization &auth, QImage &&photo) { } void Step::finish(const MTPUser &user, QImage &&photo) { +#if 0 // #TODO legacy if (user.type() != mtpc_user || !user.c_user().is_self() || !user.c_user().vid().v) { @@ -192,6 +206,42 @@ void Step::finish(const MTPUser &user, QImage &&photo) { } } + api().request(MTPmessages_GetDialogFilters( + )).done([=](const MTPVector &result) { + createSession(user, photo, result.v); + }).fail([=](const MTP::Error &error) { + createSession(user, photo, QVector()); + }).send(); +#endif +} + +void Step::finish(QImage &&photo) { + api().request(TLgetMe()).done([=](const TLuser &result) { + finish(result, photo); + }).fail([=] { + // #TODO tdlib errors + }).send(); +} + +void Step::finish(const TLuser &self, QImage photo) { + self.match([&](const TLDuser &data) { + // Check if such account is authorized already. + for (const auto &[_, existing] : Core::App().domain().accounts()) { + const auto raw = existing.get(); + if (const auto session = raw->maybeSession()) { + if (raw->mtp().environment() == _account->mtp().environment() + && UserId(data.vid()) == session->userId()) { + _account->logOut(); + crl::on_main(raw, [=] { + Core::App().domain().activate(raw); + }); + return; + } + } + } + }); + createSession(self, photo, {}); + #if 0 // #TODO tdlib api().request(MTPmessages_GetDialogFilters( )).done([=](const MTPVector &result) { @@ -202,6 +252,7 @@ void Step::finish(const MTPUser &user, QImage &&photo) { #endif } +#if 0 // #TODO legacy void Step::createSession( const MTPUser &user, QImage photo, @@ -243,6 +294,43 @@ void Step::createSession( } Local::sync(); } +#endif + +void Step::createSession( + const TLuser &self, + QImage photo, + const QVector &filters) { + // Save the default language if we've suggested some other and user ignored it. + const auto currentId = Lang::Id(); + const auto defaultId = Lang::DefaultLanguageId(); + const auto suggested = Lang::CurrentCloudManager().suggestedLanguage(); + if (currentId.isEmpty() && !suggested.isEmpty() && suggested != defaultId) { + Lang::GetInstance().switchToId(Lang::DefaultLanguage()); + Local::writeLangPack(); + } + + auto settings = std::make_unique(); + settings->setDialogsFiltersEnabled(!filters.isEmpty()); + + const auto account = _account; + account->createSession(self, std::move(settings)); + + // "this" is already deleted here by creating the main widget. + account->local().writeMtpData(); + auto &session = account->session(); + //session.data().chatsFilters().setPreloaded(filters); // #TODO tdlib + if (!filters.isEmpty()) { + session.saveSettingsDelayed(); + } + if (!photo.isNull()) { + session.api().peerPhoto().upload( + session.user(), + { std::move(photo) }); + } + if (session.supportMode()) { + PrepareSupportMode(&session); + } +} void Step::paintEvent(QPaintEvent *e) { auto p = QPainter(this); @@ -451,6 +539,41 @@ void Step::paintCover(QPainter &p, int top) { st::introCoverIcon.paint(p, planeLeft, planeTop, width()); } +void Step::handleUpdate(const TLupdate &update) { + update.match([&](const TLDupdateAuthorizationState &data) { + handleAuthorizationState(data.vauthorization_state()); + }, [](const auto &) { + }); +} + +bool Step::handleAuthorizationState(const TLauthorizationState &state) { + return state.match([&](const TLDauthorizationStateWaitPhoneNumber &data) { + goNext(); + return true; + }, [&](const TLDauthorizationStateWaitCode &data) { + goNext(); + return true; + }, [&](const TLDauthorizationStateWaitOtherDeviceConfirmation &data) { + goNext(); + return true; + }, [&](const TLDauthorizationStateWaitRegistration &data) { + goNext(); + return true; + }, [&](const TLDauthorizationStateWaitPassword &data) { + getData()->pwdState.hasRecovery = tl_is_true( + data.vhas_recovery_email_address()); + getData()->pwdState.hint = data.vpassword_hint().v; + //getData()->pwdState.notEmptyPassport = data.is_has_secure_values(); // #TODO tdlib + goNext(); + return true; + }, [&](const TLDauthorizationStateReady &data) { + finish(); + return true; + }, [&](const auto &) { + return false; + }); +} + int Step::contentLeft() const { return (width() - st::introNextButton.width) / 2; } diff --git a/Telegram/SourceFiles/intro/intro_step.h b/Telegram/SourceFiles/intro/intro_step.h index 4ccf54e784f38..8b28cc16895fa 100644 --- a/Telegram/SourceFiles/intro/intro_step.h +++ b/Telegram/SourceFiles/intro/intro_step.h @@ -148,6 +148,12 @@ class Step : public Ui::RpWidget { virtual int errorTop() const; + virtual void handleUpdate(const Tdb::TLupdate &update); + virtual bool handleAuthorizationState( + const Tdb::TLauthorizationState &state); + + void finish(QImage &&photo = QImage()); + private: struct CoverAnimation { CoverAnimation() = default; @@ -183,6 +189,12 @@ class Step : public Ui::RpWidget { void prepareCoverMask(); void paintCover(QPainter &p, int top); + void finish(const Tdb::TLuser &self, QImage photo); + void createSession( + const Tdb::TLuser &user, + QImage photo, + const QVector &filters); + const not_null _account; const not_null _data; mutable std::optional _api; diff --git a/Telegram/SourceFiles/main/main_account.cpp b/Telegram/SourceFiles/main/main_account.cpp index e67857e4408b7..ee76b3d91be78 100644 --- a/Telegram/SourceFiles/main/main_account.cpp +++ b/Telegram/SourceFiles/main/main_account.cpp @@ -47,20 +47,6 @@ constexpr auto kWideIdsTag = ~uint64(0); return result; } -[[nodiscard]] std::unique_ptr CreateTdbAccount(bool testMode) { - return std::make_unique(Tdb::AccountConfig{ - .apiId = ApiId, - .apiHash = ApiHash, - .systemLanguageCode = Lang::GetInstance().systemLangCode(), - .deviceModel = Platform::DeviceModelPretty(), - .systemVersion = Platform::SystemVersionPretty(), - .applicationVersion = QString::fromLatin1(AppVersionStr), - .databaseDirectory = "", - .filesDirectory = "", - .testDc = testMode, - }); -} - } // namespace Account::Account( @@ -97,7 +83,7 @@ std::unique_ptr Account::prepareToStart( } void Account::start(std::unique_ptr config) { - _tdb = CreateTdbAccount(config ? config->isTestMode() : false); + _tdb = createTdb(config ? config->isTestMode() : false); _appConfig = std::make_unique(this); startMtp(config ? std::move(config) @@ -108,6 +94,20 @@ void Account::start(std::unique_ptr config) { watchSessionChanges(); } +std::unique_ptr Account::createTdb(bool testMode) { + return std::make_unique(Tdb::AccountConfig{ + .apiId = ApiId, + .apiHash = ApiHash, + .systemLanguageCode = Lang::GetInstance().systemLangCode(), + .deviceModel = Platform::DeviceModelPretty(), + .systemVersion = Platform::SystemVersionPretty(), + .applicationVersion = QString::fromLatin1(AppVersionStr), + .databaseDirectory = _local->libDatabasePath(), + .filesDirectory = _local->libFilesPath(), + .testDc = testMode, + }); +} + void Account::prepareToStartAdded( std::shared_ptr localKey) { _local->startAdded(std::move(localKey)); @@ -153,6 +153,7 @@ uint64 Account::willHaveSessionUniqueId(MTP::Config *config) const { | (config && config->isTestMode() ? 0x0100'0000'0000'0000ULL : 0ULL); } +#if 0 // #TODO legacy void Account::createSession( const MTPUser &user, std::unique_ptr settings) { @@ -162,15 +163,19 @@ void Account::createSession( 0, settings ? std::move(settings) : std::make_unique()); } +#endif void Account::createSession( UserId id, QByteArray serialized, int streamVersion, std::unique_ptr settings) { + using namespace Tdb; DEBUG_LOG(("sessionUserSerialized.size: %1").arg(serialized.size())); QDataStream peekStream(serialized); const auto phone = Serialize::peekUserPhone(streamVersion, peekStream); + +#if 0 // #TODO legacy const auto flags = MTPDuser::Flag::f_self | (phone.isEmpty() ? MTPDuser::Flag() : MTPDuser::Flag::f_phone); @@ -198,8 +203,43 @@ void Account::createSession( serialized, streamVersion, std::move(settings)); +#endif + + createSession( + tl_user( + tl_int53(base::take(_sessionUserId).bare), + tl_string(), // first_name + tl_string(), // last_name + tl_string(), // username + tl_string(phone), + tl_userStatusEmpty(), + null, + tl_bool(true), // is_contact #TODO tdlib check + tl_bool(true), // is_mutual_contact #TODO tdlib check + tl_bool(false), // is_verified + tl_bool(false), // is_support + tl_string(), // restriction_reason + tl_bool(false), // is_scam + tl_bool(false), // is_fake, + tl_bool(true), // have_access + tl_userTypeRegular(), + tl_string()), // language_code + serialized, + streamVersion, + std::move(settings)); +} + +void Account::createSession( + const Tdb::TLuser &user, + std::unique_ptr settings) { + createSession( + user, + QByteArray(), + 0, + settings ? std::move(settings) : std::make_unique()); } +#if 0 // #TODO legacy void Account::createSession( const MTPUser &user, QByteArray serialized, @@ -217,6 +257,24 @@ void Account::createSession( Ensures(_session != nullptr); } +#endif + +void Account::createSession( + const Tdb::TLuser &user, + QByteArray serialized, + int streamVersion, + std::unique_ptr settings) { + Expects(_session == nullptr); + Expects(_sessionValue.current() == nullptr); + + _session = std::make_unique(this, user, std::move(settings)); + if (!serialized.isEmpty()) { + local().readSelf(_session.get(), serialized, streamVersion); + } + _sessionValue = _session.get(); + + Ensures(_session != nullptr); +} void Account::destroySession(DestroyReason reason) { _storedSessionSettings.reset(); @@ -545,12 +603,20 @@ void Account::logOut() { return; } _loggingOut = true; +#if 0 // #TODO legacy if (_mtp) { _mtp->logout([=] { loggedOut(); }); } else { // We log out because we've forgotten passcode. loggedOut(); } +#endif + _tdb->sender().request( + Tdb::TLlogOut() + ).fail([=](const Tdb::Error &error) { + LOG(("Tdb Error: logOut - ").arg(error.message)); + loggedOut(); + }).send(); } bool Account::loggingOut() const { diff --git a/Telegram/SourceFiles/main/main_account.h b/Telegram/SourceFiles/main/main_account.h index 560ef506597f9..5f4c961d31c85 100644 --- a/Telegram/SourceFiles/main/main_account.h +++ b/Telegram/SourceFiles/main/main_account.h @@ -11,6 +11,10 @@ For license and copyright information please follow this link: #include "mtproto/mtp_instance.h" #include "base/weak_ptr.h" +namespace Tdb { +class TLuser; +} // namespace Td + namespace Storage { class Account; class Domain; @@ -54,15 +58,21 @@ class Account final : public base::has_weak_ptr { void start(std::unique_ptr config); [[nodiscard]] uint64 willHaveSessionUniqueId(MTP::Config *config) const; +#if 0 // #TODO legacy void createSession( const MTPUser &user, std::unique_ptr settings = nullptr); +#endif void createSession( UserId id, QByteArray serialized, int streamVersion, std::unique_ptr settings); + void createSession( + const Tdb::TLuser &user, + std::unique_ptr settings = nullptr); + void logOut(); void forcedLogOut(); [[nodiscard]] bool loggingOut() const; @@ -141,11 +151,18 @@ class Account final : public base::has_weak_ptr { }; void startMtp(std::unique_ptr config); +#if 0 // #TODO legacy void createSession( const MTPUser &user, QByteArray serialized, int streamVersion, std::unique_ptr settings); +#endif + void createSession( + const Tdb::TLuser &user, + QByteArray serialized, + int streamVersion, + std::unique_ptr settings); void watchProxyChanges(); void watchSessionChanges(); bool checkForUpdates(const MTP::Response &message); @@ -157,6 +174,8 @@ class Account final : public base::has_weak_ptr { void loggedOut(); void destroySession(DestroyReason reason); + [[nodiscard]] std::unique_ptr createTdb(bool testMode); + const not_null _domain; const std::unique_ptr _local; std::unique_ptr _tdb; diff --git a/Telegram/SourceFiles/main/main_domain.cpp b/Telegram/SourceFiles/main/main_domain.cpp index 26e01229f611a..a7a5551c20702 100644 --- a/Telegram/SourceFiles/main/main_domain.cpp +++ b/Telegram/SourceFiles/main/main_domain.cpp @@ -26,6 +26,8 @@ For license and copyright information please follow this link: #include "window/window_controller.h" #include "data/data_peer_values.h" // Data::AmPremiumValue. +#include "tdb/tdb_account.h" + namespace Main { Domain::Domain(const QString &dataName) @@ -64,6 +66,8 @@ bool Domain::started() const { Storage::StartResult Domain::start(const QByteArray &passcode) { Expects(!started()); + configureTdbLogs(); + const auto result = _local->start(passcode); if (result == Storage::StartResult::Success) { activateAfterStarting(); @@ -74,6 +78,25 @@ Storage::StartResult Domain::start(const QByteArray &passcode) { return result; } +void Domain::configureTdbLogs() { + using namespace Tdb; + if (!Logs::DebugEnabled()) { + Execute(TLsetLogVerbosityLevel(tl_int32(0))); + Execute(TLsetLogStream(tl_logStreamEmpty())); + } else { + const auto logFolder = cWorkingDir() + qsl("DebugLogs"); + const auto logPath = logFolder + qsl("/last_tdlib_log.txt"); + QFile(logPath).remove(); + QDir().mkpath(logFolder); + + Execute(TLsetLogVerbosityLevel(tl_int32(4))); + Execute(TLsetLogStream(tl_logStreamFile( + tl_string(logPath), + tl_int53(200 * 1024 * 1024), + tl_bool(false)))); + } +} + void Domain::finish() { _accountToActivate = -1; _active.reset(nullptr); diff --git a/Telegram/SourceFiles/main/main_domain.h b/Telegram/SourceFiles/main/main_domain.h index 1a39e8e7fcbe2..0c9dd0814f783 100644 --- a/Telegram/SourceFiles/main/main_domain.h +++ b/Telegram/SourceFiles/main/main_domain.h @@ -79,6 +79,7 @@ class Domain final { [[nodiscard]] int activeForStorage() const; private: + void configureTdbLogs(); void activateAfterStarting(); void closeAccountWindows(not_null account); bool removePasscodeIfEmpty(); diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 84f48106a26cd..f3cd9027373d3 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -78,7 +78,7 @@ constexpr auto kTmpPasswordReserveTime = TimeId(10); Session::Session( not_null account, - const MTPUser &user, + const Tdb::TLuser &user, std::unique_ptr settings) : _account(account) , _settings(std::move(settings)) diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h index 342c7ced629dd..2e2c713607a29 100644 --- a/Telegram/SourceFiles/main/main_session.h +++ b/Telegram/SourceFiles/main/main_session.h @@ -14,6 +14,10 @@ For license and copyright information please follow this link: class ApiWrap; +namespace Tdb { +class TLuser; +} // namespace Td + namespace Api { class Updates; class SendProgressManager; @@ -70,10 +74,16 @@ class SendAsPeers; class Session final : public base::has_weak_ptr { public: +#if 0 // #TODO legacy Session( not_null account, const MTPUser &user, std::unique_ptr settings); +#endif + Session( + not_null account, + const Tdb::TLuser &user, + std::unique_ptr settings); ~Session(); Session(const Session &other) = delete; diff --git a/Telegram/SourceFiles/storage/storage_account.cpp b/Telegram/SourceFiles/storage/storage_account.cpp index fe8049ff6d73a..6065942030ed1 100644 --- a/Telegram/SourceFiles/storage/storage_account.cpp +++ b/Telegram/SourceFiles/storage/storage_account.cpp @@ -150,6 +150,18 @@ QString Account::tempDirectory() const { return _tempPath; } +QString Account::libDatabasePath() const { + Expects(!_databasePath.isEmpty()); + + return _databasePath + "td"; +} + +QString Account::libFilesPath() const { + Expects(!_databasePath.isEmpty()); + + return _databasePath + "files"; +} + StartResult Account::legacyStart(const QByteArray &passcode) { const auto result = readMapWith(MTP::AuthKeyPtr(), passcode); if (result == ReadMapResult::Failed) { diff --git a/Telegram/SourceFiles/storage/storage_account.h b/Telegram/SourceFiles/storage/storage_account.h index ade41f10c839d..2124db21a7f1d 100644 --- a/Telegram/SourceFiles/storage/storage_account.h +++ b/Telegram/SourceFiles/storage/storage_account.h @@ -75,6 +75,8 @@ class Account final { } [[nodiscard]] QString tempDirectory() const; + [[nodiscard]] QString libDatabasePath() const; + [[nodiscard]] QString libFilesPath() const; [[nodiscard]] MTP::AuthKeyPtr peekLegacyLocalKey() const { return _localKey; diff --git a/Telegram/SourceFiles/tdb/details/tdb_instance.cpp b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp index 34f19897391d4..d605ed1221e72 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_instance.cpp +++ b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp @@ -7,9 +7,12 @@ For license and copyright information please follow this link: */ #include "tdb/details/tdb_instance.h" +#include "base/debug_log.h" + #include +#include +#include #include -#include #include namespace Tdb::details { @@ -56,7 +59,6 @@ class Instance::Manager final void loop(); const not_null _manager; - std::jthread _thread; base::flat_map> _clients; QMutex _mutex; @@ -66,6 +68,8 @@ class Instance::Manager final std::atomic _closingId = 0; crl::semaphore _closing; + std::jthread _thread; + }; class Instance::Impl final { @@ -305,6 +309,11 @@ rpl::producer Instance::Impl::updates() const { } void Instance::Impl::sendTdlibParameters(InstanceConfig &&config) { + const auto fail = [=](Error error) { + LOG(("Critical Error: setTdlibParameters - %1").arg(error.message)); + }; + QDir().mkpath(config.databaseDirectory); + QDir().mkpath(config.filesDirectory); send( allocateRequestId(), TLsetTdlibParameters( @@ -325,7 +334,7 @@ void Instance::Impl::sendTdlibParameters(InstanceConfig &&config) { tl_bool(true), // enable_storage_optimizer tl_bool(false))), // ignore_file_names nullptr, - nullptr); + fail); } Instance::Instance(InstanceConfig &&config) @@ -356,4 +365,14 @@ rpl::producer Instance::updates() const { return _impl->updates(); } +void ExecuteExternal( + ExternalGenerator &&request, + ExternalCallback &&callback) { + const auto result = ClientManager::execute( + api::object_ptr(request())); + if (auto handler = callback ? callback(result.get()) : nullptr) { + handler(); + } +} + } // namespace Tdb::details diff --git a/Telegram/SourceFiles/tdb/details/tdb_instance.h b/Telegram/SourceFiles/tdb/details/tdb_instance.h index 65f8953471052..cac36b84d2797 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_instance.h +++ b/Telegram/SourceFiles/tdb/details/tdb_instance.h @@ -8,6 +8,7 @@ For license and copyright information please follow this link: #pragma once #include "tdb/tdb_tl_scheme.h" +#include "base/expected.h" namespace Tdb::details { @@ -73,7 +74,8 @@ class Instance final { [[nodiscard]] RequestId allocateRequestId() const; template < typename Request, - typename = std::enable_if_t>> + typename = std::enable_if_t>, + typename = typename Request::ResponseType> void send( RequestId requestId, Request &&request, @@ -106,4 +108,25 @@ class Instance final { }; +void ExecuteExternal( + ExternalGenerator &&request, + ExternalCallback &&callback); + +template < + typename Request, + typename = std::enable_if_t>, + typename = typename Request::ResponseType> +auto Execute(Request &&request) { + using Response = typename Request::ResponseType; + auto container = base::expected(); + ExecuteExternal( + tl_to_generator(std::move(request)), + PrepareCallback([&](const Response &result) { + container = result; + }, [&](const Error &error) { + container = base::make_unexpected(error); + })); + return container; +} + } // namespace Tdb::details diff --git a/Telegram/SourceFiles/tdb/tdb_account.h b/Telegram/SourceFiles/tdb/tdb_account.h index d803f431d231d..3e7e3a2cf27cd 100644 --- a/Telegram/SourceFiles/tdb/tdb_account.h +++ b/Telegram/SourceFiles/tdb/tdb_account.h @@ -39,4 +39,6 @@ class Account final { }; +using details::Execute; + } // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/tdb_sender.h b/Telegram/SourceFiles/tdb/tdb_sender.h index 41454c00e8875..31d0a5fa84bca 100644 --- a/Telegram/SourceFiles/tdb/tdb_sender.h +++ b/Telegram/SourceFiles/tdb/tdb_sender.h @@ -117,6 +117,11 @@ class Sender final { public: using Result = typename Request::ResponseType; + [[nodiscard]] SpecificRequestBuilder &done( + FnMut callback) { + _done = makeDoneHandler(std::move(callback)); + return *this; + } [[nodiscard]] SpecificRequestBuilder &done( FnMut(std::move(callback)); return *this; } - [[nodiscard]] SpecificRequestBuilder &done( - FnMut callback) { - _done = makeDoneHandler(std::move(callback)); + + [[nodiscard]] SpecificRequestBuilder &fail( + Fn callback) noexcept { + setFailHandler(std::move(callback)); return *this; } - [[nodiscard]] SpecificRequestBuilder &fail( Fn callback) noexcept { - setFailHandler(std::move(callback)); - return *this; - } RequestId send() noexcept { const auto id = requestId(); From f15f9f2d003baf87dfca5a9b18de4dbb90fc449e Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 21 Apr 2021 20:49:06 +0400 Subject: [PATCH 008/350] Implement registration / authorization. --- .../SourceFiles/api/api_text_entities.cpp | 65 ++++++++ Telegram/SourceFiles/api/api_text_entities.h | 5 + .../chat_helpers/message_field.cpp | 3 + Telegram/SourceFiles/core/application.cpp | 1 + Telegram/SourceFiles/intro/intro_code.cpp | 86 +++++++++-- Telegram/SourceFiles/intro/intro_code.h | 22 +++ .../intro/intro_password_check.cpp | 79 +++++++++- .../SourceFiles/intro/intro_password_check.h | 14 ++ Telegram/SourceFiles/intro/intro_phone.cpp | 34 ++++- Telegram/SourceFiles/intro/intro_phone.h | 5 +- Telegram/SourceFiles/intro/intro_qr.cpp | 40 ++--- Telegram/SourceFiles/intro/intro_qr.h | 7 +- Telegram/SourceFiles/intro/intro_signup.cpp | 58 ++++++- Telegram/SourceFiles/intro/intro_signup.h | 10 ++ Telegram/SourceFiles/intro/intro_start.cpp | 22 ++- Telegram/SourceFiles/intro/intro_start.h | 2 +- Telegram/SourceFiles/intro/intro_step.cpp | 67 +++++++-- Telegram/SourceFiles/intro/intro_step.h | 10 +- Telegram/SourceFiles/intro/intro_widget.cpp | 65 ++++++-- Telegram/SourceFiles/intro/intro_widget.h | 13 +- Telegram/SourceFiles/main/main_account.cpp | 57 ++++++- Telegram/SourceFiles/main/main_account.h | 13 +- Telegram/SourceFiles/main/main_session.h | 2 +- .../SourceFiles/tdb/details/tdb_instance.cpp | 141 +++++++++++------- .../SourceFiles/tdb/details/tdb_instance.h | 15 +- .../SourceFiles/tdb/details/tdb_tl_core.h | 2 +- Telegram/SourceFiles/tdb/tdb_account.h | 4 + .../window/window_lock_widgets.cpp | 18 +++ .../SourceFiles/window/window_lock_widgets.h | 7 + 29 files changed, 710 insertions(+), 157 deletions(-) diff --git a/Telegram/SourceFiles/api/api_text_entities.cpp b/Telegram/SourceFiles/api/api_text_entities.cpp index 6c434bc9bab33..8531f9eef7f03 100644 --- a/Telegram/SourceFiles/api/api_text_entities.cpp +++ b/Telegram/SourceFiles/api/api_text_entities.cpp @@ -18,6 +18,7 @@ namespace Api { namespace { using namespace TextUtilities; +using namespace Tdb; [[nodiscard]] QString CustomEmojiEntityData( const MTPDmessageEntityCustomEmoji &data) { @@ -184,4 +185,68 @@ MTPVector EntitiesToMTP( return MTP_vector(std::move(v)); } +EntitiesInText EntitiesFromTL( + Main::Session *session, + const QVector &entities) { + auto result = EntitiesInText(); + if (!entities.isEmpty()) { + result.reserve(entities.size()); + for (const auto &entity : entities) { + entity.match([&](const TLDtextEntity &data) { + const auto offset = data.voffset().v; + const auto length = data.vlength().v; + auto additional = QString(); + const auto type = data.vtype().match([&]( + const TLDtextEntityTypeMention &data) { + return EntityType::Mention; + }, [&](const TLDtextEntityTypeHashtag &data) { + return EntityType::Hashtag; + }, [&](const TLDtextEntityTypeCashtag &data) { + return EntityType::Cashtag; + }, [&](const TLDtextEntityTypeBotCommand &data) { + return EntityType::BotCommand; + }, [&](const TLDtextEntityTypeUrl &data) { + return EntityType::Url; + }, [&](const TLDtextEntityTypeEmailAddress &data) { + return EntityType::Email; + }, [&](const TLDtextEntityTypePhoneNumber &data) { + return EntityType::Invalid; + }, [&](const TLDtextEntityTypeBankCardNumber &data) { + return EntityType::Invalid; + }, [&](const TLDtextEntityTypeBold &data) { + return EntityType::Bold; + }, [&](const TLDtextEntityTypeItalic &data) { + return EntityType::Italic; + }, [&](const TLDtextEntityTypeUnderline &data) { + return EntityType::Underline; + }, [&](const TLDtextEntityTypeStrikethrough &data) { + return EntityType::StrikeOut; + }, [&](const TLDtextEntityTypeCode &data) { + return EntityType::Code; + }, [&](const TLDtextEntityTypePre &data) { + return EntityType::Pre; + }, [&](const TLDtextEntityTypePreCode &data) { + additional = data.vlanguage().v; + return EntityType::Pre; + }, [&](const TLDtextEntityTypeTextUrl &data) { + additional = data.vurl().v; + return EntityType::CustomUrl; + }, [&](const TLDtextEntityTypeMentionName &data) { + additional = MentionNameDataFromFields({ + .userId = uint64(data.vuser_id().v), + }); + return EntityType::MentionName; + }, [&](const TLDtextEntityTypeMediaTimestamp &data) { + // #TODO entities media timestamp links + return EntityType::Invalid; + }); + if (type != EntityType::Invalid) { + result.push_back({ type, offset, length, additional }); + } + }); + } + } + return result; +} + } // namespace Api diff --git a/Telegram/SourceFiles/api/api_text_entities.h b/Telegram/SourceFiles/api/api_text_entities.h index 95348d6164992..ca69a55a3ccd4 100644 --- a/Telegram/SourceFiles/api/api_text_entities.h +++ b/Telegram/SourceFiles/api/api_text_entities.h @@ -8,6 +8,7 @@ For license and copyright information please follow this link: #pragma once #include "ui/text/text_entity.h" +#include "tdb/tdb_tl_scheme.h" namespace Main { class Session; @@ -29,4 +30,8 @@ enum class ConvertOption { const EntitiesInText &entities, ConvertOption option = ConvertOption::WithLocal); +[[nodiscard]] EntitiesInText EntitiesFromTL( + Main::Session *session, + const QVector &entities); + } // namespace Api diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 475e87cb388ac..58fed46f9b626 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -87,7 +87,10 @@ QString FieldTagMimeProcessor::operator()(QStringView mimeTag) { const auto tag = *i; if (TextUtilities::IsMentionLink(tag) && TextUtilities::MentionNameDataToFields(tag).selfId != id) { +#if 0 // mtp i = all.erase(i); +#endif + ++i; continue; } else if (Ui::InputField::IsCustomEmojiLink(tag)) { const auto data = Ui::InputField::CustomEmojiEntityData(tag); diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index a25bf54c7a932..5b29eb72928da 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -876,6 +876,7 @@ void Application::logoutWithChecks(Main::Account *account) { void Application::forceLogOut( not_null account, const TextWithEntities &explanation) { + // #TODO secret allow cancel force logout const auto box = Ui::show(Ui::MakeConfirmBox({ .text = explanation, .confirmText = tr::lng_passcode_logout(tr::now), diff --git a/Telegram/SourceFiles/intro/intro_code.cpp b/Telegram/SourceFiles/intro/intro_code.cpp index ed1e55fd16752..a153cae71163d 100644 --- a/Telegram/SourceFiles/intro/intro_code.cpp +++ b/Telegram/SourceFiles/intro/intro_code.cpp @@ -25,6 +25,11 @@ For license and copyright information please follow this link: namespace Intro { namespace details { +namespace { + +using namespace Tdb; + +} // namespace CodeInput::CodeInput( QWidget *parent, @@ -90,8 +95,10 @@ CodeWidget::CodeWidget( , _callTimer([=] { sendCall(); }) , _callStatus(getData()->callStatus) , _callTimeout(getData()->callTimeout) -, _callLabel(this, st::introDescription) +, _callLabel(this, st::introDescription) { +#if 0 // #TODO legacy , _checkRequestTimer([=] { checkRequest(); }) { +#endif Lang::Updated( ) | rpl::start_with_next([=] { refreshLang(); @@ -227,7 +234,9 @@ void CodeWidget::activate() { void CodeWidget::finished() { Step::finished(); account().setHandleLoginCode(nullptr); +#if 0 // #TODO legacy _checkRequestTimer.cancel(); +#endif _callTimer.cancel(); apiClear(); @@ -237,9 +246,11 @@ void CodeWidget::finished() { } void CodeWidget::cancelled() { -#if 0 // #TODO tdlib +#if 0 // #TODO legacy api().request(base::take(_sentRequest)).cancel(); api().request(base::take(_callRequestId)).cancel(); +#endif +#if 0 // #TODO tdlib api().request(MTPauth_CancelCode( MTP_string(getData()->phone), MTP_bytes(getData()->phoneHash) @@ -247,12 +258,12 @@ void CodeWidget::cancelled() { #endif } +#if 0 // #TODO legacy void CodeWidget::stopCheck() { _checkRequestTimer.cancel(); } void CodeWidget::checkRequest() { -#if 0 // #TODO legacy auto status = api().instance().state(_sentRequest); if (status < 0) { auto leftms = -status; @@ -266,7 +277,6 @@ void CodeWidget::checkRequest() { if (!_sentRequest && status == MTP::RequestSent) { stopCheck(); } -#endif } void CodeWidget::codeSubmitDone(const MTPauth_Authorization &result) { @@ -293,7 +303,6 @@ void CodeWidget::codeSubmitFail(const MTP::Error &error) { } else if (err == u"PHONE_CODE_EMPTY"_q || err == u"PHONE_CODE_INVALID"_q) { showCodeError(tr::lng_bad_code()); } else if (err == u"SESSION_PASSWORD_NEEDED"_q) { -#if 0 // #TODO tdlib _checkRequestTimer.callEach(1000); _sentRequest = api().request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { @@ -301,13 +310,48 @@ void CodeWidget::codeSubmitFail(const MTP::Error &error) { }).fail([=](const MTP::Error &error) { codeSubmitFail(error); }).handleFloodErrors().send(); -#endif } else if (Logs::DebugEnabled()) { // internal server error showCodeError(rpl::single(err + ": " + error.description())); } else { showCodeError(rpl::single(Lang::Hard::ServerError())); } } +#endif + +void CodeWidget::handleAuthorizationState( + const TLauthorizationState &state) { + state.match([&](const TLDauthorizationStateWaitCode &data) { + fillCodeInfo(data.vcode_info()); + data.vcode_info().match([&](const TLDauthenticationCodeInfo &data) { + _code->setDigitsCountMax(getData()->codeLength); + if (_callStatus == CallStatus::Calling) { + _callStatus = CallStatus::Called; + getData()->callStatus = _callStatus; + getData()->callTimeout = _callTimeout; + updateCallText(); + } else { + updateDescText(); + } + }); + }, [&](const auto &) { + Step::handleAuthorizationState(state); + }); +} + +void CodeWidget::checkCodeFail(const Error &error) { + _sentRequest = false; + const auto &type = error.message; + if (type == u"PHONE_NUMBER_INVALID" + || type == u"PHONE_CODE_EXPIRED" + || type == u"PHONE_NUMBER_BANNED") { + goBack(); + } else if (type == u"PHONE_CODE_EMPTY" + || type == u"PHONE_CODE_INVALID") { + showCodeError(tr::lng_bad_code()); + } else { + showCodeError(rpl::single(type)); + } +} void CodeWidget::codeChanged() { hideError(); @@ -319,7 +363,11 @@ void CodeWidget::sendCall() { if (--_callTimeout <= 0) { _callStatus = CallStatus::Calling; _callTimer.cancel(); -#if 0 // #TODO tdlib + + api().request(TLresendAuthenticationCode( + )).send(); + +#if 0 // mtp _callRequestId = api().request(MTPauth_ResendCode( MTP_string(getData()->phone), MTP_bytes(getData()->phoneHash) @@ -335,6 +383,7 @@ void CodeWidget::sendCall() { } } +#if 0 // mtp void CodeWidget::callDone(const MTPauth_SentCode &result) { result.match([&](const MTPDauth_sentCode &data) { fillSentCodeData(data); @@ -375,6 +424,7 @@ void CodeWidget::gotPassword(const MTPaccount_Password &result) { } goReplace(Animate::Forward); } +#endif void CodeWidget::submit() { if (getData()->codeByFragmentUrl.isEmpty()) { @@ -399,11 +449,21 @@ void CodeWidget::submitCode() { hideError(); +#if 0 // #TODO legacy _checkRequestTimer.callEach(1000); +#endif _sentCode = text; + + _sentRequest = true; + api().request(TLcheckAuthenticationCode( + tl_string(_sentCode) + )).fail([=](const Error &error) { + checkCodeFail(error); + }).send(); + +#if 0 // #TODO legacy getData()->pwdState = Core::CloudPasswordState(); -#if 0 // #TODO tdlib _sentRequest = api().request(MTPauth_SignIn( MTP_flags(MTPauth_SignIn::Flag::f_phone_code), MTP_string(getData()->phone), @@ -435,10 +495,16 @@ rpl::producer CodeWidget::nextButtonStyle() const { } void CodeWidget::noTelegramCode() { + if (_noTelegramCodeSent) { + return; + } + _noTelegramCodeSent = true; + api().request(TLresendAuthenticationCode()).send(); + +#if 0 // #TODO legacy if (_noTelegramCodeRequestId) { return; } -#if 0 // #TODO tdlib _noTelegramCodeRequestId = api().request(MTPauth_ResendCode( MTP_string(getData()->phone), MTP_bytes(getData()->phoneHash) @@ -450,6 +516,7 @@ void CodeWidget::noTelegramCode() { #endif } +#if 0 // #TODO legacy void CodeWidget::noTelegramCodeDone(const MTPauth_SentCode &result) { _noTelegramCodeRequestId = 0; @@ -489,6 +556,7 @@ void CodeWidget::noTelegramCodeFail(const MTP::Error &error) { showCodeError(rpl::single(Lang::Hard::ServerError())); } } +#endif } // namespace details } // namespace Intro diff --git a/Telegram/SourceFiles/intro/intro_code.h b/Telegram/SourceFiles/intro/intro_code.h index 65f39117b241a..31a892dd0e176 100644 --- a/Telegram/SourceFiles/intro/intro_code.h +++ b/Telegram/SourceFiles/intro/intro_code.h @@ -67,7 +67,9 @@ class CodeWidget final : public Step { void noTelegramCode(); void codeChanged(); void sendCall(); +#if 0 // mtp void checkRequest(); +#endif int errorTop() const override; @@ -75,10 +77,13 @@ class CodeWidget final : public Step { void refreshLang(); void updateControlsGeometry(); +#if 0 // mtp void codeSubmitDone(const MTPauth_Authorization &result); void codeSubmitFail(const MTP::Error &error); +#endif void showCodeError(rpl::producer text); +#if 0 // mtp void callDone(const MTPauth_SentCode &result); void gotPassword(const MTPaccount_Password &result); @@ -88,23 +93,40 @@ class CodeWidget final : public Step { void submitCode(); void stopCheck(); +#endif + + void handleAuthorizationState( + const Tdb::TLauthorizationState &state) override; + + void checkCodeFail(const Tdb::Error &error); object_ptr _noTelegramCode; +#if 0 // #TODO legacy mtpRequestId _noTelegramCodeRequestId = 0; +#endif object_ptr _code; QString _sentCode; +#if 0 // #TODO legacy mtpRequestId _sentRequest = 0; +#endif rpl::variable _isFragment = false; base::Timer _callTimer; CallStatus _callStatus = CallStatus(); int _callTimeout; +#if 0 // #TODO legacy mtpRequestId _callRequestId = 0; +#endif object_ptr _callLabel; +#if 0 // #TODO legacy base::Timer _checkRequestTimer; +#endif + + bool _noTelegramCodeSent = false; + bool _sentRequest = false; }; diff --git a/Telegram/SourceFiles/intro/intro_password_check.cpp b/Telegram/SourceFiles/intro/intro_password_check.cpp index 090394188304e..16f0932e4d1a2 100644 --- a/Telegram/SourceFiles/intro/intro_password_check.cpp +++ b/Telegram/SourceFiles/intro/intro_password_check.cpp @@ -127,9 +127,12 @@ void PasswordCheckWidget::activate() { } void PasswordCheckWidget::cancelled() { +#if 0 // mtp api().request(base::take(_sentRequest)).cancel(); +#endif } +#if 0 // mtp void PasswordCheckWidget::pwdSubmitDone( bool recover, const MTPauth_Authorization &result) { @@ -192,7 +195,6 @@ void PasswordCheckWidget::checkPasswordHash() { void PasswordCheckWidget::requestPasswordData() { api().request(base::take(_sentRequest)).cancel(); -#if 0 // #TODO tdlib _sentRequest = api().request( MTPaccount_GetPassword() ).done([=](const MTPaccount_Password &result) { @@ -203,7 +205,6 @@ void PasswordCheckWidget::requestPasswordData() { passwordChecked(); }); }).send(); -#endif } void PasswordCheckWidget::passwordChecked() { @@ -214,7 +215,6 @@ void PasswordCheckWidget::passwordChecked() { return serverError(); } _passwordState.mtp.request.id = 0; -#if 0 // #TODO tdlib _sentRequest = api().request( MTPauth_CheckPassword(check.result) ).done([=](const MTPauth_Authorization &result) { @@ -222,7 +222,6 @@ void PasswordCheckWidget::passwordChecked() { }).fail([=](const MTP::Error &error) { pwdSubmitFail(error); }).handleFloodErrors().send(); -#endif } void PasswordCheckWidget::serverError() { @@ -298,11 +297,12 @@ void PasswordCheckWidget::recoverStartFail(const MTP::Error &error) { update(); hideError(); } +#endif void PasswordCheckWidget::toRecover() { if (_passwordState.hasRecovery) { if (_sentRequest) { - api().request(base::take(_sentRequest)).cancel(); + return; } hideError(); _toRecover->hide(); @@ -314,7 +314,18 @@ void PasswordCheckWidget::toRecover() { _codeField->setFocus(); updateDescriptionText(); if (_emailPattern.isEmpty()) { -#if 0 // #TODO tdlib + api().request( + TLrequestAuthenticationPasswordRecovery() + ).fail([=](const Error &error) { + _pwdField->show(); + _pwdHint->show(); + _codeField->hide(); + _pwdField->setFocus(); + updateDescriptionText(); + update(); + hideError(); + }).send(); +#if 0 // #TODO legacy api().request( MTPauth_RequestPasswordRecovery() ).done([=](const MTPauth_PasswordRecovery &result) { @@ -378,7 +389,16 @@ void PasswordCheckWidget::submit() { return; } const auto send = crl::guard(this, [=] { -#if 0 // #TODO tdlib + _sentRequest = true; + api().request(TLrecoverAuthenticationPassword( + tl_string(code), + tl_string(), // new_password + tl_string() // new_hint + )).fail([=](const Error &error) { + recoverFail(error); + }).send(); + +#if 0 // #TODO legacy _sentRequest = api().request(MTPauth_CheckRecoveryPassword( MTP_string(code) )).done([=](const MTPBool &result) { @@ -432,6 +452,51 @@ void PasswordCheckWidget::passwordSubmitFail(const Error &error) { } } +void PasswordCheckWidget::recoverFail(const Error &error) { + _sentRequest = false; + const auto &type = error.message; + if (type == u"PASSWORD_EMPTY" + || type == u"AUTH_KEY_UNREGISTERED") { + goBack(); + } else if (type == u"PASSWORD_RECOVERY_NA") { + _pwdField->show(); + _pwdHint->show(); + _codeField->hide(); + _pwdField->setFocus(); + updateDescriptionText(); + update(); + hideError(); + } else if (type == u"PASSWORD_RECOVERY_EXPIRED") { + _emailPattern = QString(); + toPassword(); + } else if (type == u"CODE_INVALID") { + showError(tr::lng_signin_wrong_code()); + _codeField->selectAll(); + _codeField->showError(); + } else { + showError(rpl::single(type)); + _codeField->setFocus(); + } +} + +void PasswordCheckWidget::handleAuthorizationState( + const TLauthorizationState &state) { + state.match([&](const TLDauthorizationStateWaitPassword &data) { + const auto has = tl_is_true(data.vhas_recovery_email_address()); + if (_passwordState.hasRecovery != has + || _passwordState.hint != data.vpassword_hint().v) { + getData()->pwdState.hasRecovery = has; + getData()->pwdState.hint = data.vpassword_hint().v; + goReplace(Animate::Forward); + } else { + _emailPattern = data.vrecovery_email_address_pattern().v; + updateDescriptionText(); + } + }, [&](const auto &) { + Step::handleAuthorizationState(state); + }); +} + rpl::producer PasswordCheckWidget::nextButtonText() const { return tr::lng_intro_submit(); } diff --git a/Telegram/SourceFiles/intro/intro_password_check.h b/Telegram/SourceFiles/intro/intro_password_check.h index 29d5f52cb7453..6520490e1c98f 100644 --- a/Telegram/SourceFiles/intro/intro_password_check.h +++ b/Telegram/SourceFiles/intro/intro_password_check.h @@ -48,6 +48,7 @@ class PasswordCheckWidget final : public Step { void refreshLang(); void updateControlsGeometry(); +#if 0 // #TODO legacy void pwdSubmitDone(bool recover, const MTPauth_Authorization &result); void pwdSubmitFail(const MTP::Error &error); void codeSubmitDone(const QString &code, const MTPBool &result); @@ -55,19 +56,28 @@ class PasswordCheckWidget final : public Step { void recoverStartFail(const MTP::Error &error); void recoverStarted(const MTPauth_PasswordRecovery &result); +#endif void updateDescriptionText(); +#if 0 // #TODO legacy void handleSrpIdInvalid(); void requestPasswordData(); void checkPasswordHash(); void passwordChecked(); void serverError(); +#endif + + void handleAuthorizationState( + const Tdb::TLauthorizationState &state) override; void passwordSubmitFail(const Tdb::Error &error); + void recoverFail(const Tdb::Error &error); Core::CloudPasswordState _passwordState; +#if 0 // #TODO legacy crl::time _lastSrpIdInvalidTime = 0; bytes::vector _passwordHash; +#endif QString _emailPattern; object_ptr _pwdField; @@ -75,7 +85,11 @@ class PasswordCheckWidget final : public Step { object_ptr _codeField; object_ptr _toRecover; object_ptr _toPassword; +#if 0 // #TODO legacy mtpRequestId _sentRequest = 0; +#endif + + bool _sentRequest = false; }; diff --git a/Telegram/SourceFiles/intro/intro_phone.cpp b/Telegram/SourceFiles/intro/intro_phone.cpp index 61bbe3b379a53..e5543bcbca1f9 100644 --- a/Telegram/SourceFiles/intro/intro_phone.cpp +++ b/Telegram/SourceFiles/intro/intro_phone.cpp @@ -56,8 +56,10 @@ PhoneWidget::PhoneWidget( , _phone( this, st::introPhone, - [](const QString &s) { return Countries::Groups(s); }) + [](const QString &s) { return Countries::Groups(s); }) { +#if 0 // #TODO legacy , _checkRequestTimer([=] { checkRequest(); }) { +#endif _phone->frontBackspaceEvent( ) | rpl::start_with_next([=](not_null e) { _code->startErasing(e); @@ -177,7 +179,7 @@ void PhoneWidget::submit() { for (const auto &[index, existing] : Core::App().domain().accounts()) { const auto raw = existing.get(); if (const auto session = raw->maybeSession()) { - if (raw->mtp().environment() == account().mtp().environment() + if (existing->testMode() == account().testMode() && digitsOnly(session->user()->phone()) == phoneDigits) { crl::on_main(raw, [=] { Core::App().domain().activate(raw); @@ -194,7 +196,7 @@ void PhoneWidget::submit() { #endif _sentPhone = phone; - + _sentRequest = true; api().request(TLsetAuthenticationPhoneNumber( tl_string(phone), tl_phoneNumberAuthenticationSettings( @@ -223,12 +225,12 @@ void PhoneWidget::submit() { #endif } +#if 0 // #TODO legacy void PhoneWidget::stopCheck() { _checkRequestTimer.cancel(); } void PhoneWidget::checkRequest() { -#if 0 // #TODO legacy auto status = api().instance().state(_sentRequest); if (status < 0) { auto leftms = -status; @@ -239,10 +241,8 @@ void PhoneWidget::checkRequest() { if (!_sentRequest && status == MTP::RequestSent) { stopCheck(); } -#endif } -#if 0 // #TODO legacy void PhoneWidget::phoneSubmitDone(const MTPauth_SentCode &result) { stopCheck(); _sentRequest = 0; @@ -290,12 +290,26 @@ void PhoneWidget::phoneSubmitFail(const MTP::Error &error) { } #endif -bool PhoneWidget::handleAuthorizationState( +void PhoneWidget::handleAuthorizationState( const TLauthorizationState &state) { - return Step::handleAuthorizationState(state); + state.match([&](const TLDauthorizationStateWaitPhoneNumber &data) { + }, [&](const TLDauthorizationStateWaitOtherDeviceConfirmation &data) { + }, [&](const auto &) { + Step::handleAuthorizationState(state); + }); } void PhoneWidget::phoneSetFail(const Error &error) { + const auto &type = error.message; + if (type == u"PHONE_NUMBER_FLOOD") { + Ui::show(Box(tr::lng_error_phone_flood(tr::now))); + } else if (type == u"PHONE_NUMBER_INVALID") { + showPhoneError(tr::lng_bad_phone()); + } else if (type == u"PHONE_NUMBER_BANNED") { + Ui::ShowPhoneBannedError(getData()->controller, _sentPhone); + } else { + showPhoneError(rpl::single(type)); + } } QString PhoneWidget::fullNumber() const { @@ -318,14 +332,18 @@ void PhoneWidget::activate() { void PhoneWidget::finished() { Step::finished(); +#if 0 // #TODO legacy _checkRequestTimer.cancel(); +#endif apiClear(); cancelled(); } void PhoneWidget::cancelled() { +#if 0 // #TODO legacy api().request(base::take(_sentRequest)).cancel(); +#endif } } // namespace details diff --git a/Telegram/SourceFiles/intro/intro_phone.h b/Telegram/SourceFiles/intro/intro_phone.h index 387cdbf8f7fcb..1b64969b5ba65 100644 --- a/Telegram/SourceFiles/intro/intro_phone.h +++ b/Telegram/SourceFiles/intro/intro_phone.h @@ -54,7 +54,7 @@ class PhoneWidget final : public Step { void phoneSubmitFail(const MTP::Error &error); #endif - bool handleAuthorizationState( + void handleAuthorizationState( const Tdb::TLauthorizationState &state) override; void phoneSetFail(const Tdb::Error &error); @@ -71,10 +71,13 @@ class PhoneWidget final : public Step { object_ptr _phone; QString _sentPhone; +#if 0 // #TODO legacy mtpRequestId _sentRequest = 0; base::Timer _checkRequestTimer; +#endif + bool _sentRequest = 0; }; } // namespace details diff --git a/Telegram/SourceFiles/intro/intro_qr.cpp b/Telegram/SourceFiles/intro/intro_qr.cpp index 1cc48cd4b6c4a..d1ce29da0e19f 100644 --- a/Telegram/SourceFiles/intro/intro_qr.cpp +++ b/Telegram/SourceFiles/intro/intro_qr.cpp @@ -186,9 +186,9 @@ QrWidget::QrWidget( setDescriptionText(rpl::single(QString())); setErrorCentered(true); -#if 0 // #TODO legacy cancelNearestDcRequest(); +#if 0 // #TODO legacy account->mtpUpdates( ) | rpl::start_with_next([=](const MTPUpdates &updates) { checkForTokenUpdate(updates); @@ -196,11 +196,15 @@ QrWidget::QrWidget( #endif setupControls(); +#if 0 // #TODO legacy account->mtp().mainDcIdValue( ) | rpl::start_with_next([=] { api().request(base::take(_requestId)).cancel(); refreshCode(); }, lifetime()); +#endif + + requestCode(); } int QrWidget::errorTop() const { @@ -234,16 +238,19 @@ void QrWidget::checkForTokenUpdate(const MTPUpdate &update) { } #endif -bool QrWidget::handleAuthorizationState(const TLauthorizationState &state) { - state.match([&]( - const TLDauthorizationStateWaitOtherDeviceConfirmation &data) { +void QrWidget::handleAuthorizationState(const TLauthorizationState &state) { + state.match([&](const TLDauthorizationStateWaitPhoneNumber &data) { + api().request(TLrequestQrCodeAuthentication( + tl_vector(0) + )).fail([=](const Error &error) { + showTokenError(error); + }).send(); + }, [&](const TLDauthorizationStateWaitOtherDeviceConfirmation &data) { + getData()->qrLink = data.vlink().v; _qrLinks.fire_copy(data.vlink().v); }, [&](const auto &) { - if (!Step::handleAuthorizationState(state)) { - goBack(); - } + Step::handleAuthorizationState(state); }); - return true; } void QrWidget::submit() { @@ -333,20 +340,15 @@ void QrWidget::setupControls() { skip->setClickedCallback([=] { submit(); }); } -void QrWidget::refreshCode() { +void QrWidget::requestCode() { + if (!getData()->qrLink.isEmpty()) { + _qrLinks.fire_copy(getData()->qrLink); + return; + } api().request( TLgetAuthorizationState() ).done([=](const TLauthorizationState &result) { - result.match( - [&](const TLDauthorizationStateWaitPhoneNumber &data) { - api().request(TLrequestQrCodeAuthentication( - tl_vector(0) - )).fail([=](const Error &error) { - showTokenError(error); - }).send(); - }, [&](const auto &) { - handleAuthorizationState(result); - }); + handleAuthorizationState(result); }).fail([=](const Error &error) { showTokenError(error); }).send(); diff --git a/Telegram/SourceFiles/intro/intro_qr.h b/Telegram/SourceFiles/intro/intro_qr.h index 28a08bab74208..f350f0331ea6e 100644 --- a/Telegram/SourceFiles/intro/intro_qr.h +++ b/Telegram/SourceFiles/intro/intro_qr.h @@ -36,8 +36,8 @@ class QrWidget final : public Step { void sendCheckPasswordRequest(); void setupControls(); - void refreshCode(); #if 0 // #TODO legacy + void refreshCode(); void checkForTokenUpdate(const MTPUpdates &updates); void checkForTokenUpdate(const MTPUpdate &update); void handleTokenResult(const MTPauth_LoginToken &result); @@ -47,10 +47,13 @@ class QrWidget final : public Step { void importTo(MTP::DcId dcId, const QByteArray &token); #endif void showToken(const QByteArray &token); +#if 0 // #TODO legacy void done(const MTPauth_Authorization &authorization); +#endif - bool handleAuthorizationState( + void handleAuthorizationState( const Tdb::TLauthorizationState &state) override; + void requestCode(); rpl::event_stream _qrLinks; #if 0 // #TODO legacy diff --git a/Telegram/SourceFiles/intro/intro_signup.cpp b/Telegram/SourceFiles/intro/intro_signup.cpp index 892da77b1a64d..b4bc937ebb11d 100644 --- a/Telegram/SourceFiles/intro/intro_signup.cpp +++ b/Telegram/SourceFiles/intro/intro_signup.cpp @@ -21,6 +21,11 @@ For license and copyright information please follow this link: namespace Intro { namespace details { +namespace { + +using namespace Tdb; + +} // namespace SignupWidget::SignupWidget( QWidget *parent, @@ -107,9 +112,12 @@ void SignupWidget::activate() { } void SignupWidget::cancelled() { +#if 0 api().request(base::take(_sentRequest)).cancel(); +#endif } +#if 0 // #TODO legacy void SignupWidget::nameSubmitDone(const MTPauth_Authorization &result) { finish(result); } @@ -154,6 +162,7 @@ void SignupWidget::nameSubmitFail(const MTP::Error &error) { } } } +#endif void SignupWidget::submit() { if (_sentRequest) { @@ -182,7 +191,16 @@ void SignupWidget::submit() { _firstName = _first->getLastText().trimmed(); _lastName = _last->getLastText().trimmed(); -#if 0 // #TODO tdlib + + _sentRequest = true; + api().request(TLregisterUser( + tl_string(_firstName), + tl_string(_lastName) + )).fail([=](const Error &error) { + registerUserFail(error); + }).send(); + +#if 0 // #TODO legacy _sentRequest = api().request(MTPauth_SignUp( MTP_string(getData()->phone), MTP_bytes(getData()->phoneHash), @@ -207,6 +225,44 @@ void SignupWidget::submit() { } } +void SignupWidget::handleAuthorizationState( + const TLauthorizationState &state) { + state.match([&](const TLDauthorizationStateWaitRegistration &data) { + fillTerms(data.vterms_of_service()); + }, [&](const auto &) { + Step::handleAuthorizationState(state); + }); +} + +void SignupWidget::registerUserFail(const Error &error) { + _sentRequest = false; + + const auto &type = error.message; + if (type == u"PHONE_NUMBER_FLOOD") { + Ui::show(Box(tr::lng_error_phone_flood(tr::now))); + } else if (type == u"PHONE_NUMBER_INVALID" + || type == u"PHONE_NUMBER_BANNED" + || type == u"PHONE_CODE_EXPIRED" + || type == u"PHONE_CODE_EMPTY" + || type == u"PHONE_CODE_INVALID" + || type == u"PHONE_NUMBER_OCCUPIED") { + goBack(); + } else if (type == u"FIRSTNAME_INVALID") { + showError(tr::lng_bad_name()); + _first->setFocus(); + } else if (type == u"LASTNAME_INVALID") { + showError(tr::lng_bad_name()); + _last->setFocus(); + } else { + showError(rpl::single(type)); + if (_invertOrder) { + _last->setFocus(); + } else { + _first->setFocus(); + } + } +} + rpl::producer SignupWidget::nextButtonText() const { return tr::lng_intro_finish(); } diff --git a/Telegram/SourceFiles/intro/intro_signup.h b/Telegram/SourceFiles/intro/intro_signup.h index f6c5fbe8ea129..7266ab721e6a7 100644 --- a/Telegram/SourceFiles/intro/intro_signup.h +++ b/Telegram/SourceFiles/intro/intro_signup.h @@ -39,18 +39,28 @@ class SignupWidget final : public Step { void refreshLang(); void updateControlsGeometry(); +#if 0 // #TODO legacy void nameSubmitDone(const MTPauth_Authorization &result); void nameSubmitFail(const MTP::Error &error); +#endif + + void handleAuthorizationState( + const Tdb::TLauthorizationState &state) override; + + void registerUserFail(const Tdb::Error &error); object_ptr _photo; object_ptr _first; object_ptr _last; QString _firstName, _lastName; +#if 0 // #TODO legacy mtpRequestId _sentRequest = 0; +#endif bool _invertOrder = false; bool _termsAccepted = false; + bool _sentRequest = false; }; diff --git a/Telegram/SourceFiles/intro/intro_start.cpp b/Telegram/SourceFiles/intro/intro_start.cpp index 3d6062306c4f8..08ac6ddcf81dc 100644 --- a/Telegram/SourceFiles/intro/intro_start.cpp +++ b/Telegram/SourceFiles/intro/intro_start.cpp @@ -30,10 +30,16 @@ StartWidget::StartWidget( setTitleText(rpl::single(u"Telegram Desktop"_q)); setDescriptionText(tr::lng_intro_about()); show(); + + api().request( + TLgetAuthorizationState() + ).done([=](const TLauthorizationState &result) { + handleAuthorizationState(result); + }).send(); } void StartWidget::submit() { -#if 0 // #TODO tdlib +#if 0 // #TODO legacy account().destroyStaleAuthorizationKeys(); goNext(); #endif @@ -42,7 +48,6 @@ void StartWidget::submit() { TLgetAuthorizationState() ).done([=](const TLauthorizationState &result) { Step::handleAuthorizationState(result); - }).fail([=](const Error &error) { }).send(); } @@ -50,9 +55,18 @@ rpl::producer StartWidget::nextButtonText() const { return tr::lng_start_msgs(); } -bool StartWidget::handleAuthorizationState( +void StartWidget::handleAuthorizationState( const TLauthorizationState &state) { - return true; + return state.match([&](const auto &data) { + using Data = decltype(data); + if constexpr (TLDauthorizationStateReady::Is() + || TLDauthorizationStateWaitCode::Is() + || TLDauthorizationStateWaitOtherDeviceConfirmation::Is() + || TLDauthorizationStateWaitRegistration::Is() + || TLDauthorizationStateWaitPassword::Is()) { + Step::handleAuthorizationState(state); + } + }); } } // namespace details diff --git a/Telegram/SourceFiles/intro/intro_start.h b/Telegram/SourceFiles/intro/intro_start.h index 4752d62d26c14..46d4d38ce3ea8 100644 --- a/Telegram/SourceFiles/intro/intro_start.h +++ b/Telegram/SourceFiles/intro/intro_start.h @@ -29,7 +29,7 @@ class StartWidget : public Step { rpl::producer nextButtonText() const override; private: - bool handleAuthorizationState( + void handleAuthorizationState( const Tdb::TLauthorizationState &state) override; }; diff --git a/Telegram/SourceFiles/intro/intro_step.cpp b/Telegram/SourceFiles/intro/intro_step.cpp index 7f948327b6b7e..4b194c480df68 100644 --- a/Telegram/SourceFiles/intro/intro_step.cpp +++ b/Telegram/SourceFiles/intro/intro_step.cpp @@ -44,6 +44,7 @@ For license and copyright information please follow this link: #include "intro/intro_phone.h" #include "intro/intro_code.h" #include "intro/intro_password_check.h" +#include "intro/intro_start.h" namespace Intro { namespace details { @@ -127,7 +128,7 @@ Tdb::Sender &Step::api() const { } void Step::apiClear() { - _api.reset(); + _api.emplace(_account->sender()); } rpl::producer Step::nextButtonText() const { @@ -156,6 +157,7 @@ void Step::goReplace(Step *step, Animate animate) { } } +#if 0 // mtp void Step::finish(const MTPauth_Authorization &auth, QImage &&photo) { auth.match([&](const MTPDauth_authorization &data) { if (data.vuser().type() != mtpc_user @@ -179,7 +181,6 @@ void Step::finish(const MTPauth_Authorization &auth, QImage &&photo) { } void Step::finish(const MTPUser &user, QImage &&photo) { -#if 0 // #TODO legacy if (user.type() != mtpc_user || !user.c_user().is_self() || !user.c_user().vid().v) { @@ -212,14 +213,14 @@ void Step::finish(const MTPUser &user, QImage &&photo) { }).fail([=](const MTP::Error &error) { createSession(user, photo, QVector()); }).send(); -#endif } +#endif void Step::finish(QImage &&photo) { api().request(TLgetMe()).done([=](const TLuser &result) { finish(result, photo); - }).fail([=] { - // #TODO tdlib errors + }).fail([=](const Error &error) { + const auto &type = error.message; }).send(); } @@ -229,7 +230,7 @@ void Step::finish(const TLuser &self, QImage photo) { for (const auto &[_, existing] : Core::App().domain().accounts()) { const auto raw = existing.get(); if (const auto session = raw->maybeSession()) { - if (raw->mtp().environment() == _account->mtp().environment() + if (existing->testMode() == _account->testMode() && UserId(data.vid()) == session->userId()) { _account->logOut(); crl::on_main(raw, [=] { @@ -434,6 +435,7 @@ bool Step::paintAnimated(QPainter &p, QRect clip) { return true; } +#if 0 // #TODO legacy void Step::fillSentCodeData(const MTPDauth_sentCode &data) { const auto bad = [](const char *type) { LOG(("API Error: Should not be '%1'.").arg(type)); @@ -462,6 +464,43 @@ void Step::fillSentCodeData(const MTPDauth_sentCode &data) { bad("SetUpEmailRequired"); }); } +#endif + +void Step::fillCodeInfo(const TLauthenticationCodeInfo &info) { + info.match([&](const TLDauthenticationCodeInfo &data) { + getData()->phone = data.vphone_number().v; + const auto currentType = data.vtype().type(); + getData()->codeByTelegram + = (currentType == id_authenticationCodeTypeTelegramMessage); + getData()->codeLength = data.vtype().match([]( + const TLDauthenticationCodeTypeFlashCall &) { + LOG(("Tdb Error: authenticationCodeTypeFlashCall.")); + return 0; + }, [&](const auto &data) { + return data.vlength().v; + }); + if (const auto next = data.vnext_type()) { + const auto type = next->type(); + getData()->callStatus + = (type == id_authenticationCodeTypeCall + ? CallStatus::Waiting + : CallStatus::Disabled); + getData()->callTimeout + = (type == id_authenticationCodeTypeCall + ? data.vtimeout().v + : 0); + } else { + getData()->callStatus = CallStatus::Disabled; + getData()->callTimeout = 0; + } + }); +} + +void Step::fillTerms(const TLtermsOfService &terms) { + getData()->termsLock = terms.match([&](const TLDtermsOfService &data) { + return Window::TermsLock::FromTL(nullptr, data); + }); +} void Step::showDescription() { _description->show(anim::type::normal); @@ -546,31 +585,29 @@ void Step::handleUpdate(const TLupdate &update) { }); } -bool Step::handleAuthorizationState(const TLauthorizationState &state) { - return state.match([&](const TLDauthorizationStateWaitPhoneNumber &data) { +void Step::handleAuthorizationState(const TLauthorizationState &state) { + return state.match([&]( + const TLDauthorizationStateWaitPhoneNumber &data) { goNext(); - return true; }, [&](const TLDauthorizationStateWaitCode &data) { + fillCodeInfo(data.vcode_info()); goNext(); - return true; }, [&](const TLDauthorizationStateWaitOtherDeviceConfirmation &data) { + getData()->qrLink = data.vlink().v; goNext(); - return true; }, [&](const TLDauthorizationStateWaitRegistration &data) { + fillTerms(data.vterms_of_service()); goNext(); - return true; }, [&](const TLDauthorizationStateWaitPassword &data) { getData()->pwdState.hasRecovery = tl_is_true( data.vhas_recovery_email_address()); getData()->pwdState.hint = data.vpassword_hint().v; //getData()->pwdState.notEmptyPassport = data.is_has_secure_values(); // #TODO tdlib goNext(); - return true; }, [&](const TLDauthorizationStateReady &data) { finish(); - return true; }, [&](const auto &) { - return false; + goNext(); }); } diff --git a/Telegram/SourceFiles/intro/intro_step.h b/Telegram/SourceFiles/intro/intro_step.h index 8b28cc16895fa..cf8224b50b080 100644 --- a/Telegram/SourceFiles/intro/intro_step.h +++ b/Telegram/SourceFiles/intro/intro_step.h @@ -104,7 +104,12 @@ class Step : public Ui::RpWidget { rpl::producer richDescriptionText); bool paintAnimated(QPainter &p, QRect clip); +#if 0 // mtp void fillSentCodeData(const MTPDauth_sentCode &type); +#endif + + void fillCodeInfo(const Tdb::TLauthenticationCodeInfo &info); + void fillTerms(const Tdb::TLtermsOfService &terms); void showDescription(); void hideDescription(); @@ -112,12 +117,15 @@ class Step : public Ui::RpWidget { [[nodiscard]] not_null getData() const { return _data; } + +#if 0 // mtp void finish(const MTPauth_Authorization &auth, QImage &&photo = {}); void finish(const MTPUser &user, QImage &&photo = {}); void createSession( const MTPUser &user, QImage photo, const QVector &filters); +#endif void goBack(); @@ -149,7 +157,7 @@ class Step : public Ui::RpWidget { virtual int errorTop() const; virtual void handleUpdate(const Tdb::TLupdate &update); - virtual bool handleAuthorizationState( + virtual void handleAuthorizationState( const Tdb::TLauthorizationState &state); void finish(QImage &&photo = QImage()); diff --git a/Telegram/SourceFiles/intro/intro_widget.cpp b/Telegram/SourceFiles/intro/intro_widget.cpp index 362664eb9cab7..53f30d6ed1e0d 100644 --- a/Telegram/SourceFiles/intro/intro_widget.cpp +++ b/Telegram/SourceFiles/intro/intro_widget.cpp @@ -46,6 +46,8 @@ For license and copyright information please follow this link: #include "styles/style_intro.h" #include "base/qt/qt_common_adapters.h" +#include "tdb/tdb_account.h" + namespace Intro { namespace { @@ -104,9 +106,7 @@ Widget::Widget( #endif switch (point) { case EnterPoint::Start: -#if 0 // #TODO legacy getNearestDC(); -#endif appendStep(new StartWidget(this, _account, getData())); break; case EnterPoint::Phone: @@ -125,10 +125,17 @@ Widget::Widget( createLanguageLink(); }, lifetime()); +#if 0 // #TODO legacy _account->mtpUpdates( ) | rpl::start_with_next([=](const MTPUpdates &updates) { handleUpdates(updates); }, lifetime()); +#endif + + _account->tdb().updates( + ) | rpl::start_with_next([=](const TLupdate &update) { + handleUpdate(update); + }, lifetime()); _back->entity()->setClickedCallback([=] { backRequested(); }); _back->hide(anim::type::instant); @@ -221,6 +228,7 @@ void Widget::refreshLang() { InvokeQueued(this, [this] { updateControlsGeometry(); }); } +#if 0 // #TODO legacy void Widget::handleUpdates(const MTPUpdates &updates) { updates.match([&](const MTPDupdateShort &data) { handleUpdate(data.vupdate()); @@ -248,6 +256,29 @@ void Widget::handleUpdate(const MTPUpdate &update) { Ui::show(Ui::MakeInformBox(text)); }, [](const auto &) {}); } +#endif + +void Widget::handleUpdate(const TLupdate &update) { + update.match([&](const TLDupdateServiceNotification &data) { + const auto text = data.vcontent().match([&]( + const TLDmessageText &data) { + return data.vtext().match([&](const TLDformattedText &data) { + return TextWithEntities{ + data.vtext().v, + Api::EntitiesFromTL(nullptr, data.ventities().v), + }; + }); + }, [](const auto &) { + return TextWithEntities(); + }); + if (data.vtype().v.startsWith("AUTH_KEY_DROP_")) { + Core::App().forceLogOut(_account, text); + } else { + Ui::show(Box(text)); + } + }, [](const auto &) { + }); +} void Widget::createLanguageLink() { if (_changeLanguage @@ -451,13 +482,9 @@ void Widget::appendStep(Step *step) { step->setShowTermsCallback([=] { showTerms(); }); -#if 0 // #TODO legacy step->setCancelNearestDcCallback([=] { - if (_api) { - _api->request(base::take(_nearestDcRequestId)).cancel(); - } + _api.request(base::take(_nearestDcRequestId)).cancel(); }); -#endif step->setAcceptTermsCallback([=](Fn callback) { acceptTerms(callback); }); @@ -538,10 +565,10 @@ void Widget::resetAccount() { }).fail([=](const Error &error) { _resetRequest = 0; - const auto &message = error.message; - if (message.startsWith(qstr("2FA_CONFIRM_WAIT_"))) { // #TODO tdlib errors + const auto &type = error.message; + if (type.startsWith(u"2FA_CONFIRM_WAIT_"_q)) { const auto seconds = base::StringViewMid( - message, + type, qstr("2FA_CONFIRM_WAIT_").size()).toInt(); const auto days = (seconds + 59) / 86400; const auto hours = ((seconds + 59) % 86400) / 3600; @@ -582,7 +609,7 @@ void Widget::resetAccount() { Ui::FormatPhone(getData()->phone), lt_when, when))); - } else if (type == u"2FA_RECENT_CONFIRM"_q) { // #TODO tdlib errors + } else if (type == u"2FA_RECENT_CONFIRM"_q) { Ui::show(Ui::MakeInformBox( tr::lng_signin_reset_cancelled())); } else { @@ -600,8 +627,20 @@ void Widget::resetAccount() { })); } -#if 0 // #TODO legacy void Widget::getNearestDC() { + _nearestDcRequestId = _api.request(TLgetCountryCode( + )).done([=](const TLtext &result) { + _nearestDcRequestId = 0; + result.match([&](const TLDtext &data) { + const auto nearestCountry = data.vtext().v; + if (getData()->country != nearestCountry) { + getData()->country = nearestCountry; + getData()->updated.fire({}); + } + }); + }).send(); + +#if 0 // #TODO legacy if (!_api) { return; } @@ -620,8 +659,8 @@ void Widget::getNearestDC() { getData()->updated.fire({}); } }).send(); -} #endif +} void Widget::showTerms(Fn callback) { if (getData()->termsLock.text.text.isEmpty()) { diff --git a/Telegram/SourceFiles/intro/intro_widget.h b/Telegram/SourceFiles/intro/intro_widget.h index 964e0a0254610..3b9834784f9d4 100644 --- a/Telegram/SourceFiles/intro/intro_widget.h +++ b/Telegram/SourceFiles/intro/intro_widget.h @@ -50,7 +50,9 @@ struct Data { QString country; QString phone; +#if 0 // #TODO legacy QByteArray phoneHash; +#endif CallStatus callStatus = CallStatus::Disabled; int callTimeout = 0; @@ -65,6 +67,7 @@ struct Data { rpl::event_stream<> updated; + QString qrLink; }; enum class StackAction { @@ -117,8 +120,10 @@ class Widget void createLanguageLink(); void checkUpdateStatus(); void setupNextButton(); +#if 0 // #TODO legacy void handleUpdates(const MTPUpdates &updates); void handleUpdate(const MTPUpdate &update); +#endif void backRequested(); void updateControlsGeometry(); @@ -150,11 +155,11 @@ class Widget details::Animate animate); void appendStep(details::Step *step); -#if 0 // #TODO legacy void getNearestDC(); -#endif void showTerms(Fn callback); + void handleUpdate(const Tdb::TLupdate &update); + // FloatDelegate [[nodiscard]] auto floatPlayerDelegate() -> not_null; @@ -177,9 +182,7 @@ class Widget const not_null _account; Tdb::Sender _api; -#if 0 // #TODO legacy - mtpRequestId _nearestDcRequestId = 0; -#endif + Tdb::RequestId _nearestDcRequestId = 0; std::unique_ptr _showAnimation; diff --git a/Telegram/SourceFiles/main/main_account.cpp b/Telegram/SourceFiles/main/main_account.cpp index ee76b3d91be78..3ec4eb387a1a4 100644 --- a/Telegram/SourceFiles/main/main_account.cpp +++ b/Telegram/SourceFiles/main/main_account.cpp @@ -64,6 +64,7 @@ Account::~Account() { session->saveSettingsNowIfNeeded(); } destroySession(DestroyReason::Quitting); + _tdb = nullptr; } Storage::Domain &Account::domainLocal() const { @@ -83,7 +84,8 @@ std::unique_ptr Account::prepareToStart( } void Account::start(std::unique_ptr config) { - _tdb = createTdb(config ? config->isTestMode() : false); + _testMode = config ? config->isTestMode() : false; + _tdb = createTdb(); _appConfig = std::make_unique(this); startMtp(config ? std::move(config) @@ -94,8 +96,8 @@ void Account::start(std::unique_ptr config) { watchSessionChanges(); } -std::unique_ptr Account::createTdb(bool testMode) { - return std::make_unique(Tdb::AccountConfig{ +std::unique_ptr Account::createTdb() { + auto result = std::make_unique(Tdb::AccountConfig{ .apiId = ApiId, .apiHash = ApiHash, .systemLanguageCode = Lang::GetInstance().systemLangCode(), @@ -104,8 +106,13 @@ std::unique_ptr Account::createTdb(bool testMode) { .applicationVersion = QString::fromLatin1(AppVersionStr), .databaseDirectory = _local->libDatabasePath(), .filesDirectory = _local->libFilesPath(), - .testDc = testMode, + .testDc = _testMode, }); + result->updates( + ) | rpl::filter(Tdb::IsRecreatedUpdate) | rpl::start_with_next([=] { + loggedOut(); + }, _lifetime); + return result; } void Account::prepareToStartAdded( @@ -214,8 +221,8 @@ void Account::createSession( tl_string(phone), tl_userStatusEmpty(), null, - tl_bool(true), // is_contact #TODO tdlib check - tl_bool(true), // is_mutual_contact #TODO tdlib check + tl_bool(true), // is_contact + tl_bool(true), // is_mutual_contact tl_bool(false), // is_verified tl_bool(false), // is_support tl_string(), // restriction_reason @@ -320,6 +327,12 @@ Tdb::Sender &Account::sender() const { return _tdb->sender(); } +bool Account::testMode() const { + Expects(_tdb != nullptr); + + return _testMode; +} + rpl::producer> Account::mtpValue() const { return _mtpValue.value() | rpl::map([](MTP::Instance *instance) { return not_null{ instance }; @@ -354,6 +367,7 @@ void Account::setLegacyMtpKey(std::shared_ptr key) { } QByteArray Account::serializeMtpAuthorization() const { +#if 0 // #TODO legacy const auto serialize = [&]( MTP::DcId mainDcId, const MTP::AuthKeysList &keys, @@ -408,6 +422,32 @@ QByteArray Account::serializeMtpAuthorization() const { const auto &keys = _mtpFields.keys; const auto &keysToDestroy = _mtpKeysToDestroy; return serialize(_mtpFields.mainDcId, keys, keysToDestroy); +#endif + const auto serialize = [&] { + auto result = QByteArray(); + // wide tag + userId + legacyMainDcId + 2 * legacyKeysCount + auto size = 2 * sizeof(quint64) + sizeof(qint32) * 3; + result.reserve(size); + { + QDataStream stream(&result, QIODevice::WriteOnly); + stream.setVersion(QDataStream::Qt_5_1); + + const auto currentUserId = sessionExists() + ? session().userId() + : UserId(); + stream + << quint64(kWideIdsTag) + << quint64(currentUserId.bare) + << qint32(0) // legacyMainDcId + << qint32(0) // legacyKeysCount + << qint32(0); // legacyKeysToDestroyCount + + DEBUG_LOG(("Auth Info: Written, userId: %1" + ).arg(currentUserId.bare)); + } + return result; + }; + return serialize(); } void Account::setSessionUserId(UserId userId) { @@ -466,6 +506,7 @@ void Account::setMtpAuthorization(const QByteArray &serialized) { } setSessionUserId(userId); +#if 0 // #TODO legacy _mtpFields.mainDcId = mainDcId; const auto readKeys = [&](auto &keys) { @@ -493,6 +534,7 @@ void Account::setMtpAuthorization(const QByteArray &serialized) { "read keys, current: %1, to destroy: %2" ).arg(_mtpFields.keys.size() ).arg(_mtpKeysToDestroy.size())); +#endif } void Account::startMtp(std::unique_ptr config) { @@ -611,10 +653,9 @@ void Account::logOut() { loggedOut(); } #endif - _tdb->sender().request( + sender().request( Tdb::TLlogOut() ).fail([=](const Tdb::Error &error) { - LOG(("Tdb Error: logOut - ").arg(error.message)); loggedOut(); }).send(); } diff --git a/Telegram/SourceFiles/main/main_account.h b/Telegram/SourceFiles/main/main_account.h index 5f4c961d31c85..fdde60a6c2f32 100644 --- a/Telegram/SourceFiles/main/main_account.h +++ b/Telegram/SourceFiles/main/main_account.h @@ -13,7 +13,9 @@ For license and copyright information please follow this link: namespace Tdb { class TLuser; -} // namespace Td +class Account; +class Sender; +} // namespace Tdb namespace Storage { class Account; @@ -26,11 +28,6 @@ class AuthKey; class Config; } // namespace MTP -namespace Tdb { -class Account; -class Sender; -} // namespace Tdb - namespace Main { class Domain; @@ -99,6 +96,7 @@ class Account final : public base::has_weak_ptr { return *_tdb; } [[nodiscard]] Tdb::Sender &sender() const; + [[nodiscard]] bool testMode() const; [[nodiscard]] MTP::Instance &mtp() const { return *_mtp; @@ -174,7 +172,7 @@ class Account final : public base::has_weak_ptr { void loggedOut(); void destroySession(DestroyReason reason); - [[nodiscard]] std::unique_ptr createTdb(bool testMode); + [[nodiscard]] std::unique_ptr createTdb(); const not_null _domain; const std::unique_ptr _local; @@ -200,6 +198,7 @@ class Account final : public base::has_weak_ptr { MTP::Instance::Fields _mtpFields; MTP::AuthKeysList _mtpKeysToDestroy; bool _loggingOut = false; + bool _testMode = false; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h index 2e2c713607a29..a4f0f8346721b 100644 --- a/Telegram/SourceFiles/main/main_session.h +++ b/Telegram/SourceFiles/main/main_session.h @@ -16,7 +16,7 @@ class ApiWrap; namespace Tdb { class TLuser; -} // namespace Td +} // namespace Tdb namespace Api { class Updates; diff --git a/Telegram/SourceFiles/tdb/details/tdb_instance.cpp b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp index d605ed1221e72..f1c6506fb2efd 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_instance.cpp +++ b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp @@ -24,13 +24,6 @@ namespace api = td_api; } // namespace -std::optional ParseError(ExternalResponse response) { - if (response->get_id() != api::error::ID) { - return std::nullopt; - } - return Error(tl_from(response)); -} - class Instance::Manager final : public std::enable_shared_from_this { struct PrivateTag { @@ -58,6 +51,12 @@ class Instance::Manager final RequestId requestId = 0); void loop(); + void handleUpdateOnMain(ClientId clientId, TLupdate &&update); + void handleResponseOnMain( + ClientId clientId, + RequestId requestId, + FnMut &&handler); + const not_null _manager; base::flat_map> _clients; @@ -93,10 +92,12 @@ class Instance::Impl final { Request &&request, FnMut &&done, FnMut &&fail) { + const auto type = request.type(); return sendPrepared( requestId, tl_to_generator(std::move(request)), PrepareCallback( + type, std::move(done), std::move(fail))); } @@ -105,10 +106,11 @@ class Instance::Impl final { [[nodiscard]] rpl::producer updates() const; private: - void sendTdlibParameters(InstanceConfig &&config); + void sendTdlibParameters(); const std::shared_ptr _manager; - ClientManager::ClientId _client; + std::atomic _client; + InstanceConfig _config; QMutex _activeRequestsMutex; base::flat_set _activeRequests; rpl::event_stream _updates; @@ -117,6 +119,30 @@ class Instance::Impl final { std::weak_ptr Instance::ManagerInstance; +std::optional ParseError(ExternalResponse response) { + if (response->get_id() != api::error::ID) { + return std::nullopt; + } + return Error(tl_from(response)); +} + +bool ClientClosedUpdate(const TLupdate &update) { + if (update.type() != id_updateAuthorizationState) { + return false; + } + const auto &data = update.c_updateAuthorizationState(); + const auto &state = data.vauthorization_state(); + return (state.type() == id_authorizationStateClosed); +} + +void LogError(uint32 type, RequestId requestId, const Error &error) { + LOG(("Tdb Error (%1) to 0x%2 (requestId %3): ") + .arg(error.code) + .arg(type, 0, 16) + .arg(requestId) + + error.message); +} + Instance::Manager::Manager(PrivateTag) : _manager(ClientManager::get_manager_singleton()) , _thread([=] { loop(); }) { @@ -138,11 +164,7 @@ std::shared_ptr Instance::Manager::Instance() { } void Instance::Manager::destroyClient(ClientId id) { - Expects(!_closingId); - - _closingId = id; sendToExternal(id, api::make_object()); - _closing.acquire(); _clients.remove(id); if (_clients.empty()) { @@ -188,17 +210,7 @@ void Instance::Manager::loop() { if (!response.object) { continue; } - if (response.object->get_id() == api::updateAuthorizationState::ID) { - const auto update = static_cast( - response.object.get()); - const auto state = update->authorization_state_.get(); - if (state->get_id() == api::authorizationStateClosed::ID) { - Assert(_closingId == response.client_id); - _closingId = 0; - _closing.release(); - continue; - } - } else if (response.object->get_id() == api::error::ID) { + if (response.object->get_id() == api::error::ID) { const auto error = static_cast( response.object.get()); if (error->code_ == 500 @@ -215,10 +227,7 @@ void Instance::Manager::loop() { clientId, update = tl_from(object) ]() mutable { - const auto i = _clients.find(clientId); - if (i != end(_clients)) { - i->second->handleUpdate(std::move(update)); - } + handleUpdateOnMain(clientId, std::move(update)); }); continue; } @@ -227,28 +236,56 @@ void Instance::Manager::loop() { lock.unlock(); if (!callback) { + if (const auto error = ParseError(object)) { + LogError(uint32(-1), requestId, *error); + } continue; } crl::on_main(weak_from_this(), [ this, clientId, requestId, - handler = (*callback)({ object }) + handler = (*callback)(requestId, object) ]() mutable { - const auto i = _clients.find(clientId); - if (i != end(_clients) - && i->second->shouldInvokeHandler(requestId) - && handler) { - handler(); - } + handleResponseOnMain(clientId, requestId, std::move(handler)); }); } } +void Instance::Manager::handleUpdateOnMain( + ClientId clientId, + TLupdate &&update) { + const auto i = _clients.find(clientId); + if (i == end(_clients)) { + return; + } + const auto instance = i->second; + if (ClientClosedUpdate(update)) { + _clients.erase(i); + } + instance->handleUpdate(std::move(update)); +} + +void Instance::Manager::handleResponseOnMain( + ClientId clientId, + RequestId requestId, + FnMut &&handler) { + const auto i = _clients.find(clientId); + if (i == end(_clients) + || !i->second->shouldInvokeHandler(requestId) + || !handler) { + return; + } + handler(); +} + Instance::Impl::Impl(InstanceConfig &&config) : _manager(Manager::Instance()) -, _client(_manager->createClient(this)) { - sendTdlibParameters(std::move(config)); +, _client(_manager->createClient(this)) +, _config(std::move(config)) { + QDir().mkpath(_config.databaseDirectory); + QDir().mkpath(_config.filesDirectory); + sendTdlibParameters(); } Instance::Impl::~Impl() { @@ -269,7 +306,7 @@ void Instance::Impl::sendPrepared( } crl::async([ manager = _manager, - clientId = _client, + clientId = _client.load(), requestId, request = std::move(request), callback = std::move(callback) @@ -293,6 +330,10 @@ bool Instance::Impl::shouldInvokeHandler(RequestId requestId) { } void Instance::Impl::handleUpdate(TLupdate &&update) { + if (ClientClosedUpdate(update)) { + _client = _manager->createClient(this); + sendTdlibParameters(); + } update.match([&](const TLDupdateAuthorizationState &data) { data.vauthorization_state().match([]( const TLDauthorizationStateWaitTdlibParameters &) { @@ -308,29 +349,27 @@ rpl::producer Instance::Impl::updates() const { return _updates.events(); } -void Instance::Impl::sendTdlibParameters(InstanceConfig &&config) { +void Instance::Impl::sendTdlibParameters() { const auto fail = [=](Error error) { LOG(("Critical Error: setTdlibParameters - %1").arg(error.message)); }; - QDir().mkpath(config.databaseDirectory); - QDir().mkpath(config.filesDirectory); send( allocateRequestId(), TLsetTdlibParameters( tl_tdlibParameters( - tl_bool(config.testDc), - tl_string(config.databaseDirectory), - tl_string(config.filesDirectory), // files_directory + tl_bool(_config.testDc), + tl_string(_config.databaseDirectory), + tl_string(_config.filesDirectory), // files_directory tl_bool(true), // use_file_database tl_bool(true), // use_chat_info_database tl_bool(true), // use_message_database tl_bool(false), // use_secret_chats - tl_int32(config.apiId), - tl_string(config.apiHash), - tl_string(config.systemLanguageCode), - tl_string(config.deviceModel), - tl_string(config.systemVersion), - tl_string(config.applicationVersion), + tl_int32(_config.apiId), + tl_string(_config.apiHash), + tl_string(_config.systemLanguageCode), + tl_string(_config.deviceModel), + tl_string(_config.systemVersion), + tl_string(_config.applicationVersion), tl_bool(true), // enable_storage_optimizer tl_bool(false))), // ignore_file_names nullptr, @@ -370,7 +409,7 @@ void ExecuteExternal( ExternalCallback &&callback) { const auto result = ClientManager::execute( api::object_ptr(request())); - if (auto handler = callback ? callback(result.get()) : nullptr) { + if (auto handler = callback ? callback(0, result.get()) : nullptr) { handler(); } } diff --git a/Telegram/SourceFiles/tdb/details/tdb_instance.h b/Telegram/SourceFiles/tdb/details/tdb_instance.h index cac36b84d2797..525bf8dc3a702 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_instance.h +++ b/Telegram/SourceFiles/tdb/details/tdb_instance.h @@ -15,23 +15,29 @@ namespace Tdb::details { using RequestId = int64; [[nodiscard]] std::optional ParseError(ExternalResponse); +[[nodiscard]] bool ClientClosedUpdate(const TLupdate &update); + +void LogError(uint32 type, RequestId requestId, const Error &error); template [[nodiscard]] ExternalCallback PrepareCallback( + uint32 type, FnMut done, FnMut fail) { if (!done && !fail) { return nullptr; } return [ + type, done = std::move(done), fail = std::move(fail) - ](ExternalResponse external) mutable -> FnMut { + ](RequestId requestId, ExternalResponse external) mutable + -> FnMut { if (auto error = ParseError(external)) { + LogError(type, requestId, *error); if (!fail) { return nullptr; } - // #TODO tdlib log error return [ fail = std::move(fail), error = *error @@ -81,10 +87,12 @@ class Instance final { Request &&request, FnMut &&done, FnMut &&fail) { + const auto type = request.type(); sendPrepared( requestId, tl_to_generator(std::move(request)), PrepareCallback( + type, std::move(done), std::move(fail))); } @@ -119,9 +127,10 @@ template < auto Execute(Request &&request) { using Response = typename Request::ResponseType; auto container = base::expected(); + const auto type = request.type(); ExecuteExternal( tl_to_generator(std::move(request)), - PrepareCallback([&](const Response &result) { + PrepareCallback(type, [&](const Response &result) { container = result; }, [&](const Error &error) { container = base::make_unexpected(error); diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h index 5fd0e90f5b911..1201f34ccdb1f 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core.h +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h @@ -130,7 +130,7 @@ inline bool operator!=(const TLstring &a, const TLstring &b) { using ExternalRequest = ::td::td_api::Function*; using ExternalResponse = const ::td::td_api::Object*; using ExternalGenerator = Fn; -using ExternalCallback = FnMut(ExternalResponse)>; +using ExternalCallback = FnMut(uint64, ExternalResponse)>; template [[nodiscard]] ExternalGenerator tl_to_generator(Request &&); diff --git a/Telegram/SourceFiles/tdb/tdb_account.h b/Telegram/SourceFiles/tdb/tdb_account.h index 3e7e3a2cf27cd..0a2bdc5b65c82 100644 --- a/Telegram/SourceFiles/tdb/tdb_account.h +++ b/Telegram/SourceFiles/tdb/tdb_account.h @@ -41,4 +41,8 @@ class Account final { using details::Execute; +[[nodiscard]] inline bool IsRecreatedUpdate(const TLupdate &update) { + return details::ClientClosedUpdate(update); +} + } // namespace Tdb diff --git a/Telegram/SourceFiles/window/window_lock_widgets.cpp b/Telegram/SourceFiles/window/window_lock_widgets.cpp index 813db805b3a8b..a68b416e192fd 100644 --- a/Telegram/SourceFiles/window/window_lock_widgets.cpp +++ b/Telegram/SourceFiles/window/window_lock_widgets.cpp @@ -184,6 +184,24 @@ TermsLock TermsLock::FromMTP( }; } +TermsLock TermsLock::FromTL( + Main::Session *session, + const Tdb::TLDtermsOfService &data) { + const auto minAge = data.vmin_user_age().v; + auto text = data.vtext().match([&](const Tdb::TLDformattedText &data) { + return TextWithEntities{ + TextUtilities::Clean(data.vtext().v), + Api::EntitiesFromTL(session, data.ventities().v), + }; + }); + return { + {}, // #TODO legacy + std::move(text), + (minAge ? std::make_optional(minAge) : std::nullopt), + Tdb::tl_is_true(data.vshow_popup()) + }; +} + TermsBox::TermsBox( QWidget*, const TermsLock &data, diff --git a/Telegram/SourceFiles/window/window_lock_widgets.h b/Telegram/SourceFiles/window/window_lock_widgets.h index d2967d47fff0f..7f21dc13f4cb3 100644 --- a/Telegram/SourceFiles/window/window_lock_widgets.h +++ b/Telegram/SourceFiles/window/window_lock_widgets.h @@ -23,6 +23,10 @@ namespace Main { class Session; } // namespace Main +namespace Tdb { +class TLDtermsOfService; +} // namespace Tdb + namespace Window { class Controller; @@ -88,6 +92,9 @@ struct TermsLock { static TermsLock FromMTP( Main::Session *session, const MTPDhelp_termsOfService &data); + static TermsLock FromTL( + Main::Session *session, + const Tdb::TLDtermsOfService &data); }; From 7c0478fac2a0b55a212524cde39ed73dfe7e117b Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 21 Apr 2021 22:26:29 +0400 Subject: [PATCH 009/350] Improve intro steps navigation. --- Telegram/SourceFiles/intro/intro_code.cpp | 5 + Telegram/SourceFiles/intro/intro_code.h | 4 + .../intro/intro_password_check.cpp | 11 ++ .../SourceFiles/intro/intro_password_check.h | 4 + Telegram/SourceFiles/intro/intro_phone.cpp | 5 + Telegram/SourceFiles/intro/intro_phone.h | 4 + Telegram/SourceFiles/intro/intro_qr.cpp | 3 + Telegram/SourceFiles/intro/intro_qr.h | 4 + Telegram/SourceFiles/intro/intro_signup.cpp | 5 + Telegram/SourceFiles/intro/intro_signup.h | 4 + Telegram/SourceFiles/intro/intro_start.cpp | 6 +- Telegram/SourceFiles/intro/intro_start.h | 4 + Telegram/SourceFiles/intro/intro_step.cpp | 17 ++- Telegram/SourceFiles/intro/intro_step.h | 26 +++- Telegram/SourceFiles/intro/intro_widget.cpp | 143 +++++++++++++++++- Telegram/SourceFiles/intro/intro_widget.h | 20 +++ 16 files changed, 255 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/intro/intro_code.cpp b/Telegram/SourceFiles/intro/intro_code.cpp index a153cae71163d..71180d4f51cf7 100644 --- a/Telegram/SourceFiles/intro/intro_code.cpp +++ b/Telegram/SourceFiles/intro/intro_code.cpp @@ -246,6 +246,8 @@ void CodeWidget::finished() { } void CodeWidget::cancelled() { + _sentRequest = false; + #if 0 // #TODO legacy api().request(base::take(_sentRequest)).cancel(); api().request(base::take(_callRequestId)).cancel(); @@ -344,7 +346,10 @@ void CodeWidget::checkCodeFail(const Error &error) { if (type == u"PHONE_NUMBER_INVALID" || type == u"PHONE_CODE_EXPIRED" || type == u"PHONE_NUMBER_BANNED") { +#if 0 // mtp goBack(); +#endif + go(StepType::Start); } else if (type == u"PHONE_CODE_EMPTY" || type == u"PHONE_CODE_INVALID") { showCodeError(tr::lng_bad_code()); diff --git a/Telegram/SourceFiles/intro/intro_code.h b/Telegram/SourceFiles/intro/intro_code.h index 31a892dd0e176..f0f3f1f1b7122 100644 --- a/Telegram/SourceFiles/intro/intro_code.h +++ b/Telegram/SourceFiles/intro/intro_code.h @@ -60,6 +60,10 @@ class CodeWidget final : public Step { void updateDescText(); + StepType type() const override { + return StepType::Code; + } + protected: void resizeEvent(QResizeEvent *e) override; diff --git a/Telegram/SourceFiles/intro/intro_password_check.cpp b/Telegram/SourceFiles/intro/intro_password_check.cpp index 16f0932e4d1a2..9f167f10c0115 100644 --- a/Telegram/SourceFiles/intro/intro_password_check.cpp +++ b/Telegram/SourceFiles/intro/intro_password_check.cpp @@ -127,6 +127,8 @@ void PasswordCheckWidget::activate() { } void PasswordCheckWidget::cancelled() { + _sentRequest = false; + #if 0 // mtp api().request(base::take(_sentRequest)).cancel(); #endif @@ -457,7 +459,10 @@ void PasswordCheckWidget::recoverFail(const Error &error) { const auto &type = error.message; if (type == u"PASSWORD_EMPTY" || type == u"AUTH_KEY_UNREGISTERED") { +#if 0 // mtp goBack(); +#endif + go(StepType::Start); } else if (type == u"PASSWORD_RECOVERY_NA") { _pwdField->show(); _pwdHint->show(); @@ -487,7 +492,13 @@ void PasswordCheckWidget::handleAuthorizationState( || _passwordState.hint != data.vpassword_hint().v) { getData()->pwdState.hasRecovery = has; getData()->pwdState.hint = data.vpassword_hint().v; +#if 0 // mtp goReplace(Animate::Forward); +#endif + _passwordState.hasRecovery = has; + _passwordState.hint = data.vpassword_hint().v; + _passwordState.notEmptyPassport = data.vhas_passport_data().v; + refreshLang(); } else { _emailPattern = data.vrecovery_email_address_pattern().v; updateDescriptionText(); diff --git a/Telegram/SourceFiles/intro/intro_password_check.h b/Telegram/SourceFiles/intro/intro_password_check.h index 6520490e1c98f..5945f2736a403 100644 --- a/Telegram/SourceFiles/intro/intro_password_check.h +++ b/Telegram/SourceFiles/intro/intro_password_check.h @@ -35,6 +35,10 @@ class PasswordCheckWidget final : public Step { void submit() override; rpl::producer nextButtonText() const override; + StepType type() const override { + return StepType::Password; + } + protected: void resizeEvent(QResizeEvent *e) override; diff --git a/Telegram/SourceFiles/intro/intro_phone.cpp b/Telegram/SourceFiles/intro/intro_phone.cpp index e5543bcbca1f9..beffe57dc143b 100644 --- a/Telegram/SourceFiles/intro/intro_phone.cpp +++ b/Telegram/SourceFiles/intro/intro_phone.cpp @@ -115,7 +115,10 @@ void PhoneWidget::setupQrLogin() { }, qrLogin->lifetime()); qrLogin->setClickedCallback([=] { +#if 0 // mtp goReplace(Animate::Forward); +#endif + go(StepType::Qr); }); } @@ -341,6 +344,8 @@ void PhoneWidget::finished() { } void PhoneWidget::cancelled() { + _sentRequest = false; + #if 0 // #TODO legacy api().request(base::take(_sentRequest)).cancel(); #endif diff --git a/Telegram/SourceFiles/intro/intro_phone.h b/Telegram/SourceFiles/intro/intro_phone.h index 1b64969b5ba65..82fccb7a9995c 100644 --- a/Telegram/SourceFiles/intro/intro_phone.h +++ b/Telegram/SourceFiles/intro/intro_phone.h @@ -40,6 +40,10 @@ class PhoneWidget final : public Step { return true; } + StepType type() const override { + return StepType::Phone; + } + protected: void resizeEvent(QResizeEvent *e) override; diff --git a/Telegram/SourceFiles/intro/intro_qr.cpp b/Telegram/SourceFiles/intro/intro_qr.cpp index d1ce29da0e19f..1e0aa20af06e3 100644 --- a/Telegram/SourceFiles/intro/intro_qr.cpp +++ b/Telegram/SourceFiles/intro/intro_qr.cpp @@ -254,7 +254,10 @@ void QrWidget::handleAuthorizationState(const TLauthorizationState &state) { } void QrWidget::submit() { +#if 0 // mtp goReplace(Animate::Forward); +#endif + go(StepType::Phone); } rpl::producer QrWidget::nextButtonText() const { diff --git a/Telegram/SourceFiles/intro/intro_qr.h b/Telegram/SourceFiles/intro/intro_qr.h index f350f0331ea6e..371bc60caeb3d 100644 --- a/Telegram/SourceFiles/intro/intro_qr.h +++ b/Telegram/SourceFiles/intro/intro_qr.h @@ -31,6 +31,10 @@ class QrWidget final : public Step { return true; } + StepType type() const override { + return StepType::Qr; + } + private: int errorTop() const override; diff --git a/Telegram/SourceFiles/intro/intro_signup.cpp b/Telegram/SourceFiles/intro/intro_signup.cpp index b4bc937ebb11d..10382e0c96c51 100644 --- a/Telegram/SourceFiles/intro/intro_signup.cpp +++ b/Telegram/SourceFiles/intro/intro_signup.cpp @@ -112,6 +112,8 @@ void SignupWidget::activate() { } void SignupWidget::cancelled() { + _sentRequest = false; + #if 0 api().request(base::take(_sentRequest)).cancel(); #endif @@ -246,7 +248,10 @@ void SignupWidget::registerUserFail(const Error &error) { || type == u"PHONE_CODE_EMPTY" || type == u"PHONE_CODE_INVALID" || type == u"PHONE_NUMBER_OCCUPIED") { +#if 0 // mtp goBack(); +#endif + go(StepType::Start); } else if (type == u"FIRSTNAME_INVALID") { showError(tr::lng_bad_name()); _first->setFocus(); diff --git a/Telegram/SourceFiles/intro/intro_signup.h b/Telegram/SourceFiles/intro/intro_signup.h index 7266ab721e6a7..a9c0535b5dd5f 100644 --- a/Telegram/SourceFiles/intro/intro_signup.h +++ b/Telegram/SourceFiles/intro/intro_signup.h @@ -32,6 +32,10 @@ class SignupWidget final : public Step { void submit() override; rpl::producer nextButtonText() const override; + StepType type() const override { + return StepType::SignUp; + } + protected: void resizeEvent(QResizeEvent *e) override; diff --git a/Telegram/SourceFiles/intro/intro_start.cpp b/Telegram/SourceFiles/intro/intro_start.cpp index 08ac6ddcf81dc..f62603d991c2a 100644 --- a/Telegram/SourceFiles/intro/intro_start.cpp +++ b/Telegram/SourceFiles/intro/intro_start.cpp @@ -47,7 +47,11 @@ void StartWidget::submit() { api().request( TLgetAuthorizationState() ).done([=](const TLauthorizationState &result) { - Step::handleAuthorizationState(result); + if (result.type() == id_authorizationStateWaitPhoneNumber) { + go(StepType::Qr); + } else { + Step::handleAuthorizationState(result); + } }).send(); } diff --git a/Telegram/SourceFiles/intro/intro_start.h b/Telegram/SourceFiles/intro/intro_start.h index 46d4d38ce3ea8..b02c2b92943ba 100644 --- a/Telegram/SourceFiles/intro/intro_start.h +++ b/Telegram/SourceFiles/intro/intro_start.h @@ -28,6 +28,10 @@ class StartWidget : public Step { void submit() override; rpl::producer nextButtonText() const override; + StepType type() const override { + return StepType::Start; + } + private: void handleAuthorizationState( const Tdb::TLauthorizationState &state) override; diff --git a/Telegram/SourceFiles/intro/intro_step.cpp b/Telegram/SourceFiles/intro/intro_step.cpp index 4b194c480df68..aca6f7a92bc60 100644 --- a/Telegram/SourceFiles/intro/intro_step.cpp +++ b/Telegram/SourceFiles/intro/intro_step.cpp @@ -139,6 +139,7 @@ rpl::producer Step::nextButtonStyle() const { return rpl::single((const style::RoundButton*)(nullptr)); } +#if 0 // mtp void Step::goBack() { if (_goCallback) { _goCallback(nullptr, StackAction::Back, Animate::Back); @@ -157,7 +158,6 @@ void Step::goReplace(Step *step, Animate animate) { } } -#if 0 // mtp void Step::finish(const MTPauth_Authorization &auth, QImage &&photo) { auth.match([&](const MTPDauth_authorization &data) { if (data.vuser().type() != mtpc_user @@ -588,26 +588,26 @@ void Step::handleUpdate(const TLupdate &update) { void Step::handleAuthorizationState(const TLauthorizationState &state) { return state.match([&]( const TLDauthorizationStateWaitPhoneNumber &data) { - goNext(); + go(StepType::Phone); }, [&](const TLDauthorizationStateWaitCode &data) { fillCodeInfo(data.vcode_info()); - goNext(); + go(StepType::Code); }, [&](const TLDauthorizationStateWaitOtherDeviceConfirmation &data) { getData()->qrLink = data.vlink().v; - goNext(); + go(StepType::Qr); }, [&](const TLDauthorizationStateWaitRegistration &data) { fillTerms(data.vterms_of_service()); - goNext(); + go(StepType::SignUp); }, [&](const TLDauthorizationStateWaitPassword &data) { getData()->pwdState.hasRecovery = tl_is_true( data.vhas_recovery_email_address()); getData()->pwdState.hint = data.vpassword_hint().v; //getData()->pwdState.notEmptyPassport = data.is_has_secure_values(); // #TODO tdlib - goNext(); + go(StepType::Password); }, [&](const TLDauthorizationStateReady &data) { finish(); }, [&](const auto &) { - goNext(); + go(StepType::Start); }); } @@ -725,8 +725,11 @@ void Step::setShowAnimationClipping(QRect clipping) { _coverAnimation.clipping = clipping; } +#if 0 // mtp void Step::setGoCallback( Fn callback) { +#endif +void Step::setGoCallback(Fn callback) { _goCallback = std::move(callback); } diff --git a/Telegram/SourceFiles/intro/intro_step.h b/Telegram/SourceFiles/intro/intro_step.h index cf8224b50b080..8f56a78313c46 100644 --- a/Telegram/SourceFiles/intro/intro_step.h +++ b/Telegram/SourceFiles/intro/intro_step.h @@ -36,6 +36,15 @@ struct Data; enum class StackAction; enum class Animate; +enum class StepType { + Start, + Phone, + Qr, + Code, + Password, + SignUp, +}; + class Step : public Ui::RpWidget { public: Step( @@ -48,6 +57,7 @@ class Step : public Ui::RpWidget { [[nodiscard]] Main::Account &account() const { return *_account; } + [[nodiscard]] virtual StepType type() const = 0; // It should not be called in StartWidget, in other steps it should be // present and not changing. @@ -60,8 +70,11 @@ class Step : public Ui::RpWidget { setFocus(); } +#if 0 // mtp void setGoCallback( Fn callback); +#endif + void setGoCallback(Fn callback); void setShowResetCallback(Fn callback); void setShowTermsCallback(Fn callback); void setCancelNearestDcCallback(Fn callback); @@ -125,7 +138,6 @@ class Step : public Ui::RpWidget { const MTPUser &user, QImage photo, const QVector &filters); -#endif void goBack(); @@ -138,6 +150,13 @@ class Step : public Ui::RpWidget { void goReplace(Animate animate) { goReplace(new StepType(parentWidget(), _account, _data), animate); } +#endif + + void go(StepType type) { + if (_goCallback) { + _goCallback(type); + } + } void showResetButton() { if (_showResetCallback) _showResetCallback(); @@ -186,8 +205,10 @@ class Step : public Ui::RpWidget { float64 howMuchHidden); void refreshError(const QString &text); +#if 0 // mtp void goNext(Step *step); void goReplace(Step *step, Animate animate); +#endif [[nodiscard]] CoverAnimation prepareCoverAnimation(Step *step); [[nodiscard]] QPixmap prepareContentSnapshot(); @@ -208,7 +229,10 @@ class Step : public Ui::RpWidget { mutable std::optional _api; bool _hasCover = false; +#if 0 // mtp Fn _goCallback; +#endif + Fn _goCallback; Fn _showResetCallback; Fn _showTermsCallback; Fn _cancelNearestDcCallback; diff --git a/Telegram/SourceFiles/intro/intro_widget.cpp b/Telegram/SourceFiles/intro/intro_widget.cpp index 53f30d6ed1e0d..e1ea0ab26d1c8 100644 --- a/Telegram/SourceFiles/intro/intro_widget.cpp +++ b/Telegram/SourceFiles/intro/intro_widget.cpp @@ -103,7 +103,6 @@ Widget::Widget( _api.emplace(instance); crl::on_main(this, [=] { createLanguageLink(); }); }, lifetime()); -#endif switch (point) { case EnterPoint::Start: getNearestDC(); @@ -117,6 +116,20 @@ Widget::Widget( break; default: Unexpected("Enter point in Intro::Widget::Widget."); } +#endif + switch (point) { + case EnterPoint::Start: + getNearestDC(); + go(StepType::Start); + break; + case EnterPoint::Phone: + go(StepType::Phone); + break; + case EnterPoint::Qr: + go(StepType::Qr); + break; + default: Unexpected("Enter point in Intro::Widget::Widget."); + } fixOrder(); @@ -360,6 +373,7 @@ void Widget::setInnerFocus() { } } +#if 0 // mtp void Widget::historyMove(StackAction action, Animate animate) { Expects(_stepHistory.size() > 1); @@ -374,6 +388,34 @@ void Widget::historyMove(StackAction action, Animate animate) { } else if (action == StackAction::Replace) { _stepHistory.erase(_stepHistory.end() - 2); } +#endif +void Widget::historyMove( + Step *wasStep, + std::vector>::iterator nowStep) { + _back->raise(); + _settings->raise(); + if (_update) { + _update->raise(); + } + _connecting->raise(); + + for (auto i = nowStep + 1; i != end(_stepHistory); ++i) { + (*i)->cancelled(); + } + if (!wasStep || wasStep->animating()) { + _stepHistory.erase(nowStep + 1, end(_stepHistory)); + showControls(); + getStep()->showFast(); + setInnerFocus(); + return; + } + + const auto wasType = wasStep ? wasStep->type() : StepType::Start; + const auto nowType = (*nowStep)->type(); + const auto animate = ((nowType >= wasType) + || (wasType == StepType::Qr && nowType == StepType::Phone)) + ? Animate::Forward + : Animate::Back; if (_resetAccount) { hideAndDestroy(std::exchange(_resetAccount, { nullptr })); @@ -399,9 +441,14 @@ void Widget::historyMove(StackAction action, Animate animate) { }, _next->lifetime()); } +#if 0 // mtp getStep()->finishInit(); getStep()->prepareShowAnimated(wasStep); if (wasStep->hasCover() != getStep()->hasCover()) { +#endif + (*nowStep)->finishInit(); + (*nowStep)->prepareShowAnimated(wasStep); + if (wasStep->hasCover() != (*nowStep)->hasCover()) { _nextTopFrom = wasStep->contentTop() + st::introNextTop; _controlsTopFrom = wasStep->hasCover() ? st::introCoverHeight : 0; _coverShownAnimation.start( @@ -413,12 +460,18 @@ void Widget::historyMove(StackAction action, Animate animate) { } _stepLifetime.destroy(); +#if 0 // mtp if (action == StackAction::Forward || action == StackAction::Replace) { wasStep->finished(); } if (action == StackAction::Back || action == StackAction::Replace) { delete base::take(wasStep); } +#endif + if (wasStep) { + wasStep->finished(); + } + _stepHistory.erase(nowStep + 1, end(_stepHistory)); _back->toggle(getStep()->hasBack(), anim::type::normal); auto stepHasCover = getStep()->hasCover(); @@ -454,6 +507,56 @@ void Widget::fixOrder() { _connecting->raise(); } +template +std::unique_ptr Widget::makeStep() { + return std::make_unique(this, _account, getData()); +} + +void Widget::go(StepType type) { + if (type == StepType::Start) { + if (const auto parent + = Core::App().domain().maybeLastOrSomeAuthedAccount()) { + Core::App().domain().activate(parent); + } + return; + } else if (!_stepHistory.empty() && getStep()->type() == type) { + return; + } + const auto wasStep = _stepHistory.empty() ? nullptr : getStep().get(); + auto nowStep = begin(_stepHistory); + for (; nowStep != end(_stepHistory); ++nowStep) { + if ((*nowStep)->type() == type) { + break; + } + } + auto saved = std::unique_ptr(); + if (nowStep == end(_stepHistory)) { + appendStep([&]() -> std::unique_ptr { + switch (type) { + case StepType::Start: return makeStep(); + case StepType::Phone: return makeStep(); + case StepType::Qr: return makeStep(); + case StepType::Code: return makeStep(); + case StepType::Password: return makeStep(); + case StepType::SignUp: return makeStep(); + } + Unexpected("Type in Intro::Widget::go."); + }()); + if (type == StepType::Qr || type == StepType::Phone) { + while (_stepHistory.size() > 1 + && (*(_stepHistory.end() - 2))->type() != StepType::Start) { + if ((_stepHistory.end() - 2)->get() == wasStep) { + saved = std::move(*(_stepHistory.end() - 2)); + } + _stepHistory.erase(_stepHistory.end() - 2); + } + } + nowStep = (_stepHistory.end() - 1); + } + historyMove(wasStep, nowStep); +} + +#if 0 // mtp void Widget::moveToStep(Step *step, StackAction action, Animate animate) { appendStep(step); _back->raise(); @@ -489,6 +592,28 @@ void Widget::appendStep(Step *step) { acceptTerms(callback); }); } +#endif + +void Widget::appendStep(std::unique_ptr step) { + const auto raw = step.get(); + _stepHistory.push_back(std::move(step)); + raw->setGeometry(rect()); + raw->setGoCallback([=](StepType type) { + go(type); + }); + raw->setShowResetCallback([=] { + showResetButton(); + }); + raw->setShowTermsCallback([=] { + showTerms(); + }); + raw->setCancelNearestDcCallback([=] { + _api.request(base::take(_nearestDcRequestId)).cancel(); + }); + raw->setAcceptTermsCallback([=](Fn callback) { + acceptTerms(callback); + }); +} void Widget::showResetButton() { if (!_resetAccount) { @@ -552,6 +677,7 @@ void Widget::resetAccount() { getData()->controller->hideLayer(); if (getData()->phone.isEmpty()) { +#if 0 // mtp moveToStep( new QrWidget(this, _account, getData()), StackAction::Replace, @@ -561,6 +687,10 @@ void Widget::resetAccount() { new SignupWidget(this, _account, getData()), StackAction::Replace, Animate::Forward); +#endif + go(StepType::Qr); + } else { + go(StepType::SignUp); } }).fail([=](const Error &error) { _resetRequest = 0; @@ -821,7 +951,10 @@ void Widget::resizeEvent(QResizeEvent *e) { if (_stepHistory.empty()) { return; } +#if 0 // mtp for (const auto step : _stepHistory) { +#endif + for (const auto &step : _stepHistory) { step->setGeometry(rect()); } @@ -889,6 +1022,7 @@ void Widget::keyPressEvent(QKeyEvent *e) { void Widget::backRequested() { if (_stepHistory.size() > 1) { +#if 0 // mtp historyMove(StackAction::Back, Animate::Back); } else if (const auto parent = Core::App().domain().maybeLastOrSomeAuthedAccount()) { @@ -898,13 +1032,20 @@ void Widget::backRequested() { new StartWidget(this, _account, getData()), StackAction::Replace, Animate::Back); +#endif + go(_stepHistory[_stepHistory.size() - 2]->type()); + } else { + go(StepType::Start); } } Widget::~Widget() { +#if 0 // mtp for (auto step : base::take(_stepHistory)) { delete step; } +#endif + base::take(_stepHistory); } } // namespace Intro diff --git a/Telegram/SourceFiles/intro/intro_widget.h b/Telegram/SourceFiles/intro/intro_widget.h index 3b9834784f9d4..2370d37478111 100644 --- a/Telegram/SourceFiles/intro/intro_widget.h +++ b/Telegram/SourceFiles/intro/intro_widget.h @@ -82,6 +82,7 @@ enum class Animate { }; class Step; +enum class StepType; } // namespace details @@ -142,6 +143,7 @@ class Widget void acceptTerms(Fn callback); void hideAndDestroy(object_ptr> widget); +#if 0 // mtp [[nodiscard]] details::Step *getStep(int skip = 0) const { Expects(skip >= 0); Expects(skip < _stepHistory.size()); @@ -154,6 +156,21 @@ class Widget details::StackAction action, details::Animate animate); void appendStep(details::Step *step); +#endif + + [[nodiscard]] not_null getStep() const { + Expects(!_stepHistory.empty()); + + return _stepHistory.back().get(); + } + void historyMove( + details::Step *wasStep, + std::vector>::iterator nowStep); + void appendStep(std::unique_ptr step); + void go(details::StepType type); + + template + [[nodiscard]] std::unique_ptr makeStep(); void getNearestDC(); void showTerms(Fn callback); @@ -186,7 +203,10 @@ class Widget std::unique_ptr _showAnimation; +#if 0 // mtp std::vector _stepHistory; +#endif + std::vector> _stepHistory; rpl::lifetime _stepLifetime; details::Data _data; From f773bab0e0daa9700d094c2e37b5139b0eb43d48 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 29 Apr 2021 12:18:24 +0400 Subject: [PATCH 010/350] Start chat list loading. --- Telegram/SourceFiles/api/api_peer_photo.cpp | 25 +++++++++++ Telegram/SourceFiles/apiwrap.cpp | 32 +++++++++++++- Telegram/SourceFiles/apiwrap.h | 11 +++++ Telegram/SourceFiles/data/data_channel.cpp | 8 ++++ Telegram/SourceFiles/data/data_channel.h | 5 +++ Telegram/SourceFiles/data/data_chat.cpp | 8 ++++ Telegram/SourceFiles/data/data_chat.h | 4 ++ Telegram/SourceFiles/data/data_peer.cpp | 33 +++++++++++++++ Telegram/SourceFiles/data/data_peer.h | 12 ++++++ Telegram/SourceFiles/data/data_peer_id.cpp | 38 +++++++++++++++++ Telegram/SourceFiles/data/data_peer_id.h | 12 ++++++ Telegram/SourceFiles/data/data_session.cpp | 42 +++++++++++++------ Telegram/SourceFiles/data/data_user.cpp | 10 +++++ Telegram/SourceFiles/data/data_user.h | 5 +++ Telegram/SourceFiles/history/history.cpp | 2 + Telegram/SourceFiles/intro/intro_widget.cpp | 30 +++++++------ Telegram/SourceFiles/intro/intro_widget.h | 2 +- Telegram/SourceFiles/main/main_session.cpp | 8 ++++ Telegram/SourceFiles/main/main_session.h | 5 +++ .../SourceFiles/storage/file_download.cpp | 13 ++++++ .../SourceFiles/tdb/details/tdb_instance.cpp | 2 +- .../SourceFiles/ui/image/image_location.cpp | 27 +++++++++++- .../SourceFiles/ui/image/image_location.h | 42 +++++++++++++++++++ 23 files changed, 343 insertions(+), 33 deletions(-) diff --git a/Telegram/SourceFiles/api/api_peer_photo.cpp b/Telegram/SourceFiles/api/api_peer_photo.cpp index 25a7065873279..9cfc1bbb0a7a7 100644 --- a/Telegram/SourceFiles/api/api_peer_photo.cpp +++ b/Telegram/SourceFiles/api/api_peer_photo.cpp @@ -27,11 +27,16 @@ For license and copyright information please follow this link: #include "storage/localimageloader.h" #include "storage/storage_user_photos.h" +#include "tdb/tdb_sender.h" +#include "tdb/tdb_tl_scheme.h" + #include namespace Api { namespace { +using namespace Tdb; + constexpr auto kSharedMediaLimit = 100; [[nodiscard]] SendMediaReady PreparePeerPhoto( @@ -248,6 +253,7 @@ void PeerPhoto::suggest(not_null peer, UserPhoto &&photo) { } void PeerPhoto::clear(not_null photo) { +#if 0 // #TODO legacy const auto self = _session->user(); if (self->userpicPhotoId() == photo->id) { _api.request(MTPphotos_UpdateProfilePhoto( @@ -292,6 +298,25 @@ void PeerPhoto::clear(not_null photo) { photo->id)); } } +#endif + + if (_session->user()->userpicPhotoId() == photo->id) { + _session->sender().request(TLdeleteProfilePhoto( + tl_int64(photo->id) + )).send(); + } else if (photo->peer && photo->peer->userpicPhotoId() == photo->id) { + _session->sender().request(TLsetChatPhoto( + peerToTdbChat(photo->peer->id), + null + )).send(); + } else { + _session->sender().request(TLdeleteProfilePhoto( + tl_int64(photo->id) + )).send(); + _session->storage().remove(Storage::UserPhotosRemoveOne( + peerToUser(_session->userPeerId()), + photo->id)); + } } void PeerPhoto::clearPersonal(not_null user) { diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 82c8190518748..51c2883cac1e7 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -100,6 +100,8 @@ For license and copyright information please follow this link: #include "storage/storage_media_prepare.h" #include "storage/storage_account.h" +#include "tdb/tdb_sender.h" + namespace { // Save draft to the cloud with 1 sec extra delay. @@ -116,6 +118,7 @@ constexpr auto kDialogsFirstLoad = 20; constexpr auto kDialogsPerPage = 500; constexpr auto kStatsSessionKillTimeout = 10 * crl::time(1000); +using namespace Tdb; using PhotoFileLocationId = Data::PhotoFileLocationId; using DocumentFileLocationId = Data::DocumentFileLocationId; using UpdatedFileReferences = Data::UpdatedFileReferences; @@ -214,6 +217,14 @@ Api::Updates &ApiWrap::updates() const { return _session->updates(); } +Account &ApiWrap::tdb() const { + return _session->tdb(); +} + +Sender &ApiWrap::sender() const { + return _session->sender(); +} + void ApiWrap::setupSupportMode() { if (!_session->supportMode()) { return; @@ -848,6 +859,7 @@ void ApiWrap::requestMoreDialogs(Data::Folder *folder) { const auto firstLoad = !state->offsetDate; const auto loadCount = firstLoad ? kDialogsFirstLoad : kDialogsPerPage; +#if 0 // #TODO legacy const auto flags = MTPmessages_GetDialogs::Flag::f_exclude_pinned | MTPmessages_GetDialogs::Flag::f_folder_id; const auto hash = uint64(0); @@ -901,6 +913,20 @@ void ApiWrap::requestMoreDialogs(Data::Folder *folder) { }).fail([=] { dialogsLoadState(folder)->requestId = 0; }).send(); +#endif + + state->requestId = sender().request(TLgetChats( + folder ? tl_chatListArchive() : tl_chatListMain(), + tl_int32(loadCount) + )).done([=](const TLchats &result) { + result.match([&](const TLDchats &data) { + for (const auto &chatId : data.vchat_ids().v) { + const auto peerId = peerFromTdbChat(chatId); + } + }); + }).fail([=](const Error &error) { + dialogsLoadState(folder)->requestId = 0; + }).send(); if (!state->pinnedReceived) { requestPinnedDialogs(folder); @@ -1927,7 +1953,8 @@ void ApiWrap::updatePrivacyLastSeens() { Data::PeerUpdate::Flag::OnlineStatus); session().data().maybeStopWatchForOffline(user); }); - + +#if 0 // #TODO legacy if (_contactsStatusesRequestId) { request(_contactsStatusesRequestId).cancel(); } @@ -1954,8 +1981,10 @@ void ApiWrap::updatePrivacyLastSeens() { }).fail([this] { _contactsStatusesRequestId = 0; }).send(); +#endif } +#if 0 // #TODO legacy int ApiWrap::OnlineTillFromStatus( const MTPUserStatus &status, int currentOnlineTill) { @@ -1971,6 +2000,7 @@ int ApiWrap::OnlineTillFromStatus( } Unexpected("Bad UserStatus type."); } +#endif void ApiWrap::clearHistory(not_null peer, bool revoke) { deleteHistory(peer, true, revoke); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index ecb0f968aaefc..50cc83f6562a2 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -14,6 +14,7 @@ For license and copyright information please follow this link: #include "mtproto/sender.h" #include "data/stickers/data_stickers_set.h" #include "data/data_messages.h" +#include "tdb/tdb_sender.h" class TaskQueue; struct MessageGroupId; @@ -22,6 +23,11 @@ enum class SendMediaType; struct FileLoadTo; struct ChatRestrictionsInfo; +namespace Tdb { +class Account; +class Sender; +} // namespace Tdb + namespace Main { class Session; } // namespace Main @@ -139,6 +145,9 @@ class ApiWrap final : public MTP::Sender { [[nodiscard]] Storage::Account &local() const; [[nodiscard]] Api::Updates &updates() const; + [[nodiscard]] Tdb::Account &tdb() const; + [[nodiscard]] Tdb::Sender &sender() const; + void applyUpdates( const MTPUpdates &updates, uint64 sentMessageRandomId = 0); @@ -257,9 +266,11 @@ class ApiWrap final : public MTP::Sender { void updateNotifySettingsDelayed(Data::DefaultNotify type); void saveDraftToCloudDelayed(not_null thread); +#if 0 // #TODO legacy static int OnlineTillFromStatus( const MTPUserStatus &status, int currentOnlineTill); +#endif void clearHistory(not_null peer, bool revoke); void deleteConversation(not_null peer, bool revoke); diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 5daff7e176115..813dc345870b0 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -32,11 +32,13 @@ For license and copyright information please follow this link: #include "main/main_session.h" #include "api/api_chat_invite.h" #include "api/api_invite_links.h" +#include "tdb/tdb_tl_scheme.h" #include "apiwrap.h" #include "window/notifications_manager.h" namespace { +using namespace Tdb; using UpdateFlag = Data::PeerUpdate::Flag; } // namespace @@ -93,6 +95,7 @@ ChannelData::ChannelData(not_null owner, PeerId id) , _ptsWaiter(&owner->session().updates()) { } +#if 0 // #TODO legacy void ChannelData::setPhoto(const MTPChatPhoto &photo) { photo.match([&](const MTPDchatPhoto & data) { updateUserpic( @@ -103,6 +106,11 @@ void ChannelData::setPhoto(const MTPChatPhoto &photo) { clearUserpic(); }); } +#endif + +void ChannelData::setPhoto(const TLchatPhotoInfo &photo) { + updateUserpic(photo); +} void ChannelData::setName( const QString &newName, diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index bdf0f42054386..577ae2ff98cd7 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -156,9 +156,14 @@ class ChannelData final : public PeerData { void setName(const QString &name, const QString &username); void setUsername(const QString &username); void setUsernames(const Data::Usernames &newUsernames); + +#if 0 // #TODO legacy void setPhoto(const MTPChatPhoto &photo); +#endif void setAccessHash(uint64 accessHash); + void setPhoto(const Tdb::TLchatPhotoInfo &photo); + void setFlags(ChannelDataFlags which); void addFlags(ChannelDataFlags which); void removeFlags(ChannelDataFlags which); diff --git a/Telegram/SourceFiles/data/data_chat.cpp b/Telegram/SourceFiles/data/data_chat.cpp index 1e19a00d1b407..8f8558b3824fa 100644 --- a/Telegram/SourceFiles/data/data_chat.cpp +++ b/Telegram/SourceFiles/data/data_chat.cpp @@ -16,11 +16,13 @@ For license and copyright information please follow this link: #include "data/notify/data_notify_settings.h" #include "history/history.h" #include "main/main_session.h" +#include "tdb/tdb_tl_scheme.h" #include "apiwrap.h" #include "api/api_invite_links.h" namespace { +using namespace Tdb; using UpdateFlag = Data::PeerUpdate::Flag; } // namespace @@ -38,6 +40,7 @@ ChatData::ChatData(not_null owner, PeerId id) }, _lifetime); } +#if 0 // #TODO legacy void ChatData::setPhoto(const MTPChatPhoto &photo) { photo.match([&](const MTPDchatPhoto &data) { updateUserpic( @@ -48,6 +51,11 @@ void ChatData::setPhoto(const MTPChatPhoto &photo) { clearUserpic(); }); } +#endif + +void ChatData::setPhoto(const TLchatPhotoInfo &photo) { + updateUserpic(photo); +} ChatAdminRightsInfo ChatData::defaultAdminRights(not_null user) { const auto isCreator = (creator == peerToUser(user->id)) diff --git a/Telegram/SourceFiles/data/data_chat.h b/Telegram/SourceFiles/data/data_chat.h index 93202608a3156..0ec7e8352956c 100644 --- a/Telegram/SourceFiles/data/data_chat.h +++ b/Telegram/SourceFiles/data/data_chat.h @@ -35,7 +35,11 @@ class ChatData final : public PeerData { ChatData(not_null owner, PeerId id); void setName(const QString &newName); +#if 0 // #TODO legacy void setPhoto(const MTPChatPhoto &photo); +#endif + + void setPhoto(const Tdb::TLchatPhotoInfo &photo); void invalidateParticipants(); [[nodiscard]] bool noParticipantInfo() const { diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index caeb39aed0141..2405580b1713a 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -49,12 +49,14 @@ For license and copyright information please follow this link: #include "storage/file_download.h" #include "storage/storage_facade.h" #include "storage/storage_shared_media.h" +#include "tdb/tdb_tl_scheme.h" namespace { constexpr auto kUpdateFullPeerTimeout = crl::time(5000); // Not more than once in 5 seconds. constexpr auto kUserpicSize = 160; +using namespace Tdb; using UpdateFlag = Data::PeerUpdate::Flag; } // namespace @@ -452,6 +454,7 @@ Data::FileOrigin PeerData::userpicPhotoOrigin() const { : Data::FileOrigin(); } +#if 0 // #TODO legacy void PeerData::updateUserpic( PhotoId photoId, MTP::DcId dcId, @@ -470,6 +473,36 @@ void PeerData::updateUserpic( kUserpicSize), hasVideo); } +#endif + +void PeerData::updateUserpic(FileId fileId, PhotoId photoId) { + setUserpicChecked( + photoId, + ImageLocation( + { TdbFileLocation{ fileId } }, + kUserpicSize, + kUserpicSize)); +} + +void PeerData::updateUserpic(const TLchatPhotoInfo &photo) { + photo.match([&](const TLDchatPhotoInfo &data) { + updateUserpic(data.vsmall().match([&](const TLDfile &data) { + return data.vid().v; + })); // #TODO tdlib set data to view. + }); +} + +void PeerData::updateUserpic(const TLprofilePhoto &photo) { + photo.match([&](const TLDprofilePhoto &data) { + updateUserpic(data.vsmall().match([&](const TLDfile &data) { + return data.vid().v; + }), data.vid().v); // #TODO tdlib set data to view. + }); +} + +void PeerData::clearPhoto() { + clearUserpic(); +} void PeerData::clearUserpic() { setUserpicChecked(PhotoId(), ImageLocation(), false); diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index 894045fdd51f9..2487aae18f707 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -30,6 +30,11 @@ class Account; class Session; } // namespace Main +namespace Tdb { +class TLprofilePhoto; +class TLchatPhotoInfo; +} // namespace Tdb + namespace Data { class Forum; @@ -269,6 +274,7 @@ class PeerData { return _nameFirstLetters; } + void clearPhoto(); void setUserpic( PhotoId photoId, const ImageLocation &location, @@ -434,10 +440,16 @@ class PeerData { const QString &newName, const QString &newNameOrPhone, const QString &newUsername); +#if 0 // #TODO legacy void updateUserpic(PhotoId photoId, MTP::DcId dcId, bool hasVideo); +#endif void clearUserpic(); void invalidateEmptyUserpic(); + void updateUserpic(FileId fileId, PhotoId photoId = 0); + void updateUserpic(const Tdb::TLchatPhotoInfo &photo); + void updateUserpic(const Tdb::TLprofilePhoto &photo); + private: void fillNames(); [[nodiscard]] not_null ensureEmptyUserpic() const; diff --git a/Telegram/SourceFiles/data/data_peer_id.cpp b/Telegram/SourceFiles/data/data_peer_id.cpp index b6a77237b02ae..6aacd7b67c1aa 100644 --- a/Telegram/SourceFiles/data/data_peer_id.cpp +++ b/Telegram/SourceFiles/data/data_peer_id.cpp @@ -7,6 +7,44 @@ For license and copyright information please follow this link: */ #include "data/data_peer_id.h" +#include "tdb/details/tdb_tl_core.h" + +PeerId peerFromTdbChat(Tdb::TLint53 id) noexcept { + //constexpr int64 MIN_SECRET_ID = -2002147483648ll; // From TDLib. + //constexpr int64 ZERO_SECRET_ID = -2000000000000ll; + //constexpr int64 MAX_SECRET_ID = -1997852516353ll; + constexpr int64 MIN_CHANNEL_ID = -1002147483647ll; + constexpr int64 MAX_CHANNEL_ID = -1000000000000ll; + constexpr int64 MIN_CHAT_ID = -2147483647ll; + //constexpr int64 MAX_USER_ID = 2147483647ll; + if (id.v > 0) { + return UserId(BareId(id.v)); + } else if (id.v < 0 && id.v > MIN_CHAT_ID) { + return ChatId(BareId(-id.v)); + } else if (id.v < MAX_CHANNEL_ID && id.v > MIN_CHANNEL_ID) { + return ChannelId(BareId(MAX_CHANNEL_ID - id.v)); + } + return PeerId(); +} + +Tdb::TLint53 peerToTdbChat(PeerId id) noexcept { + //constexpr int64 MIN_SECRET_ID = -2002147483648ll; // From TDLib. + //constexpr int64 ZERO_SECRET_ID = -2000000000000ll; + //constexpr int64 MAX_SECRET_ID = -1997852516353ll; + //constexpr int64 MIN_CHANNEL_ID = -1002147483647ll; + constexpr int64 MAX_CHANNEL_ID = -1000000000000ll; + //constexpr int64 MIN_CHAT_ID = -2147483647ll; + //constexpr int64 MAX_USER_ID = 2147483647ll; + if (const auto userId = peerToUser(id)) { + return Tdb::tl_int53(int64(userId.bare)); + } else if (const auto chatId = peerToChat(id)) { + return Tdb::tl_int53(-int64(chatId.bare)); + } else if (const auto channelId = peerToChannel(id)) { + return Tdb::tl_int53(MAX_CHANNEL_ID - int64(channelId.bare)); + } + return Tdb::tl_int53(0); +} + PeerId peerFromMTP(const MTPPeer &peer) { return peer.match([](const MTPDpeerUser &data) { return peerFromUser(data.vuser_id()); diff --git a/Telegram/SourceFiles/data/data_peer_id.h b/Telegram/SourceFiles/data/data_peer_id.h index e4cf6cc55239d..9f1d8d8af3f26 100644 --- a/Telegram/SourceFiles/data/data_peer_id.h +++ b/Telegram/SourceFiles/data/data_peer_id.h @@ -9,6 +9,14 @@ For license and copyright information please follow this link: using BareId = uint64; +namespace tl { +class int64_type; +} // namespace tl + +namespace Tdb { +using TLint53 = tl::int64_type; +} // namespace Tdb + struct PeerIdZeroHelper { }; using PeerIdZero = void(PeerIdZeroHelper::*)(); @@ -215,6 +223,8 @@ bool operator>=(PeerIdZero, PeerId) = delete; return peerFromChannel(channelId.v); } +[[nodiscard]] PeerId peerFromTdbChat(Tdb::TLint53 id) noexcept; + [[nodiscard]] inline constexpr UserId peerToUser(PeerId id) noexcept { return id.to(); } @@ -227,6 +237,8 @@ bool operator>=(PeerIdZero, PeerId) = delete; return id.to(); } +[[nodiscard]] Tdb::TLint53 peerToTdbChat(PeerId id) noexcept; + [[nodiscard]] inline MTPlong peerToBareMTPInt(PeerId id) { return MTP_long(id.value & PeerId::kChatTypeMask); } diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index cc4b0007b563d..f977bc3e270d6 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -489,6 +489,7 @@ not_null Session::processUser(const MTPUser &data) { const auto result = user(data.match([](const auto &data) { return data.vid().v; })); +#if 0 // #TODO legacy auto minimal = false; const MTPUserStatus *status = nullptr; const MTPUserStatus emptyStatus = MTP_userStatusEmpty(); @@ -745,6 +746,8 @@ not_null Session::processUser(const MTPUser &data) { if (flags) { session().changes().peerUpdated(result, flags); } +#endif + return result; } @@ -761,7 +764,7 @@ not_null Session::processChat(const MTPChat &data) { return peer(peerFromChannel(data.vid().v)); }); auto minimal = false; - +#if 0 // #TODO legacy using UpdateFlag = Data::PeerUpdate::Flag; auto flags = UpdateFlag::None | UpdateFlag::None; data.match([&](const MTPDchat &data) { @@ -1057,6 +1060,7 @@ not_null Session::processChat(const MTPChat &data) { if (flags) { session().changes().peerUpdated(result, flags); } +#endif return result; } @@ -1109,7 +1113,11 @@ not_null Session::processUser(const TLuser &user) { : result->nameOrPhone; result->setName(firstName, lastName, phoneName, userName); - result->setPhoto(MTP_userProfilePhotoEmpty()); // #TODO tdlib + if (const auto photo = data.vprofile_photo()) { + result->setPhoto(*photo); + } else { + result->clearPhoto(); + } result->setUnavailableReasons({}); // #TODO tdlib //result->setFlags(MTPDuser_ClientFlag::f_inaccessible | 0); //result->setFlags(MTPDuser::Flag::f_deleted); @@ -1128,17 +1136,25 @@ not_null Session::processUser(const TLuser &user) { result->setLoadedStatus(PeerData::LoadedStatus::Full); } - //data.vstatus() // #TODO tdlib - //if (status && !minimal) { - // const auto oldOnlineTill = result->onlineTill; - // const auto newOnlineTill = ApiWrap::OnlineTillFromStatus( - // *status, - // oldOnlineTill); - // if (oldOnlineTill != newOnlineTill) { - // result->onlineTill = newOnlineTill; - // flags |= UpdateFlag::OnlineStatus; - // } - //} + const auto oldOnlineTill = result->onlineTill; + const auto newOnlineTill = data.vstatus().match([&]( + const TLDuserStatusEmpty &) { + return 0; + }, [&](const TLDuserStatusRecently &) { + return (oldOnlineTill > -10) ? -2 : oldOnlineTill; + }, [&](const TLDuserStatusLastWeek &) { + return -3; + }, [&](const TLDuserStatusLastMonth &) { + return -4; + }, [&](const TLDuserStatusOffline &data) { + return data.vwas_online().v; + }, [&](const TLDuserStatusOnline &data) { + return data.vexpires().v; + }); + if (oldOnlineTill != newOnlineTill) { + result->onlineTill = newOnlineTill; + flags |= UpdateFlag::OnlineStatus; + } if (flags) { session().changes().peerUpdated(result, flags); diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index f385b8c13fbca..4951d7135f186 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -23,6 +23,9 @@ For license and copyright information please follow this link: #include "api/api_peer_photo.h" #include "apiwrap.h" #include "ui/text/text_options.h" + +#include "tdb/tdb_tl_scheme.h" +#include "apiwrap.h" #include "lang/lang_keys.h" #include "styles/style_chat.h" @@ -31,6 +34,7 @@ namespace { // User with hidden last seen stays online in UI for such amount of seconds. constexpr auto kSetOnlineAfterActivity = TimeId(30); +using namespace Tdb; using UpdateFlag = Data::PeerUpdate::Flag; } // namespace @@ -57,6 +61,7 @@ void UserData::setIsContact(bool is) { } } +#if 0 // #TODO legacy // see Serialize::readPeer as well void UserData::setPhoto(const MTPUserProfilePhoto &photo) { photo.match([&](const MTPDuserProfilePhoto &data) { @@ -74,6 +79,11 @@ void UserData::setPhoto(const MTPUserProfilePhoto &photo) { clearUserpic(); }); } +#endif + +void UserData::setPhoto(const TLprofilePhoto &photo) { + updateUserpic(photo); +} void UserData::setEmojiStatus(const MTPEmojiStatus &status) { const auto parsed = Data::ParseEmojiStatus(status); diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index 96811051ee65d..a0900cd87037b 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -75,8 +75,13 @@ class UserData final : public PeerData { using Flags = Data::Flags; UserData(not_null owner, PeerId id); + +#if 0 // #TODO legacy void setPhoto(const MTPUserProfilePhoto &photo); void setEmojiStatus(const MTPEmojiStatus &status); +#endif + + void setPhoto(const Tdb::TLprofilePhoto &photo); void setName( const QString &newFirstName, diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index e5c03f37dc890..331395a173935 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -988,6 +988,7 @@ void History::applyMessageChanges( void History::applyServiceChanges( not_null item, const MTPDmessageService &data) { +#if 0 // #TODO legacy const auto replyTo = data.vreply_to(); const auto processJoinedUser = [&]( not_null megagroup, @@ -1222,6 +1223,7 @@ void History::applyServiceChanges( } }, [](const auto &) { }); +#endif } void History::mainViewRemoved( diff --git a/Telegram/SourceFiles/intro/intro_widget.cpp b/Telegram/SourceFiles/intro/intro_widget.cpp index e1ea0ab26d1c8..f1216685f1aa8 100644 --- a/Telegram/SourceFiles/intro/intro_widget.cpp +++ b/Telegram/SourceFiles/intro/intro_widget.cpp @@ -117,19 +117,16 @@ Widget::Widget( default: Unexpected("Enter point in Intro::Widget::Widget."); } #endif - switch (point) { - case EnterPoint::Start: - getNearestDC(); - go(StepType::Start); - break; - case EnterPoint::Phone: - go(StepType::Phone); - break; - case EnterPoint::Qr: - go(StepType::Qr); - break; - default: Unexpected("Enter point in Intro::Widget::Widget."); - } + const auto stepType = [&] { + switch (point) { + case EnterPoint::Start: getNearestDC(); return StepType::Start; + case EnterPoint::Phone: return StepType::Phone; + case EnterPoint::Qr: return StepType::Qr; + default: Unexpected("Enter point in Intro::Widget::Widget."); + } + }(); + const auto went = go(stepType); + Assert(went); fixOrder(); @@ -512,15 +509,15 @@ std::unique_ptr Widget::makeStep() { return std::make_unique(this, _account, getData()); } -void Widget::go(StepType type) { +bool Widget::go(StepType type) { if (type == StepType::Start) { if (const auto parent = Core::App().domain().maybeLastOrSomeAuthedAccount()) { Core::App().domain().activate(parent); + return false; } - return; } else if (!_stepHistory.empty() && getStep()->type() == type) { - return; + return false; } const auto wasStep = _stepHistory.empty() ? nullptr : getStep().get(); auto nowStep = begin(_stepHistory); @@ -554,6 +551,7 @@ void Widget::go(StepType type) { nowStep = (_stepHistory.end() - 1); } historyMove(wasStep, nowStep); + return true; } #if 0 // mtp diff --git a/Telegram/SourceFiles/intro/intro_widget.h b/Telegram/SourceFiles/intro/intro_widget.h index 2370d37478111..d9a007d1edfc7 100644 --- a/Telegram/SourceFiles/intro/intro_widget.h +++ b/Telegram/SourceFiles/intro/intro_widget.h @@ -167,7 +167,7 @@ class Widget details::Step *wasStep, std::vector>::iterator nowStep); void appendStep(std::unique_ptr step); - void go(details::StepType type); + bool go(details::StepType type); template [[nodiscard]] std::unique_ptr makeStep(); diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index f3cd9027373d3..96786f92d770b 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -228,6 +228,14 @@ Storage::Domain &Session::domainLocal() const { return _account->domainLocal(); } +Tdb::Account &Session::tdb() const { + return _account->tdb(); +} + +Tdb::Sender &Session::sender() const { + return _account->sender(); +} + void Session::notifyDownloaderTaskFinished() { downloader().notifyTaskFinished(); } diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h index a4f0f8346721b..ee2c112b616cd 100644 --- a/Telegram/SourceFiles/main/main_session.h +++ b/Telegram/SourceFiles/main/main_session.h @@ -16,6 +16,8 @@ class ApiWrap; namespace Tdb { class TLuser; +class Account; +class Sender; } // namespace Tdb namespace Api { @@ -94,6 +96,9 @@ class Session final : public base::has_weak_ptr { [[nodiscard]] Domain &domain() const; [[nodiscard]] Storage::Domain &domainLocal() const; + [[nodiscard]] Tdb::Account &tdb() const; + [[nodiscard]] Tdb::Sender &sender() const; + [[nodiscard]] bool premium() const; [[nodiscard]] bool premiumPossible() const; [[nodiscard]] rpl::producer premiumPossibleValue() const; diff --git a/Telegram/SourceFiles/storage/file_download.cpp b/Telegram/SourceFiles/storage/file_download.cpp index 3cd422269d80d..3a2d9956633dc 100644 --- a/Telegram/SourceFiles/storage/file_download.cpp +++ b/Telegram/SourceFiles/storage/file_download.cpp @@ -546,6 +546,19 @@ std::unique_ptr CreateFileLoader( LoadFromCloudOrLocal, autoLoading, cacheTag); + }, [&](const TdbFileLocation &data) { + // #TODO tdlib + result = std::make_unique( + session, + QByteArray(), + toFile, + loadSize, + fullSize, + locationType, + toCache, + LoadFromCloudOrLocal, + autoLoading, + cacheTag); }); Ensures(result != nullptr); diff --git a/Telegram/SourceFiles/tdb/details/tdb_instance.cpp b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp index f1c6506fb2efd..2787ef083c3bd 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_instance.cpp +++ b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp @@ -63,7 +63,7 @@ class Instance::Manager final QMutex _mutex; base::flat_map _callbacks; - std::atomic _requestIdCounter = 0; + std::atomic _requestIdCounter = 0; std::atomic _closingId = 0; crl::semaphore _closing; diff --git a/Telegram/SourceFiles/ui/image/image_location.cpp b/Telegram/SourceFiles/ui/image/image_location.cpp index d1fdde5b64c44..549b6bebdacd2 100644 --- a/Telegram/SourceFiles/ui/image/image_location.cpp +++ b/Telegram/SourceFiles/ui/image/image_location.cpp @@ -35,6 +35,7 @@ enum class NonStorageLocationType : quint8 { Url, Memory, AudioAlbumThumb, + Tdb, }; MTPInputPeer GenerateInputPeer( @@ -716,6 +717,13 @@ InMemoryKey inMemoryKey(const AudioAlbumThumbLocation &location) { return { key.high, key.low }; } +InMemoryKey inMemoryKey(const TdbFileLocation &location) { + return { + 0xFF00000000000000ULL, + 0xFF00000000000000ULL | uint32(location.fileId) + }; +} + InMemoryKey inMemoryKey(const InMemoryLocation &location) { auto result = InMemoryKey(); const auto &data = location.bytes; @@ -822,6 +830,8 @@ QByteArray DownloadLocation::serialize() const { stream << quint8(NonStorageLocationType::Url) << data.url.toUtf8(); }, [&](const InMemoryLocation &data) { stream << quint8(NonStorageLocationType::Memory) << data.bytes; + }, [&](const TdbFileLocation &data) { + stream << quint8(NonStorageLocationType::Tdb) << qint32(data.fileId); }); buffer.close(); return result; @@ -844,6 +854,8 @@ int DownloadLocation::serializeSize() const { result += sizeof(quint64); }, [&](const InMemoryLocation &data) { result += Serialize::bytearraySize(data.bytes); + }, [&](const TdbFileLocation &data) { + result += sizeof(qint32); }); return result; } @@ -922,6 +934,15 @@ std::optional DownloadLocation::FromSerialized( DownloadLocation{ InMemoryLocation{ bytes } }) : std::nullopt; } break; + + case NonStorageLocationType::Tdb: { + qint32 fileId = 0; + stream >> fileId; + return (stream.status() == QDataStream::Ok) + ? std::make_optional( + DownloadLocation{ TdbFileLocation{ fileId } }) + : std::nullopt; + } break; } return std::nullopt; } @@ -958,13 +979,15 @@ Storage::Cache::Key DownloadLocation::cacheKey() const { return Data::AudioAlbumThumbCacheKey(data); }, [](const InMemoryLocation &data) { return Storage::Cache::Key(); + }, [](const TdbFileLocation &data) { + return Storage::Cache::Key(); // #TODO tdlib }); } Storage::Cache::Key DownloadLocation::bigFileBaseCacheKey() const { return v::is(data) ? v::get(data).bigFileBaseCacheKey() - : Storage::Cache::Key(); + : Storage::Cache::Key(); // #TODO tdlib?.. streaming } bool DownloadLocation::valid() const { @@ -980,6 +1003,8 @@ bool DownloadLocation::valid() const { return data.documentId != 0; }, [](const InMemoryLocation &data) { return !data.bytes.isEmpty(); + }, [](const TdbFileLocation &data) { + return (data.fileId != 0); }); } diff --git a/Telegram/SourceFiles/ui/image/image_location.h b/Telegram/SourceFiles/ui/image/image_location.h index 98bb7024ea2a7..bf11d990a2c19 100644 --- a/Telegram/SourceFiles/ui/image/image_location.h +++ b/Telegram/SourceFiles/ui/image/image_location.h @@ -32,6 +32,7 @@ enum LoadToCacheSetting { }; using InMemoryKey = std::pair; +using FileId = int32; namespace std { @@ -455,9 +456,50 @@ inline bool operator>=( return !(a < b); } +struct TdbFileLocation { + FileId fileId = 0; +}; + +inline bool operator==( + const TdbFileLocation &a, + const TdbFileLocation &b) { + return (a.fileId == b.fileId); +} + +inline bool operator<( + const TdbFileLocation &a, + const TdbFileLocation &b) { + return (a.fileId < b.fileId); +} + +inline bool operator!=( + const TdbFileLocation &a, + const TdbFileLocation &b) { + return !(a == b); +} + +inline bool operator>( + const TdbFileLocation &a, + const TdbFileLocation &b) { + return (b < a); +} + +inline bool operator<=( + const TdbFileLocation &a, + const TdbFileLocation &b) { + return !(b < a); +} + +inline bool operator>=( + const TdbFileLocation &a, + const TdbFileLocation &b) { + return !(a < b); +} + class DownloadLocation { public: std::variant< + TdbFileLocation, StorageFileLocation, WebFileLocation, GeoPointLocation, From c7aac7ae3384fc2c4f9b8f0d7081feb2305b1ba0 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 16 Jun 2021 19:31:40 +0400 Subject: [PATCH 011/350] Request dialogs, users, chats and channels. --- Telegram/SourceFiles/apiwrap.cpp | 75 ++++- Telegram/SourceFiles/apiwrap.h | 12 +- Telegram/SourceFiles/data/data_chat.h | 4 + Telegram/SourceFiles/data/data_session.cpp | 309 +++++++++++++++++- Telegram/SourceFiles/data/data_session.h | 9 + Telegram/SourceFiles/tdb/tdb_account.cpp | 3 + Telegram/SourceFiles/tdb/tdb_account.h | 5 + .../SourceFiles/tdb/tdb_resolve_chats.cpp | 165 ++++++++++ Telegram/SourceFiles/tdb/tdb_resolve_chats.h | 100 ++++++ Telegram/cmake/td_tdb.cmake | 2 + 10 files changed, 656 insertions(+), 28 deletions(-) create mode 100644 Telegram/SourceFiles/tdb/tdb_resolve_chats.cpp create mode 100644 Telegram/SourceFiles/tdb/tdb_resolve_chats.h diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 51c2883cac1e7..4162fb4d57dfb 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -101,6 +101,7 @@ For license and copyright information please follow this link: #include "storage/storage_account.h" #include "tdb/tdb_sender.h" +#include "tdb/tdb_account.h" namespace { @@ -152,6 +153,20 @@ void ShowChannelsLimitBox(not_null peer) { } // namespace +struct ApiWrap::DialogsLoadState { + TimeId offsetDate = 0; + MsgId offsetId = 0; + PeerData *offsetPeer = nullptr; + RequestId requestId = 0; + bool listReceived = false; + + RequestId pinnedRequestId = 0; + bool pinnedReceived = false; + + ResolveChatsRequest request; + int64 offsetChatId = 0; +}; + ApiWrap::ApiWrap(not_null session) : MTP::Sender(&session->account().mtp()) , _session(session) @@ -849,17 +864,17 @@ void ApiWrap::requestDialogs(Data::Folder *folder) { void ApiWrap::requestMoreDialogs(Data::Folder *folder) { const auto state = dialogsLoadState(folder); - if (!state) { + if (!state || !tdb().ready()) { return; - } else if (state->requestId) { + } else if (state->requestId || state->request) { return; } else if (_dialogsLoadBlockedByDate.current()) { return; } +#if 0 // #TODO legacy const auto firstLoad = !state->offsetDate; const auto loadCount = firstLoad ? kDialogsFirstLoad : kDialogsPerPage; -#if 0 // #TODO legacy const auto flags = MTPmessages_GetDialogs::Flag::f_exclude_pinned | MTPmessages_GetDialogs::Flag::f_folder_id; const auto hash = uint64(0); @@ -913,24 +928,50 @@ void ApiWrap::requestMoreDialogs(Data::Folder *folder) { }).fail([=] { dialogsLoadState(folder)->requestId = 0; }).send(); + + if (!state->pinnedReceived) { + requestPinnedDialogs(folder); + } #endif - state->requestId = sender().request(TLgetChats( + const auto firstLoad = !state->offsetChatId; + const auto loadCount = firstLoad ? kDialogsFirstLoad : kDialogsPerPage; + state->request.send(sender(), TLgetChats( folder ? tl_chatListArchive() : tl_chatListMain(), tl_int32(loadCount) - )).done([=](const TLchats &result) { - result.match([&](const TLDchats &data) { - for (const auto &chatId : data.vchat_ids().v) { - const auto peerId = peerFromTdbChat(chatId); - } - }); - }).fail([=](const Error &error) { - dialogsLoadState(folder)->requestId = 0; - }).send(); + ), [=] { + return &dialogsLoadState(folder)->request; + }, [=](const ResolvedChats &result) { + const auto state = dialogsLoadState(folder); + if (!state) { + return; + } + const auto count = result.count; + if (result.ids.isEmpty()) { + state->listReceived = true; + state->pinnedReceived = true; + dialogsLoadFinish(folder); // may kill 'state'. + } else { + state->offsetChatId = result.ids.back().v; + } + _session->data().processUsers(result.users); + _session->data().processChats(result.chats); + _session->data().processChannels(result.channels); + _session->data().processPeers(result.dialogs); + //_session->data().applyDialogs( + // folder, + // data.vmessages().v, + // data.vdialogs().v, + // count); + + if (!folder + && (!_dialogsLoadState || !_dialogsLoadState->listReceived)) { + refreshDialogsLoadBlocked(); + } + requestMoreDialogsIfNeeded(); + _session->data().chatsListChanged(folder); + }); - if (!state->pinnedReceived) { - requestPinnedDialogs(folder); - } if (!folder) { refreshDialogsLoadBlocked(); } @@ -971,6 +1012,7 @@ void ApiWrap::updateDialogsOffset( Data::Folder *folder, const QVector &dialogs, const QVector &messages) { +#if 0 // #TODO legacy auto lastDate = TimeId(0); auto lastPeer = PeerId(0); auto lastMsgId = MsgId(0); @@ -1012,6 +1054,7 @@ void ApiWrap::updateDialogsOffset( dialogsLoadFinish(folder); } } +#endif } auto ApiWrap::dialogsLoadState(Data::Folder *folder) -> DialogsLoadState* { diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 50cc83f6562a2..4eb4856646fe3 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -15,6 +15,7 @@ For license and copyright information please follow this link: #include "data/stickers/data_stickers_set.h" #include "data/data_messages.h" #include "tdb/tdb_sender.h" +#include "tdb/tdb_resolve_chats.h" class TaskQueue; struct MessageGroupId; @@ -424,16 +425,7 @@ class ApiWrap final : public MTP::Sender { crl::time received = 0; }; - struct DialogsLoadState { - TimeId offsetDate = 0; - MsgId offsetId = 0; - PeerData *offsetPeer = nullptr; - mtpRequestId requestId = 0; - bool listReceived = false; - - mtpRequestId pinnedRequestId = 0; - bool pinnedReceived = false; - }; + struct DialogsLoadState; void setupSupportMode(); void refreshDialogsLoadBlocked(); diff --git a/Telegram/SourceFiles/data/data_chat.h b/Telegram/SourceFiles/data/data_chat.h index 0ec7e8352956c..5272a229ad4c2 100644 --- a/Telegram/SourceFiles/data/data_chat.h +++ b/Telegram/SourceFiles/data/data_chat.h @@ -176,7 +176,11 @@ class ChatData final : public PeerData { const MTPlong inputChat; int count = 0; + +#if 1 // #TODO legacy? TimeId date = 0; +#endif + UserId creator = 0; base::flat_set> participants; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index f977bc3e270d6..79676d21121a3 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -131,6 +131,28 @@ void CheckForSwitchInlineButton(not_null item) { } } +[[nodiscard]] ChatRestrictions RestrictionsFromPermissions( + const TLchatPermissions & permissions) { + return permissions.match([&](const TLDchatPermissions &data) { + using Flag = ChatRestriction; + const auto bit = [&](const TLbool &check, Flag value) { + return tl_is_true(check) ? value : Flag(0); + }; + return Flag(0) + | bit(data.vcan_add_web_page_previews(), Flag::f_embed_links) + | bit(data.vcan_change_info(), Flag::f_change_info) + | bit(data.vcan_invite_users(), Flag::f_invite_users) + | bit(data.vcan_pin_messages(), Flag::f_pin_messages) + | bit(data.vcan_send_media_messages(), Flag::f_send_media) + | bit(data.vcan_send_messages(), Flag::f_send_messages) + | bit(data.vcan_send_polls(), Flag::f_send_polls) + | bit(data.vcan_send_other_messages(), Flag::f_send_stickers) + | bit(data.vcan_send_other_messages(), Flag::f_send_games) + | bit(data.vcan_send_other_messages(), Flag::f_send_gifs) + | bit(data.vcan_send_other_messages(), Flag::f_send_inline); + }); +} + // We should get a full restriction in "{full}: {reason}" format and we // need to find an "-all" tag in {full}, otherwise ignore this restriction. std::vector ExtractUnavailableReasons( @@ -1065,8 +1087,7 @@ not_null Session::processChat(const MTPChat &data) { } not_null Session::processUser(const TLuser &user) { - const auto &data = user.match([]( - const auto &data) -> const TLDuser& { + const auto &data = user.match([](const auto &data) -> const TLDuser& { return data; }); const auto result = this->user(data.vid().v); @@ -1162,6 +1183,257 @@ not_null Session::processUser(const TLuser &user) { return result; } +not_null Session::processPeer(const TLchat &dialog) { + const auto &data = dialog.match([](const auto &data) -> const TLDchat & { + return data; + }); + Assert(data.vtype().type() != id_chatTypeSecret); + const auto result = this->peer(peerFromTdbChat(data.vid())); + using UpdateFlag = Data::PeerUpdate::Flag; + auto updates = UpdateFlag::None | UpdateFlag::None; + if (const auto user = result->asUser()) { + } else if (const auto chat = result->asChat()) { + const auto canAddMembers = chat->canAddMembers(); + + chat->setName(data.vtitle().v); + if (const auto photo = data.vphoto()) { + chat->setPhoto(*photo); + } else { + chat->clearPhoto(); + } + const auto flags = RestrictionsFromPermissions(data.vpermissions()); + chat->setDefaultRestrictions(MTP_chatBannedRights( + MTP_flags(flags), + MTP_int(flags ? ChannelData::kRestrictUntilForever : 0))); + data.vvoice_chat().match([&](const TLDvoiceChat &data) { + const auto callFlag = MTPDchat::Flag::f_call_not_empty; + const auto callNotEmpty = tl_is_true(data.vhas_participants()); + chat->setFlags(chat->flags() // #TODO tdlib + | (callNotEmpty ? callFlag : MTPDchat::Flag(0))); + }); + + if (canAddMembers != chat->canAddMembers()) { + updates |= UpdateFlag::Rights; + } + } else if (const auto channel = result->asChannel()) { + const auto wasInChannel = channel->amIn(); + const auto canViewAdmins = channel->canViewAdmins(); + const auto canViewMembers = channel->canViewMembers(); + const auto canAddMembers = channel->canAddMembers(); + + data.vpermissions().match([&](const TLDchatPermissions &data) { + using Flag = ChatRestriction; + const auto bit = [&](const TLbool &check, Flag value) { + return tl_is_true(check) ? value : Flag(0); + }; + const auto flags = Flag(0) + | bit(data.vcan_add_web_page_previews(), Flag::f_embed_links) + | bit(data.vcan_change_info(), Flag::f_change_info) + | bit(data.vcan_invite_users(), Flag::f_invite_users) + | bit(data.vcan_pin_messages(), Flag::f_pin_messages) + | bit(data.vcan_send_media_messages(), Flag::f_send_media) + | bit(data.vcan_send_messages(), Flag::f_send_messages) + | bit(data.vcan_send_polls(), Flag::f_send_polls) + | bit(data.vcan_send_other_messages(), Flag::f_send_stickers) + | bit(data.vcan_send_other_messages(), Flag::f_send_games) + | bit(data.vcan_send_other_messages(), Flag::f_send_gifs) + | bit(data.vcan_send_other_messages(), Flag::f_send_inline); + channel->setDefaultRestrictions(MTP_chatBannedRights( + MTP_flags(flags), + MTP_int(flags ? ChannelData::kRestrictUntilForever : 0))); + }); + channel->setName(data.vtitle().v, channel->username); + + if (const auto photo = data.vphoto()) { + channel->setPhoto(*photo); + } else { + channel->clearPhoto(); + } + + if (wasInChannel != channel->amIn()) { + updates |= UpdateFlag::ChannelAmIn; + } + if (canViewAdmins != channel->canViewAdmins() + || canViewMembers != channel->canViewMembers() + || canAddMembers != channel->canAddMembers()) { + updates |= UpdateFlag::Rights; + } + } + if (!result->isFullLoaded()) { + result->setLoadedStatus(PeerData::LoadedStatus::Full); + } + if (updates) { + session().changes().peerUpdated(result, updates); + } + return result; +} + +not_null Session::processChat(const TLbasicGroup &chat) { + const auto &data = chat.match([]( + const auto &data) -> const TLDbasicGroup & { + return data; + }); + const auto result = this->chat(data.vid().v); + using Flag = MTPDchat::Flag; + const auto setting = Flag::f_deactivated + | Flag::f_left + | Flag::f_kicked; + auto flags = (result->flags() & ~setting) + | (!tl_is_true(data.vis_active()) ? Flag::f_deactivated : Flag()); + result->count = data.vmember_count().v; + if (const auto migratedTo = data.vupgraded_to_supergroup_id().v) { + const auto channel = this->channel(migratedTo); + channel->addFlags(MTPDchannel::Flag::f_megagroup); + ApplyMigration(result, channel); + } + data.vstatus().match([&](const TLDchatMemberStatusCreator &data) { + if (!tl_is_true(data.vis_member())) { + flags |= Flag::f_left; + } + result->creator = session().userId(); + result->setAdminRights(MTP_chatAdminRights(MTP_flags( + (tl_is_true(data.vis_anonymous()) + ? ChatAdminRight::f_anonymous + : ChatAdminRight())))); + //data.vcustom_title().v; // #TODO tdlib + }, [&](const TLDchatMemberStatusAdministrator &data) { + using Flag = ChatAdminRight; + const auto bit = [&](const TLbool &check, Flag value) { + return tl_is_true(check) ? value : Flag(0); + }; + result->setAdminRights(MTP_chatAdminRights(MTP_flags(Flag(0) + | bit(data.vcan_manage_chat(), Flag::f_other) + | bit(data.vcan_change_info(), Flag::f_change_info) + | bit(data.vcan_delete_messages(), Flag::f_delete_messages) + | bit(data.vcan_edit_messages(), Flag::f_edit_messages) + | bit(data.vcan_invite_users(), Flag::f_invite_users) + | bit(data.vcan_manage_voice_chats(), Flag::f_manage_call) + | bit(data.vcan_pin_messages(), Flag::f_pin_messages) + | bit(data.vcan_post_messages(), Flag::f_post_messages) + | bit(data.vcan_promote_members(), Flag::f_add_admins) + | bit(data.vcan_restrict_members(), Flag::f_ban_users) + | bit(data.vis_anonymous(), Flag::f_anonymous)))); + //data.vcustom_title().v; // #TODO tdlib + }, [&](const TLDchatMemberStatusMember &data) { + result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + }, [&](const TLDchatMemberStatusRestricted &data) { + LOG(("Tdb Error: Should not get restrictions in basic groups.")); + result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + if (!tl_is_true(data.vis_member())) { + flags |= Flag::f_left; + } + }, [&](const TLDchatMemberStatusLeft &data) { + result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + flags |= Flag::f_left; + }, [&](const TLDchatMemberStatusBanned &data) { + result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + flags |= Flag::f_kicked; + }); + result->setFlags(flags); + return result; +} + +not_null Session::processChannel( + const TLsupergroup &channel) { + const auto &data = channel.match([]( + const auto &data) -> const TLDsupergroup & { + return data; + }); + const auto result = this->channel(data.vid().v); + using Flag = MTPDchannel::Flag; + result->date = data.vdate().v; + const auto setting = Flag::f_megagroup + | Flag::f_gigagroup + | Flag::f_scam + | Flag::f_fake + | Flag::f_left + | Flag::f_signatures + | Flag::f_slowmode_enabled + | Flag::f_verified + | Flag::f_has_geo + | Flag::f_has_link + | Flag::f_creator; + auto flags = (result->flags() & ~setting) + | (!tl_is_true(data.vis_channel()) ? Flag::f_megagroup : Flag()) + | (tl_is_true(data.vis_broadcast_group()) + ? Flag::f_gigagroup + : Flag()) + | (tl_is_true(data.vis_fake()) ? Flag::f_fake : Flag()) + | (tl_is_true(data.vis_scam()) ? Flag::f_scam : Flag()) + | (tl_is_true(data.vis_verified()) ? Flag::f_verified : Flag()) + | (tl_is_true(data.vis_slow_mode_enabled()) + ? Flag::f_slowmode_enabled + : Flag()) + | (tl_is_true(data.vsign_messages()) ? Flag::f_signatures : Flag()) + | (tl_is_true(data.vhas_linked_chat()) ? Flag::f_has_link : Flag()) + | (tl_is_true(data.vhas_location()) ? Flag::f_has_geo : Flag()) + | ((data.vstatus().type() == id_chatMemberStatusCreator) + ? Flag::f_creator + : Flag()); + result->setMembersCount(data.vmember_count().v); + result->setName(result->name, data.vusername().v); + //data.vrestriction_reason(); // #TODO tdlib + data.vstatus().match([&](const TLDchatMemberStatusCreator &data) { + if (!tl_is_true(data.vis_member())) { + flags |= Flag::f_left; + } + result->setAdminRights(MTP_chatAdminRights(MTP_flags( + (tl_is_true(data.vis_anonymous()) + ? ChatAdminRight::f_anonymous + : ChatAdminRight())))); + result->setRestrictions( + MTP_chatBannedRights(MTP_flags(0), MTP_int(0))); + //data.vcustom_title().v; // #TODO tdlib + }, [&](const TLDchatMemberStatusAdministrator &data) { + using Flag = ChatAdminRight; + const auto bit = [&](const TLbool &check, Flag value) { + return tl_is_true(check) ? value : Flag(0); + }; + result->setAdminRights(MTP_chatAdminRights(MTP_flags(Flag(0) + | bit(data.vcan_manage_chat(), Flag::f_other) + | bit(data.vcan_change_info(), Flag::f_change_info) + | bit(data.vcan_delete_messages(), Flag::f_delete_messages) + | bit(data.vcan_edit_messages(), Flag::f_edit_messages) + | bit(data.vcan_invite_users(), Flag::f_invite_users) + | bit(data.vcan_manage_voice_chats(), Flag::f_manage_call) + | bit(data.vcan_pin_messages(), Flag::f_pin_messages) + | bit(data.vcan_post_messages(), Flag::f_post_messages) + | bit(data.vcan_promote_members(), Flag::f_add_admins) + | bit(data.vcan_restrict_members(), Flag::f_ban_users) + | bit(data.vis_anonymous(), Flag::f_anonymous)))); + result->setRestrictions( + MTP_chatBannedRights(MTP_flags(0), MTP_int(0))); + //data.vcustom_title().v; // #TODO tdlib + }, [&](const TLDchatMemberStatusMember &data) { + result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + result->setRestrictions( + MTP_chatBannedRights(MTP_flags(0), MTP_int(0))); + }, [&](const TLDchatMemberStatusRestricted &data) { + result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + result->setRestrictions(MTP_chatBannedRights( + MTP_flags(RestrictionsFromPermissions(data.vpermissions())), + MTP_int(data.vrestricted_until_date().v))); + if (!tl_is_true(data.vis_member())) { + flags |= Flag::f_left; + } + }, [&](const TLDchatMemberStatusLeft &data) { + result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + result->setRestrictions( + MTP_chatBannedRights(MTP_flags(0), MTP_int(0))); + flags |= Flag::f_left; + }, [&](const TLDchatMemberStatusBanned &data) { + result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + const auto flags = ChannelData::KickedRestrictedRights( + session().user() + ).c_chatBannedRights().vflags(); + result->setRestrictions(MTP_chatBannedRights( + flags, + MTP_int(data.vbanned_until_date().v))); + }); + result->setFlags(flags); + return result; +} + UserData *Session::processUsers(const MTPVector &data) { auto result = (UserData*)nullptr; for (const auto &user : data.v) { @@ -1178,6 +1450,39 @@ PeerData *Session::processChats(const MTPVector &data) { return result; } +PeerData *Session::processPeers(const std::vector &data) { + auto result = (PeerData*)nullptr; + for (const auto &dialog : data) { + result = processPeer(dialog); + } + return result; +} + +UserData *Session::processUsers(const std::vector &data) { + auto result = (UserData*)nullptr; + for (const auto &user : data) { + result = processUser(user); + } + return result; +} + +ChatData *Session::processChats(const std::vector &data) { + auto result = (ChatData*)nullptr; + for (const auto &chat : data) { + result = processChat(chat); + } + return result; +} + +ChannelData *Session::processChannels( + const std::vector &data) { + auto result = (ChannelData*)nullptr; + for (const auto &channel : data) { + result = processChannel(channel); + } + return result; +} + void Session::applyMaximumChatVersions(const MTPVector &data) { for (const auto &chat : data.v) { chat.match([&](const MTPDchat &data) { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index bc54330fdfae6..53553ee95ea95 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -186,12 +186,21 @@ class Session final { not_null processUser(const MTPUser &data); not_null processChat(const MTPChat &data); + not_null processPeer(const Tdb::TLchat &dialog); not_null processUser(const Tdb::TLuser &user); + not_null processChat(const Tdb::TLbasicGroup &chat); + not_null processChannel(const Tdb::TLsupergroup &channel); // Returns last user, if there were any. UserData *processUsers(const MTPVector &data); PeerData *processChats(const MTPVector &data); + // Returns last user, if there were any. + PeerData *processPeers(const std::vector &data); + UserData *processUsers(const std::vector &data); + ChatData *processChats(const std::vector &data); + ChannelData *processChannels(const std::vector &data); + void applyMaximumChatVersions(const MTPVector &data); void registerGroupCall(not_null call); diff --git a/Telegram/SourceFiles/tdb/tdb_account.cpp b/Telegram/SourceFiles/tdb/tdb_account.cpp index 4e763e3c1bafc..1ea65b1096a2b 100644 --- a/Telegram/SourceFiles/tdb/tdb_account.cpp +++ b/Telegram/SourceFiles/tdb/tdb_account.cpp @@ -32,6 +32,9 @@ bool Account::consumeUpdate(const TLupdate &update) { TLcheckDatabaseEncryptionKey(tl_bytes()) ).send(); return true; + }, [&](const TLDauthorizationStateReady &) { + _ready = true; + return false; }, [&](const auto &) { return false; }); diff --git a/Telegram/SourceFiles/tdb/tdb_account.h b/Telegram/SourceFiles/tdb/tdb_account.h index 0a2bdc5b65c82..034b1ce361d5b 100644 --- a/Telegram/SourceFiles/tdb/tdb_account.h +++ b/Telegram/SourceFiles/tdb/tdb_account.h @@ -24,6 +24,10 @@ class Account final { [[nodiscard]] rpl::producer updates() const; + [[nodiscard]] bool ready() const { + return _ready; + } + [[nodiscard]] rpl::lifetime &lifetime() { return _lifetime; } @@ -34,6 +38,7 @@ class Account final { details::Instance _instance; Sender _sender; rpl::event_stream _updates; + bool _ready = false; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/tdb/tdb_resolve_chats.cpp b/Telegram/SourceFiles/tdb/tdb_resolve_chats.cpp new file mode 100644 index 0000000000000..7bf9cb99b7ea1 --- /dev/null +++ b/Telegram/SourceFiles/tdb/tdb_resolve_chats.cpp @@ -0,0 +1,165 @@ +/* +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 "tdb/tdb_resolve_chats.h" + +namespace Tdb { +namespace { + +constexpr auto kUserShift = 0x0100000000000000ULL; +constexpr auto kChatShift = 0x0200000000000000ULL; +constexpr auto kChannelShift = 0x0400000000000000ULL; + +[[nodiscard]] uint64 PeerFromChatId(TLint53 id) noexcept { + //constexpr int64 MIN_SECRET_ID = -2002147483648ll; // From TDLib. + //constexpr int64 ZERO_SECRET_ID = -2000000000000ll; + //constexpr int64 MAX_SECRET_ID = -1997852516353ll; + constexpr int64 MIN_CHANNEL_ID = -1002147483647ll; + constexpr int64 MAX_CHANNEL_ID = -1000000000000ll; + constexpr int64 MIN_CHAT_ID = -2147483647ll; + //constexpr int64 MAX_USER_ID = 2147483647ll; + if (id.v > 0) { + return kUserShift | uint64(id.v); + } else if (id.v < 0 && id.v > MIN_CHAT_ID) { + return kChatShift | uint64(-id.v); + } else if (id.v < MAX_CHANNEL_ID && id.v > MIN_CHANNEL_ID) { + return kChannelShift | uint64(MAX_CHANNEL_ID - id.v); + } + return 0; +} + +[[nodiscard]] uint64 PeerToUser(uint64 peer) { + return (peer & kUserShift) ? (peer & ~kUserShift) : 0; +} + +[[nodiscard]] uint64 PeerToChat(uint64 peer) { + return (peer & kChatShift) ? (peer & ~kChatShift) : 0; +} + +[[nodiscard]] uint64 PeerToChannel(uint64 peer) { + return (peer & kChannelShift) ? (peer & ~kChannelShift) : 0; +} + +} // namespace + +ResolveChatsRequest::~ResolveChatsRequest() { + cancel(); +} + +void ResolveChatsRequest::cancel() { + if (!_data) { + return; + } + const auto data = base::take(_data); + for (const auto id : data->requests) { + data->sender.request(id).cancel(); + } +} + +void ResolveChatsRequest::listFail(const Error &error) { + const auto data = base::take(_data); + if (data->fail) { + data->fail(error); + } +} + +void ResolveChatsRequest::listDone(const TLchats &chats) { + Expects(_data != nullptr); + + chats.match([&](const TLDchats &data) { + const auto &ids = data.vchat_ids().v; + _data->result.count = data.vtotal_count().v; + _data->result.ids = data.vchat_ids().v; + for (const auto &chatId : ids) { + requestChat(chatId); + } + }); +} + +void ResolveChatsRequest::requestChat(TLint53 chatId) { + const auto peer = PeerFromChatId(chatId); + if (!peer) { + return; + } + _data->requests.emplace(_data->sender.request(TLgetChat( + chatId + )).done([self = _data->self](const TLchat &result, RequestId requestId) { + if (const auto that = self()) { + that->_data->result.dialogs.push_back(result); + that->requestFinished(requestId); + } + }).fail([self = _data->self](const Error &error, RequestId requestId) { + if (const auto that = self()) { + that->requestFinished(requestId); + } + }).send()); + + requestPeer(peer); +} + +void ResolveChatsRequest::requestPeer(uint64 peer) { + if (!_data->requestedPeers.emplace(peer).second) { + return; + } + + if (const auto user = PeerToUser(peer)) { + _data->requests.emplace(_data->sender.request(TLgetUser( + tl_int53(user) + )).done([self = _data->self](const TLuser &result, RequestId requestId) { + if (const auto that = self()) { + that->_data->result.users.push_back(result); + that->requestFinished(requestId); + } + }).fail([self = _data->self](const Error &error, RequestId requestId) { + if (const auto that = self()) { + that->requestFinished(requestId); + } + }).send()); + } else if (const auto chat = PeerToChat(peer)) { + _data->requests.emplace(_data->sender.request(TLgetBasicGroup( + tl_int53(chat) + )).done([self = _data->self](const TLbasicGroup &result, RequestId requestId) { + if (const auto that = self()) { + that->_data->result.chats.push_back(result); + that->requestFinished(requestId); + } + }).fail([self = _data->self](const Error &error, RequestId requestId) { + if (const auto that = self()) { + that->requestFinished(requestId); + } + }).send()); + } else if (const auto channel = PeerToChannel(peer)) { + _data->requests.emplace(_data->sender.request(TLgetSupergroup( + tl_int53(channel) + )).done([self = _data->self](const TLsupergroup &result, RequestId requestId) { + if (const auto that = self()) { + that->_data->result.channels.push_back(result); + that->requestFinished(requestId); + } + }).fail([self = _data->self](const Error &error, RequestId requestId) { + if (const auto that = self()) { + that->requestFinished(requestId); + } + }).send()); + } +} + +void ResolveChatsRequest::requestFinished(RequestId requestId) { + Expects(_data != nullptr); + + const auto removed = _data->requests.remove(requestId); + Assert(removed); + if (!_data->requests.empty()) { + return; + } + const auto data = base::take(_data); + if (data->done) { + data->done(data->result); + } +} + +} // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/tdb_resolve_chats.h b/Telegram/SourceFiles/tdb/tdb_resolve_chats.h new file mode 100644 index 0000000000000..135c59165a881 --- /dev/null +++ b/Telegram/SourceFiles/tdb/tdb_resolve_chats.h @@ -0,0 +1,100 @@ +/* +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 +*/ +#pragma once + +#include "tdb/tdb_sender.h" +#include "tdb/tdb_tl_scheme.h" + +namespace Tdb { + +struct ResolvedChats { + QVector ids; + std::vector dialogs; + std::vector users; + std::vector chats; + std::vector channels; + int count = 0; +}; + +class ResolveChatsRequest final { +public: + ResolveChatsRequest() = default; + ResolveChatsRequest(ResolveChatsRequest &&) = default; + ResolveChatsRequest &operator=(ResolveChatsRequest &&) = default; + ~ResolveChatsRequest(); + + [[nodiscard]] explicit operator bool() const { + return _data != nullptr; + } + + template + void send( + Sender &sender, + Request &&request, + Fn self, + FnMut done, + FnMut fail = nullptr) { + const auto id = sender.request( + std::move(request) + ).done([self](const TLchats &chats, RequestId requestId) { + if (const auto that = self()) { + that->listDone(chats); + that->requestFinished(requestId); + } + }).fail([self](const Error &error) { + if (const auto that = self()) { + that->listFail(error); + } + }).send(); + + cancel(); + _data = std::make_unique( + sender, + self, + id, + std::move(done), + std::move(fail)); + } + + void cancel(); + +private: + struct Data { + Data( + Sender &sender, + Fn self, + RequestId id, + FnMut done, + FnMut fail) + : sender(sender) + , self(std::move(self)) + , requests{ &id, &id + 1 } + , done(std::move(done)) + , fail(std::move(fail)) { + } + + Sender &sender; + Fn self; + base::flat_set requestedPeers; + base::flat_set requests; + ResolvedChats result; + FnMut done; + FnMut fail; + }; + + void listFail(const Error &error); + void listDone(const TLchats &chats); + void requestChat(TLint53 chatId); + void requestPeer(uint64 peer); + void requestFinished(RequestId requestId); + + std::unique_ptr _data; + +}; + +} // namespace Tdb diff --git a/Telegram/cmake/td_tdb.cmake b/Telegram/cmake/td_tdb.cmake index de0a929380390..d042f9a0521a3 100644 --- a/Telegram/cmake/td_tdb.cmake +++ b/Telegram/cmake/td_tdb.cmake @@ -17,6 +17,8 @@ nice_target_sources(td_tdb ${src_loc} PRIVATE tdb/tdb_account.cpp tdb/tdb_account.h + tdb/tdb_resolve_chats.cpp + tdb/tdb_resolve_chats.h tdb/tdb_sender.cpp tdb/tdb_sender.h tdb/tdb_tl_scheme.h From c46b65c968a96ddfa7c681cc2a61fa62676644fc Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 8 Jul 2021 09:56:02 +0300 Subject: [PATCH 012/350] Start peer / chat updates handling. --- Telegram/SourceFiles/api/api_updates.cpp | 57 +++++ Telegram/SourceFiles/api/api_updates.h | 9 + Telegram/SourceFiles/data/data_channel.cpp | 151 +++++++++++++ Telegram/SourceFiles/data/data_channel.h | 8 + Telegram/SourceFiles/data/data_chat.cpp | 50 +++++ Telegram/SourceFiles/data/data_chat.h | 8 + Telegram/SourceFiles/data/data_peer.cpp | 16 ++ Telegram/SourceFiles/data/data_peer.h | 3 + Telegram/SourceFiles/data/data_session.cpp | 236 +++++++++------------ Telegram/SourceFiles/data/data_user.cpp | 51 +++++ Telegram/SourceFiles/data/data_user.h | 9 + 11 files changed, 463 insertions(+), 135 deletions(-) diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 064f410c5b41a..4063ff900c043 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -58,6 +58,8 @@ For license and copyright information please follow this link: #include "apiwrap.h" #include "ui/text/format_values.h" // Ui::FormatPhone +#include "tdb/tdb_account.h" + namespace Api { namespace { @@ -72,6 +74,8 @@ constexpr auto kNoUpdatesTimeout = 60 * 1000; // If nothing is received in 1 min when was a sleepmode we ping. constexpr auto kNoUpdatesAfterSleepTimeout = 60 * crl::time(1000); +using namespace Tdb; + enum class DataIsLoadedResult { NotLoaded = 0, FromNotLoaded = 1, @@ -234,6 +238,7 @@ Updates::Updates(not_null session) , _idleFinishTimer([=] { checkIdleFinish(); }) { _ptsWaiter.setRequesting(true); +#if 0 // #TODO legacy session->account().mtpUpdates( ) | rpl::start_with_next([=](const MTPUpdates &updates) { mtpUpdateReceived(updates); @@ -248,6 +253,12 @@ Updates::Updates(not_null session) )).done([=](const MTPupdates_State &result) { stateDone(result); }).send(); +#endif + + session->tdb().updates( + ) | rpl::start_with_next([=](const TLupdate &update) { + applyUpdate(update); + }, _lifetime); using namespace rpl::mappers; session->changes().peerUpdates( @@ -837,6 +848,7 @@ void Updates::channelRangeDifferenceDone( } } +#if 0 // #TODO legacy void Updates::mtpNewSessionCreated() { Core::App().checkAutoLock(); _updatesSeq = 0; @@ -856,6 +868,7 @@ void Updates::mtpUpdateReceived(const MTPUpdates &updates) { applyGroupCallParticipantUpdates(updates); } } +#endif void Updates::applyGroupCallParticipantUpdates(const MTPUpdates &updates) { updates.match([&](const MTPDupdates &data) { @@ -2539,4 +2552,48 @@ void Updates::feedUpdate(const MTPUpdate &update) { } } +void Updates::applyUpdate(const TLupdate &update) { + update.match([&](const TLDupdateAuthorizationState &data) { + const auto type = data.vauthorization_state().type(); + if (type == id_authorizationStateReady) { + session().api().requestMoreDialogsIfNeeded(); + } + }, [&](const TLDupdateUser &data) { + session().data().processUser(data.vuser()); + }, [&](const TLDupdateBasicGroup &data) { + session().data().processChat(data.vbasic_group()); + }, [&](const TLDupdateSupergroup &data) { + session().data().processChannel(data.vsupergroup()); + }, [&](const TLDupdateNewChat &data) { + session().data().processPeer(data.vchat()); + }, [&](const TLDupdateChatLastMessage &data) { + //data.vchat_id(); + //data.vlast_message(); + //data.vpositions(); + }, [&](const TLDupdateChatPosition &data) { + //data.vchat_id(); + //data.vposition(); + }, [&](const TLDupdateUserFullInfo &data) { + const auto user = session().data().user(UserId(data.vuser_id())); + data.vuser_full_info().match([&](const TLDuserFullInfo &data) { + ::Data::ApplyUserUpdate(user, data); + }); + }, [&](const TLDupdateBasicGroupFullInfo &data) { + const auto chat = session().data().chat( + ChatId(data.vbasic_group_id())); + data.vbasic_group_full_info().match([&]( + const TLDbasicGroupFullInfo &data) { + ::Data::ApplyChatUpdate(chat, data); + }); + }, [&](const TLDupdateSupergroupFullInfo &data) { + const auto channel = session().data().channel( + ChannelId(data.vsupergroup_id())); + data.vsupergroup_full_info().match([&]( + const TLDsupergroupFullInfo &data) { + ::Data::ApplyChannelUpdate(channel, data); + }); + }, [](const auto &) { + }); +} + } // namespace Api diff --git a/Telegram/SourceFiles/api/api_updates.h b/Telegram/SourceFiles/api/api_updates.h index f21baa9641ce1..b09b47587a9bc 100644 --- a/Telegram/SourceFiles/api/api_updates.h +++ b/Telegram/SourceFiles/api/api_updates.h @@ -13,6 +13,10 @@ For license and copyright information please follow this link: class ApiWrap; class History; +namespace Tdb { +class TLupdate; +} // namespace Tdb + namespace MTP { class Error; } // namespace MTP @@ -82,6 +86,8 @@ class Updates final { rpl::lifetime lifetime; }; + void applyUpdate(const Tdb::TLupdate &update); + void channelRangeDifferenceSend( not_null channel, MsgRange range, @@ -120,8 +126,11 @@ class Updates final { void failDifferenceStartTimerFor(ChannelData *channel); void feedChannelDifference(const MTPDupdates_channelDifference &data); +#if 0 // #TODO legacy void mtpUpdateReceived(const MTPUpdates &updates); void mtpNewSessionCreated(); +#endif + void feedUpdateVector( const MTPVector &updates, SkipUpdatePolicy policy = SkipUpdatePolicy::SkipNone); diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 813dc345870b0..2da4b49b6fd9f 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -1142,4 +1142,155 @@ void ApplyChannelUpdate( channel->owner().sendHistoryChangeNotifications(); } +void ApplyChannelUpdate( + not_null channel, + const TLDsupergroupFullInfo &update) { + const auto session = &channel->session(); + + //if (channel->isMegagroup()) { // #TODO tdlib + // const auto suggestions = update.vpending_suggestions().value_or_empty(); + // channel->owner().setSuggestToGigagroup( + // channel, + // ranges::contains( + // suggestions, + // "convert_to_gigagroup"_q, + // &MTPstring::v)); + //} + + //channel->setAvailableMinId(update.vavailable_min_id().value_or_empty()); + auto canViewAdmins = channel->canViewAdmins(); + auto canViewMembers = channel->canViewMembers(); + auto canEditStickers = channel->canEditStickers(); + + //if (const auto call = update.vcall()) { + // channel->setGroupCall(*call); + //} else { + // channel->clearGroupCall(); + //} + //if (const auto as = update.vgroupcall_default_join_as()) { + // channel->setGroupCallDefaultJoinAs(peerFromMTP(*as)); + //} else { + // channel->setGroupCallDefaultJoinAs(0); + //} + + //channel->setMessagesTTL(update.vttl_period().value_or_empty()); + + // #TODO tdlib + //update.vcan_get_members(); + //update.vcan_get_statistics(); + //update.vcan_set_location(); + //update.vcan_set_sticker_set(); + //update.vcan_set_username(); + //update.vis_all_history_available(); + //channel->setFullFlags(update.vflags().v); + + if (const auto photo = update.vphoto()) { + channel->setPhotoFull(*photo); + } else { + channel->clearPhoto(); + } + if (const auto from = update.vupgraded_from_basic_group_id().v) { + channel->addFlags(ChannelDataFlag::Megagroup); + const auto chat = channel->owner().chat(ChatId(from)); + Data::ApplyMigration(chat, channel); + } + channel->setAbout(update.vdescription().v); + channel->setMembersCount(update.vmember_count().v); + channel->setAdminsCount(update.vadministrator_count().v); + channel->setRestrictedCount(update.vrestricted_count().v); + channel->setKickedCount(update.vbanned_count().v); + + channel->setSlowmodeSeconds(update.vslow_mode_delay().v); + if (const auto in = update.vslow_mode_delay_expires_in().v; in > 0.) { + // #TODO tdlib better slowmode management + channel->growSlowmodeLastMessage( + base::unixtime::now() + int(std::round(in * 1000)) - channel->slowmodeSeconds()); + } + + // #TODO tdlib + //if (const auto invite = update.vinvite_link()) { + // channel->session().api().inviteLinks().setMyPermanent( + // channel, + // *invite); + //} else { + // channel->session().api().inviteLinks().clearMyPermanent(channel); + //} + //if (const auto location = update.vlocation()) { + // channel->setLocation(*location); + //} else { + // channel->setLocation(MTP_channelLocationEmpty()); + //} + + const auto linkedChatId = peerToChannel( + peerFromTdbChat(update.vlinked_chat_id())); + channel->setLinkedChat(linkedChatId + ? channel->owner().channelLoaded(linkedChatId) + : nullptr); + + //if (const auto history = channel->owner().historyLoaded(channel)) { + // if (const auto available = update.vavailable_min_id()) { + // history->clearUpTill(available->v); + // } + // const auto folderId = update.vfolder_id().value_or_empty(); + // const auto folder = folderId + // ? channel->owner().folderLoaded(folderId) + // : nullptr; + // auto &histories = channel->owner().histories(); + // if (folder && history->folder() != folder) { + // // If history folder is unknown or not synced, request both. + // histories.requestDialogEntry(history); + // histories.requestDialogEntry(folder); + // } else if (!history->folderKnown() + // || channel->pts() != update.vpts().v) { + // histories.requestDialogEntry(history); + // } else { + // history->applyDialogFields( + // history->folder(), + // update.vunread_count().v, + // update.vread_inbox_max_id().v, + // update.vread_outbox_max_id().v); + // } + //} + //if (const auto pinned = update.vpinned_msg_id()) { + // SetTopPinnedMessageId(channel, pinned->v); + //} + if (channel->isMegagroup()) { + //update.vbot_commands(); // #TODO tdlib + //if (channel->mgInfo->updateBotCommands(update.vbot_info())) { + // channel->owner().botCommandsChanged(channel); + //} + + //update.vsticker_set_id();// #TODO tdlib + //const auto stickerSet = update.vstickerset(); + //const auto set = stickerSet ? &stickerSet->c_stickerSet() : nullptr; + //const auto newSetId = (set ? set->vid().v : 0); + //const auto oldSetId = (channel->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) + // ? channel->mgInfo->stickerSet.c_inputStickerSetID().vid().v + // : 0; + //const auto stickersChanged = (canEditStickers != channel->canEditStickers()) + // || (oldSetId != newSetId); + //if (oldSetId != newSetId) { + // channel->mgInfo->stickerSet = set + // ? MTP_inputStickerSetID(set->vid(), set->vaccess_hash()) + // : MTP_inputStickerSetEmpty(); + //} + //if (stickersChanged) { + // session->changes().peerUpdated(channel, UpdateFlag::StickersSet); + //} + } + channel->fullUpdated(); + + if (canViewAdmins != channel->canViewAdmins() + || canViewMembers != channel->canViewMembers()) { + session->changes().peerUpdated(channel, UpdateFlag::Rights); + } + + //session->api().applyNotifySettings( + // MTP_inputNotifyPeer(channel->input), + // update.vnotify_settings()); + + // For clearUpTill() call. + channel->owner().sendHistoryChangeNotifications(); +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index 577ae2ff98cd7..84dccf0abc90d 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -14,6 +14,10 @@ For license and copyright information please follow this link: #include "data/data_peer_bot_commands.h" #include "data/data_user_names.h" +namespace Tdb { +class TLDsupergroupFullInfo; +} // namespace Tdb + struct ChannelLocation { QString address; Data::LocationPoint point; @@ -533,4 +537,8 @@ void ApplyChannelUpdate( not_null channel, const MTPDchannelFull &update); +void ApplyChannelUpdate( + not_null channel, + const Tdb::TLDsupergroupFullInfo &update); + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_chat.cpp b/Telegram/SourceFiles/data/data_chat.cpp index 8f8558b3824fa..637323df7e5fd 100644 --- a/Telegram/SourceFiles/data/data_chat.cpp +++ b/Telegram/SourceFiles/data/data_chat.cpp @@ -573,4 +573,54 @@ void ApplyChatUpdate( }); } +void ApplyChatUpdate( + not_null chat, + const TLDbasicGroupFullInfo &update) { + //update.vmembers(); // #TODO tdlib + //ApplyChatUpdate(chat, update.vparticipants()); + + chat->creator = UserId(update.vcreator_user_id()); + //if (const auto call = update.vcall()) { + // chat->setGroupCall(*call); + //} else { + // chat->clearGroupCall(); + //} + //if (const auto as = update.vgroupcall_default_join_as()) { + // chat->setGroupCallDefaultJoinAs(peerFromMTP(*as)); + //} else { + // chat->setGroupCallDefaultJoinAs(0); + //} + + //chat->setMessagesTTL(update.vttl_period().value_or_empty()); + + //update.vbot_commands(); // #TODO tdlib + //if (const auto info = update.vbot_info()) { + // chat->setBotCommands(*info); + //} else { + // chat->setBotCommands(MTP_vector()); + //} + + //chat->setFullFlags(update.vflags().v); + if (const auto photo = update.vphoto()) { + chat->setPhotoFull(*photo); + } else { + chat->clearPhoto(); + } + //if (const auto invite = update.vinvite_link()) { // #TODO tdlib + // chat->session().api().inviteLinks().setMyPermanent(chat, *invite); + //} else { + // chat->session().api().inviteLinks().clearMyPermanent(chat); + //} + //if (const auto pinned = update.vpinned_msg_id()) { + // SetTopPinnedMessageId(chat, pinned->v); + //} + //chat->checkFolder(update.vfolder_id().value_or_empty()); + chat->fullUpdated(); + chat->setAbout(update.vdescription().v); + + //chat->session().api().applyNotifySettings( + // MTP_inputNotifyPeer(chat->input), + // update.vnotify_settings()); +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_chat.h b/Telegram/SourceFiles/data/data_chat.h index 5272a229ad4c2..5081a851d9ac8 100644 --- a/Telegram/SourceFiles/data/data_chat.h +++ b/Telegram/SourceFiles/data/data_chat.h @@ -13,6 +13,10 @@ For license and copyright information please follow this link: enum class ChatAdminRight; +namespace Tdb { +class TLDbasicGroupFullInfo; +} // namespace Tdb + enum class ChatDataFlag { Left = (1 << 0), //Kicked = (1 << 1), @@ -235,4 +239,8 @@ void ApplyChatUpdate( not_null chat, const MTPChatParticipants &update); +void ApplyChatUpdate( + not_null chat, + const Tdb::TLDbasicGroupFullInfo &update); + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 2405580b1713a..bb0ee71245313 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -500,6 +500,22 @@ void PeerData::updateUserpic(const TLprofilePhoto &photo) { }); } +void PeerData::setPhotoFull(const TLchatPhoto &data) { + data.match([&](const TLDchatPhoto &data) { + // #TODO tdlib animated avatars. + if (data.vsizes().v.isEmpty()) { + clearPhoto(); + } else { + const auto &size = data.vsizes().v.front(); + updateUserpic(size.match([&](const TLDphotoSize &data) { + return data.vphoto().match([&](const TLDfile &data) { + return data.vid().v; + }); + }), data.vid().v); // #TODO tdlib set data to view. + } + }); +} + void PeerData::clearPhoto() { clearUserpic(); } diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index 2487aae18f707..bfc09b752f0f1 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -33,6 +33,7 @@ class Session; namespace Tdb { class TLprofilePhoto; class TLchatPhotoInfo; +class TLchatPhoto; } // namespace Tdb namespace Data { @@ -274,6 +275,8 @@ class PeerData { return _nameFirstLetters; } + void setPhotoFull(const Tdb::TLchatPhoto &data); + void clearPhoto(); void setUserpic( PhotoId photoId, diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 79676d21121a3..e8c26833de273 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -139,20 +139,40 @@ void CheckForSwitchInlineButton(not_null item) { return tl_is_true(check) ? value : Flag(0); }; return Flag(0) - | bit(data.vcan_add_web_page_previews(), Flag::f_embed_links) - | bit(data.vcan_change_info(), Flag::f_change_info) - | bit(data.vcan_invite_users(), Flag::f_invite_users) - | bit(data.vcan_pin_messages(), Flag::f_pin_messages) - | bit(data.vcan_send_media_messages(), Flag::f_send_media) - | bit(data.vcan_send_messages(), Flag::f_send_messages) - | bit(data.vcan_send_polls(), Flag::f_send_polls) - | bit(data.vcan_send_other_messages(), Flag::f_send_stickers) - | bit(data.vcan_send_other_messages(), Flag::f_send_games) - | bit(data.vcan_send_other_messages(), Flag::f_send_gifs) - | bit(data.vcan_send_other_messages(), Flag::f_send_inline); + | bit(data.vcan_add_web_page_previews(), Flag::EmbedLinks) + | bit(data.vcan_change_info(), Flag::ChangeInfo) + | bit(data.vcan_invite_users(), Flag::InviteUsers) + | bit(data.vcan_pin_messages(), Flag::PinMessages) + | bit(data.vcan_send_media_messages(), Flag::SendMedia) + | bit(data.vcan_send_messages(), Flag::SendMessages) + | bit(data.vcan_send_polls(), Flag::SendPolls) + | bit(data.vcan_send_other_messages(), Flag::SendStickers) + | bit(data.vcan_send_other_messages(), Flag::SendGames) + | bit(data.vcan_send_other_messages(), Flag::SendGifs) + | bit(data.vcan_send_other_messages(), Flag::SendInline); }); } +[[nodiscard]] ChatAdminRights AdminRightsFromChatMemberStatus( + const TLDchatMemberStatusAdministrator &data) { + using Flag = ChatAdminRight; + const auto bit = [&](const TLbool &check, Flag value) { + return tl_is_true(check) ? value : Flag(0); + }; + return Flag(0) + | bit(data.vcan_manage_chat(), Flag::Other) + | bit(data.vcan_change_info(), Flag::ChangeInfo) + | bit(data.vcan_delete_messages(), Flag::DeleteMessages) + | bit(data.vcan_edit_messages(), Flag::EditMessages) + | bit(data.vcan_invite_users(), Flag::InviteUsers) + | bit(data.vcan_manage_voice_chats(), Flag::ManageCall) + | bit(data.vcan_pin_messages(), Flag::PinMessages) + | bit(data.vcan_post_messages(), Flag::PostMessages) + | bit(data.vcan_promote_members(), Flag::AddAdmins) + | bit(data.vcan_restrict_members(), Flag::BanUsers) + | bit(data.vis_anonymous(), Flag::Anonymous); +} + // We should get a full restriction in "{full}: {reason}" format and we // need to find an "-all" tag in {full}, otherwise ignore this restriction. std::vector ExtractUnavailableReasons( @@ -1140,8 +1160,8 @@ not_null Session::processUser(const TLuser &user) { result->clearPhoto(); } result->setUnavailableReasons({}); // #TODO tdlib - //result->setFlags(MTPDuser_ClientFlag::f_inaccessible | 0); - //result->setFlags(MTPDuser::Flag::f_deleted); + //result->setFlags(UserDataFlag::Inaccessible); + //result->setFlags(UserDataFlag::Deleted); result->setBotInfoVersion(-1); // #TODO tdlib result->setIsContact(tl_is_true(data.vis_contact())); if (canShareThisContact != result->canShareThisContactFast()) { @@ -1201,15 +1221,13 @@ not_null Session::processPeer(const TLchat &dialog) { } else { chat->clearPhoto(); } - const auto flags = RestrictionsFromPermissions(data.vpermissions()); - chat->setDefaultRestrictions(MTP_chatBannedRights( - MTP_flags(flags), - MTP_int(flags ? ChannelData::kRestrictUntilForever : 0))); + chat->setDefaultRestrictions( + RestrictionsFromPermissions(data.vpermissions())); data.vvoice_chat().match([&](const TLDvoiceChat &data) { - const auto callFlag = MTPDchat::Flag::f_call_not_empty; + const auto callFlag = ChatDataFlag::CallNotEmpty; const auto callNotEmpty = tl_is_true(data.vhas_participants()); chat->setFlags(chat->flags() // #TODO tdlib - | (callNotEmpty ? callFlag : MTPDchat::Flag(0))); + | (callNotEmpty ? callFlag : ChatDataFlag(0))); }); if (canAddMembers != chat->canAddMembers()) { @@ -1221,27 +1239,8 @@ not_null Session::processPeer(const TLchat &dialog) { const auto canViewMembers = channel->canViewMembers(); const auto canAddMembers = channel->canAddMembers(); - data.vpermissions().match([&](const TLDchatPermissions &data) { - using Flag = ChatRestriction; - const auto bit = [&](const TLbool &check, Flag value) { - return tl_is_true(check) ? value : Flag(0); - }; - const auto flags = Flag(0) - | bit(data.vcan_add_web_page_previews(), Flag::f_embed_links) - | bit(data.vcan_change_info(), Flag::f_change_info) - | bit(data.vcan_invite_users(), Flag::f_invite_users) - | bit(data.vcan_pin_messages(), Flag::f_pin_messages) - | bit(data.vcan_send_media_messages(), Flag::f_send_media) - | bit(data.vcan_send_messages(), Flag::f_send_messages) - | bit(data.vcan_send_polls(), Flag::f_send_polls) - | bit(data.vcan_send_other_messages(), Flag::f_send_stickers) - | bit(data.vcan_send_other_messages(), Flag::f_send_games) - | bit(data.vcan_send_other_messages(), Flag::f_send_gifs) - | bit(data.vcan_send_other_messages(), Flag::f_send_inline); - channel->setDefaultRestrictions(MTP_chatBannedRights( - MTP_flags(flags), - MTP_int(flags ? ChannelData::kRestrictUntilForever : 0))); - }); + channel->setDefaultRestrictions( + RestrictionsFromPermissions(data.vpermissions())); channel->setName(data.vtitle().v, channel->username); if (const auto photo = data.vphoto()) { @@ -1274,60 +1273,44 @@ not_null Session::processChat(const TLbasicGroup &chat) { return data; }); const auto result = this->chat(data.vid().v); - using Flag = MTPDchat::Flag; - const auto setting = Flag::f_deactivated - | Flag::f_left - | Flag::f_kicked; + using Flag = ChatDataFlag; + const auto setting = Flag::Deactivated + | Flag::Left + | Flag::Kicked; auto flags = (result->flags() & ~setting) - | (!tl_is_true(data.vis_active()) ? Flag::f_deactivated : Flag()); + | (!tl_is_true(data.vis_active()) ? Flag::Deactivated : Flag()); result->count = data.vmember_count().v; if (const auto migratedTo = data.vupgraded_to_supergroup_id().v) { const auto channel = this->channel(migratedTo); - channel->addFlags(MTPDchannel::Flag::f_megagroup); + channel->addFlags(ChannelDataFlag::Megagroup); ApplyMigration(result, channel); } data.vstatus().match([&](const TLDchatMemberStatusCreator &data) { if (!tl_is_true(data.vis_member())) { - flags |= Flag::f_left; + flags |= Flag::Left; } result->creator = session().userId(); - result->setAdminRights(MTP_chatAdminRights(MTP_flags( - (tl_is_true(data.vis_anonymous()) - ? ChatAdminRight::f_anonymous - : ChatAdminRight())))); + result->setAdminRights(tl_is_true(data.vis_anonymous()) + ? ChatAdminRight::Anonymous + : ChatAdminRight()); //data.vcustom_title().v; // #TODO tdlib }, [&](const TLDchatMemberStatusAdministrator &data) { - using Flag = ChatAdminRight; - const auto bit = [&](const TLbool &check, Flag value) { - return tl_is_true(check) ? value : Flag(0); - }; - result->setAdminRights(MTP_chatAdminRights(MTP_flags(Flag(0) - | bit(data.vcan_manage_chat(), Flag::f_other) - | bit(data.vcan_change_info(), Flag::f_change_info) - | bit(data.vcan_delete_messages(), Flag::f_delete_messages) - | bit(data.vcan_edit_messages(), Flag::f_edit_messages) - | bit(data.vcan_invite_users(), Flag::f_invite_users) - | bit(data.vcan_manage_voice_chats(), Flag::f_manage_call) - | bit(data.vcan_pin_messages(), Flag::f_pin_messages) - | bit(data.vcan_post_messages(), Flag::f_post_messages) - | bit(data.vcan_promote_members(), Flag::f_add_admins) - | bit(data.vcan_restrict_members(), Flag::f_ban_users) - | bit(data.vis_anonymous(), Flag::f_anonymous)))); + result->setAdminRights(AdminRightsFromChatMemberStatus(data)); //data.vcustom_title().v; // #TODO tdlib }, [&](const TLDchatMemberStatusMember &data) { - result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + result->setAdminRights(ChatAdminRights()); }, [&](const TLDchatMemberStatusRestricted &data) { LOG(("Tdb Error: Should not get restrictions in basic groups.")); - result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + result->setAdminRights(ChatAdminRights()); if (!tl_is_true(data.vis_member())) { - flags |= Flag::f_left; + flags |= Flag::Left; } }, [&](const TLDchatMemberStatusLeft &data) { - result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); - flags |= Flag::f_left; + result->setAdminRights(ChatAdminRights()); + flags |= Flag::Left; }, [&](const TLDchatMemberStatusBanned &data) { - result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); - flags |= Flag::f_kicked; + result->setAdminRights(ChatAdminRights()); + flags |= Flag::Kicked; }); result->setFlags(flags); return result; @@ -1340,95 +1323,78 @@ not_null Session::processChannel( return data; }); const auto result = this->channel(data.vid().v); - using Flag = MTPDchannel::Flag; + using Flag = ChannelDataFlag; result->date = data.vdate().v; - const auto setting = Flag::f_megagroup - | Flag::f_gigagroup - | Flag::f_scam - | Flag::f_fake - | Flag::f_left - | Flag::f_signatures - | Flag::f_slowmode_enabled - | Flag::f_verified - | Flag::f_has_geo - | Flag::f_has_link - | Flag::f_creator; + const auto setting = Flag::Megagroup + | Flag::Gigagroup + | Flag::Scam + | Flag::Fake + | Flag::Left + | Flag::Signatures + | Flag::SlowmodeEnabled + | Flag::Verified + //| Flag::f_has_geo + | Flag::HasLink + | Flag::Creator; auto flags = (result->flags() & ~setting) - | (!tl_is_true(data.vis_channel()) ? Flag::f_megagroup : Flag()) + | (!tl_is_true(data.vis_channel()) ? Flag::Megagroup : Flag()) | (tl_is_true(data.vis_broadcast_group()) - ? Flag::f_gigagroup + ? Flag::Gigagroup : Flag()) - | (tl_is_true(data.vis_fake()) ? Flag::f_fake : Flag()) - | (tl_is_true(data.vis_scam()) ? Flag::f_scam : Flag()) - | (tl_is_true(data.vis_verified()) ? Flag::f_verified : Flag()) + | (tl_is_true(data.vis_fake()) ? Flag::Fake : Flag()) + | (tl_is_true(data.vis_scam()) ? Flag::Scam : Flag()) + | (tl_is_true(data.vis_verified()) ? Flag::Verified : Flag()) | (tl_is_true(data.vis_slow_mode_enabled()) - ? Flag::f_slowmode_enabled + ? Flag::SlowmodeEnabled : Flag()) - | (tl_is_true(data.vsign_messages()) ? Flag::f_signatures : Flag()) - | (tl_is_true(data.vhas_linked_chat()) ? Flag::f_has_link : Flag()) - | (tl_is_true(data.vhas_location()) ? Flag::f_has_geo : Flag()) + | (tl_is_true(data.vsign_messages()) ? Flag::Signatures : Flag()) + | (tl_is_true(data.vhas_linked_chat()) ? Flag::HasLink : Flag()) + //| (tl_is_true(data.vhas_location()) ? Flag::f_has_geo : Flag()) | ((data.vstatus().type() == id_chatMemberStatusCreator) - ? Flag::f_creator + ? Flag::Creator : Flag()); result->setMembersCount(data.vmember_count().v); result->setName(result->name, data.vusername().v); //data.vrestriction_reason(); // #TODO tdlib data.vstatus().match([&](const TLDchatMemberStatusCreator &data) { if (!tl_is_true(data.vis_member())) { - flags |= Flag::f_left; - } - result->setAdminRights(MTP_chatAdminRights(MTP_flags( - (tl_is_true(data.vis_anonymous()) - ? ChatAdminRight::f_anonymous - : ChatAdminRight())))); - result->setRestrictions( - MTP_chatBannedRights(MTP_flags(0), MTP_int(0))); + flags |= Flag::Left; + } + result->setAdminRights(tl_is_true(data.vis_anonymous()) + ? ChatAdminRight::Anonymous + : ChatAdminRight()); + result->setRestrictions(ChatRestrictionsInfo()); //data.vcustom_title().v; // #TODO tdlib }, [&](const TLDchatMemberStatusAdministrator &data) { using Flag = ChatAdminRight; const auto bit = [&](const TLbool &check, Flag value) { return tl_is_true(check) ? value : Flag(0); }; - result->setAdminRights(MTP_chatAdminRights(MTP_flags(Flag(0) - | bit(data.vcan_manage_chat(), Flag::f_other) - | bit(data.vcan_change_info(), Flag::f_change_info) - | bit(data.vcan_delete_messages(), Flag::f_delete_messages) - | bit(data.vcan_edit_messages(), Flag::f_edit_messages) - | bit(data.vcan_invite_users(), Flag::f_invite_users) - | bit(data.vcan_manage_voice_chats(), Flag::f_manage_call) - | bit(data.vcan_pin_messages(), Flag::f_pin_messages) - | bit(data.vcan_post_messages(), Flag::f_post_messages) - | bit(data.vcan_promote_members(), Flag::f_add_admins) - | bit(data.vcan_restrict_members(), Flag::f_ban_users) - | bit(data.vis_anonymous(), Flag::f_anonymous)))); - result->setRestrictions( - MTP_chatBannedRights(MTP_flags(0), MTP_int(0))); + result->setAdminRights(AdminRightsFromChatMemberStatus(data)); + result->setRestrictions(ChatRestrictionsInfo()); //data.vcustom_title().v; // #TODO tdlib }, [&](const TLDchatMemberStatusMember &data) { - result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); - result->setRestrictions( - MTP_chatBannedRights(MTP_flags(0), MTP_int(0))); + result->setAdminRights(ChatAdminRights()); + result->setRestrictions(ChatRestrictionsInfo()); }, [&](const TLDchatMemberStatusRestricted &data) { - result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); - result->setRestrictions(MTP_chatBannedRights( - MTP_flags(RestrictionsFromPermissions(data.vpermissions())), - MTP_int(data.vrestricted_until_date().v))); + result->setAdminRights(ChatAdminRights()); + result->setRestrictions({ + RestrictionsFromPermissions(data.vpermissions()), + data.vrestricted_until_date().v, + }); if (!tl_is_true(data.vis_member())) { - flags |= Flag::f_left; + flags |= Flag::Left; } }, [&](const TLDchatMemberStatusLeft &data) { - result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); - result->setRestrictions( - MTP_chatBannedRights(MTP_flags(0), MTP_int(0))); - flags |= Flag::f_left; + result->setAdminRights(ChatAdminRights()); + result->setRestrictions(ChatRestrictionsInfo()); + flags |= Flag::Left; }, [&](const TLDchatMemberStatusBanned &data) { - result->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + result->setAdminRights(ChatAdminRights()); const auto flags = ChannelData::KickedRestrictedRights( session().user() - ).c_chatBannedRights().vflags(); - result->setRestrictions(MTP_chatBannedRights( - flags, - MTP_int(data.vbanned_until_date().v))); + ).flags; + result->setRestrictions({ flags, data.vbanned_until_date().v }); }); result->setFlags(flags); return result; diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index 4951d7135f186..b1aab17e58d87 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -537,4 +537,55 @@ void ApplyUserUpdate(not_null user, const MTPDuserFull &update) { user->fullUpdated(); } +void ApplyUserUpdate( + not_null user, + const TLDuserFullInfo &update) { + if (const auto photo = update.vphoto()) { + user->setPhotoFull(*photo); + } else { + user->clearPhoto(); + } + //const auto settings = update.vsettings().match([&]( // #TODO tdlib + // const MTPDpeerSettings &data) { + // return data.vflags().v; + //}); + + //MTPDpeerSettings::Flag::f_need_contacts_exception; // #TODO tdlib + //update.vneed_phone_number_privacy_exception(); + //user->setSettings(settings); + + //user->session().api().applyNotifySettings( + // MTP_inputNotifyPeer(user->input), + // update.vnotify_settings()); + + //user->setMessagesTTL(update.vttl_period().value_or_empty()); + + //update.vcommands(); // #TODO tdlib + //update.vdescription(); + //if (const auto info = update.vbot_info()) { + // user->setBotInfo(*info); + //} else { + // user->setBotInfoVersion(-1); + //} + + //if (const auto pinned = update.vpinned_msg_id()) { + // SetTopPinnedMessageId(user, pinned->v); + //} + + //MTPDuserFull::Flag::f_video_calls_available; // #TODO tdlib + //update.vsupports_video_calls(); + //user->setFullFlags(update.vflags().v); + user->setIsBlocked(tl_is_true(update.vis_blocked())); + user->setCallsStatus(tl_is_true(update.vhas_private_calls()) + ? UserData::CallsStatus::Private + : tl_is_true(update.vcan_be_called()) + ? UserData::CallsStatus::Enabled + : UserData::CallsStatus::Disabled); + user->setAbout(update.vbio().v); + //update.vshare_text(); // #TODO tdlib + user->setCommonChatsCount(update.vgroup_in_common_count().v); + //user->checkFolder(update.vfolder_id().value_or_empty()); + user->fullUpdated(); +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index a0900cd87037b..480e13d0fc260 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -16,6 +16,10 @@ namespace Data { struct BotCommand; } // namespace Data +namespace Tdb { +class TLDuserFullInfo; +} // namespace Tdb + struct BotInfo { BotInfo(); @@ -82,6 +86,7 @@ class UserData final : public PeerData { #endif void setPhoto(const Tdb::TLprofilePhoto &photo); + void setPhoto(const Tdb::TLchatPhoto &photo); void setName( const QString &newFirstName, @@ -212,4 +217,8 @@ namespace Data { void ApplyUserUpdate(not_null user, const MTPDuserFull &update); +void ApplyUserUpdate( + not_null user, + const Tdb::TLDuserFullInfo &update); + } // namespace Data From c231f2bf4df4ff88f667f758743321b46cdb9ec5 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 23 Aug 2021 09:59:22 +0300 Subject: [PATCH 013/350] Allow getting SingleDataType in sender .done handler. --- .../SourceFiles/tdb/details/tdb_tl_core.h | 3 ++ Telegram/SourceFiles/tdb/tdb_sender.h | 29 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h index 1201f34ccdb1f..1cd15605b99b1 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core.h +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h @@ -26,6 +26,9 @@ namespace Tdb { inline constexpr auto null = std::nullopt; +struct NotSingleDataTypePlaceholder { +}; + using TLint32 = tl::int_type; using TLint53 = tl::int64_type; using TLint64 = tl::int64_type; diff --git a/Telegram/SourceFiles/tdb/tdb_sender.h b/Telegram/SourceFiles/tdb/tdb_sender.h index 31d0a5fa84bca..4364c4f8a7f71 100644 --- a/Telegram/SourceFiles/tdb/tdb_sender.h +++ b/Telegram/SourceFiles/tdb/tdb_sender.h @@ -43,6 +43,7 @@ class Sender final { auto onstack = std::move(handler); sender->senderRequestHandled(requestId); + using SingleDataType = typename Result::SingleDataType; if (!onstack) { return; } else if constexpr (IsCallable< @@ -54,6 +55,19 @@ class Sender final { onstack(result); } else if constexpr (IsCallable) { onstack(); + } else if constexpr (IsCallable< + Handler, + const SingleDataType&, + RequestId>) { + result.match([&](const SingleDataType &data) { + onstack(data, requestId); + }); + } else if constexpr (IsCallable< + Handler, + const SingleDataType&>) { + result.match([&](const SingleDataType &data) { + onstack(data); + }); } else { static_assert(false_t(Handler{}), "Bad done handler."); } @@ -104,7 +118,7 @@ class Sender final { explicit Sender(Sender &other) noexcept; template - class SpecificRequestBuilder final : public RequestBuilder { + class SpecificRequestBuilder final : public RequestBuilder { private: friend class Sender; SpecificRequestBuilder( @@ -117,6 +131,7 @@ class Sender final { public: using Result = typename Request::ResponseType; + using SingleDataType = typename Result::SingleDataType; [[nodiscard]] SpecificRequestBuilder &done( FnMut callback) { _done = makeDoneHandler(std::move(callback)); @@ -134,6 +149,18 @@ class Sender final { _done = makeDoneHandler(std::move(callback)); return *this; } + [[nodiscard]] SpecificRequestBuilder &done( + FnMut callback) { + _done = makeDoneHandler(std::move(callback)); + return *this; + } + [[nodiscard]] SpecificRequestBuilder &done( + FnMut callback) { + _done = makeDoneHandler(std::move(callback)); + return *this; + } [[nodiscard]] SpecificRequestBuilder &fail( Fn callback) noexcept { From 4b870f3f37f9cb862c11edce99642e39d6462902 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 23 Aug 2021 10:31:07 +0300 Subject: [PATCH 014/350] Provide TLbool as a core type. --- .../SourceFiles/tdb/details/tdb_tl_core.h | 28 +++++++++++++++++++ .../details/tdb_tl_core_conversion_from.cpp | 2 +- .../tdb/details/tdb_tl_core_conversion_to.cpp | 2 +- .../tdb/details/tdb_tl_generate.py | 3 ++ Telegram/SourceFiles/tdb/tdb_tl_scheme.h | 8 ------ 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core.h b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h index 1cd15605b99b1..3babb00fa62a4 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core.h +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core.h @@ -22,6 +22,14 @@ class Object; class Function; } // namespace td::td_api +namespace tl { + +enum { + id_bool = 0x8f99dbc7, +}; + +} // namespace tl + namespace Tdb { inline constexpr auto null = std::nullopt; @@ -85,6 +93,26 @@ inline TLvector tl_vector() { return tl::make_vector(); } +class TLbool { +public: + bool v = false; + + constexpr TLbool() noexcept = default; + + constexpr uint32 type() const noexcept { + return tl::id_bool; + } + +private: + explicit constexpr TLbool(bool val) noexcept : v(val) { + } + + friend constexpr TLbool tl_bool(bool v) noexcept; +}; +inline constexpr TLbool tl_bool(bool v) noexcept { + return TLbool(v); +} + class TLstring { public: TLstring() noexcept = default; diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp index 9d29628015aaa..3c2d73c19f336 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_from.cpp @@ -30,7 +30,7 @@ TLdouble tl_from_simple(double value) { } TLbool tl_from_simple(bool value) { - return value ? tl_boolTrue() : tl_boolFalse(); + return tl_bool(value); } } // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp index c1f22b9f90966..2a2822356647f 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_core_conversion_to.cpp @@ -30,7 +30,7 @@ double tl_to_simple(const TLdouble &value) { } bool tl_to_simple(const TLbool &value) { - return (value.type() == id_boolTrue); + return value.v; } } // namespace Tdb diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_generate.py b/Telegram/SourceFiles/tdb/details/tdb_tl_generate.py index aac583e079a8f..18624a7d46e0b 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_generate.py +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_generate.py @@ -37,6 +37,9 @@ 'bytes = Bytes;', 'vector {t:Type} # [ t ] = Vector t;', + + 'boolFalse = Bool;', + 'boolTrue = Bool;' ], 'builtin': [ 'double', diff --git a/Telegram/SourceFiles/tdb/tdb_tl_scheme.h b/Telegram/SourceFiles/tdb/tdb_tl_scheme.h index d9b59015cf0f6..04a51ef6c038d 100644 --- a/Telegram/SourceFiles/tdb/tdb_tl_scheme.h +++ b/Telegram/SourceFiles/tdb/tdb_tl_scheme.h @@ -11,14 +11,6 @@ For license and copyright information please follow this link: namespace Tdb { -[[nodiscard]] inline TLbool tl_bool(bool value) { - return value ? tl_boolTrue() : tl_boolFalse(); -} - -[[nodiscard]] inline bool tl_is_true(const TLbool &value) { - return (value.type() == id_boolTrue); -} - struct Error { explicit Error(const TLerror &error) : code(error.c_error().vcode().v) From 6d2f60cc75615ed04f72acea9a5bc47b32895cc3 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 23 Aug 2021 10:31:22 +0300 Subject: [PATCH 015/350] Fix build with TLbool provided as a core type. --- Telegram/SourceFiles/data/data_session.cpp | 48 +++++++++---------- Telegram/SourceFiles/data/data_user.cpp | 6 +-- .../intro/intro_password_check.cpp | 2 +- Telegram/SourceFiles/intro/intro_step.cpp | 3 +- .../window/window_lock_widgets.cpp | 2 +- 5 files changed, 30 insertions(+), 31 deletions(-) diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index e8c26833de273..3277462cea46f 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -136,7 +136,7 @@ void CheckForSwitchInlineButton(not_null item) { return permissions.match([&](const TLDchatPermissions &data) { using Flag = ChatRestriction; const auto bit = [&](const TLbool &check, Flag value) { - return tl_is_true(check) ? value : Flag(0); + return check.v ? value : Flag(0); }; return Flag(0) | bit(data.vcan_add_web_page_previews(), Flag::EmbedLinks) @@ -157,7 +157,7 @@ void CheckForSwitchInlineButton(not_null item) { const TLDchatMemberStatusAdministrator &data) { using Flag = ChatAdminRight; const auto bit = [&](const TLbool &check, Flag value) { - return tl_is_true(check) ? value : Flag(0); + return check.v ? value : Flag(0); }; return Flag(0) | bit(data.vcan_manage_chat(), Flag::Other) @@ -1137,10 +1137,10 @@ not_null Session::processUser(const TLuser &user) { } const auto isSelf = (UserId(data.vid().v) == session().userId()); const auto showPhone = !result->isServiceUser() - && !tl_is_true(data.vis_support()) + && !data.vis_support().v && !isSelf - && !tl_is_true(data.vis_contact()) - && !tl_is_true(data.vis_mutual_contact()); + && !data.vis_contact().v + && !data.vis_mutual_contact().v; const auto showPhoneChanged = !result->isServiceUser() && !isSelf && ((showPhone && result->isContact()) @@ -1163,7 +1163,7 @@ not_null Session::processUser(const TLuser &user) { //result->setFlags(UserDataFlag::Inaccessible); //result->setFlags(UserDataFlag::Deleted); result->setBotInfoVersion(-1); // #TODO tdlib - result->setIsContact(tl_is_true(data.vis_contact())); + result->setIsContact(data.vis_contact().v); if (canShareThisContact != result->canShareThisContactFast()) { flags |= UpdateFlag::CanShareContact; } @@ -1225,7 +1225,7 @@ not_null Session::processPeer(const TLchat &dialog) { RestrictionsFromPermissions(data.vpermissions())); data.vvoice_chat().match([&](const TLDvoiceChat &data) { const auto callFlag = ChatDataFlag::CallNotEmpty; - const auto callNotEmpty = tl_is_true(data.vhas_participants()); + const auto callNotEmpty = data.vhas_participants().v; chat->setFlags(chat->flags() // #TODO tdlib | (callNotEmpty ? callFlag : ChatDataFlag(0))); }); @@ -1278,7 +1278,7 @@ not_null Session::processChat(const TLbasicGroup &chat) { | Flag::Left | Flag::Kicked; auto flags = (result->flags() & ~setting) - | (!tl_is_true(data.vis_active()) ? Flag::Deactivated : Flag()); + | (!data.vis_active().v ? Flag::Deactivated : Flag()); result->count = data.vmember_count().v; if (const auto migratedTo = data.vupgraded_to_supergroup_id().v) { const auto channel = this->channel(migratedTo); @@ -1286,11 +1286,11 @@ not_null Session::processChat(const TLbasicGroup &chat) { ApplyMigration(result, channel); } data.vstatus().match([&](const TLDchatMemberStatusCreator &data) { - if (!tl_is_true(data.vis_member())) { + if (!data.vis_member().v) { flags |= Flag::Left; } result->creator = session().userId(); - result->setAdminRights(tl_is_true(data.vis_anonymous()) + result->setAdminRights(data.vis_anonymous().v ? ChatAdminRight::Anonymous : ChatAdminRight()); //data.vcustom_title().v; // #TODO tdlib @@ -1302,7 +1302,7 @@ not_null Session::processChat(const TLbasicGroup &chat) { }, [&](const TLDchatMemberStatusRestricted &data) { LOG(("Tdb Error: Should not get restrictions in basic groups.")); result->setAdminRights(ChatAdminRights()); - if (!tl_is_true(data.vis_member())) { + if (!data.vis_member().v) { flags |= Flag::Left; } }, [&](const TLDchatMemberStatusLeft &data) { @@ -1337,19 +1337,19 @@ not_null Session::processChannel( | Flag::HasLink | Flag::Creator; auto flags = (result->flags() & ~setting) - | (!tl_is_true(data.vis_channel()) ? Flag::Megagroup : Flag()) - | (tl_is_true(data.vis_broadcast_group()) + | (!data.vis_channel().v ? Flag::Megagroup : Flag()) + | (data.vis_broadcast_group().v ? Flag::Gigagroup : Flag()) - | (tl_is_true(data.vis_fake()) ? Flag::Fake : Flag()) - | (tl_is_true(data.vis_scam()) ? Flag::Scam : Flag()) - | (tl_is_true(data.vis_verified()) ? Flag::Verified : Flag()) - | (tl_is_true(data.vis_slow_mode_enabled()) + | (data.vis_fake().v ? Flag::Fake : Flag()) + | (data.vis_scam().v ? Flag::Scam : Flag()) + | (data.vis_verified().v ? Flag::Verified : Flag()) + | (data.vis_slow_mode_enabled().v ? Flag::SlowmodeEnabled : Flag()) - | (tl_is_true(data.vsign_messages()) ? Flag::Signatures : Flag()) - | (tl_is_true(data.vhas_linked_chat()) ? Flag::HasLink : Flag()) - //| (tl_is_true(data.vhas_location()) ? Flag::f_has_geo : Flag()) + | (data.vsign_messages().v ? Flag::Signatures : Flag()) + | (data.vhas_linked_chat().v ? Flag::HasLink : Flag()) + //| (data.vhas_location().v ? Flag::f_has_geo : Flag()) | ((data.vstatus().type() == id_chatMemberStatusCreator) ? Flag::Creator : Flag()); @@ -1357,10 +1357,10 @@ not_null Session::processChannel( result->setName(result->name, data.vusername().v); //data.vrestriction_reason(); // #TODO tdlib data.vstatus().match([&](const TLDchatMemberStatusCreator &data) { - if (!tl_is_true(data.vis_member())) { + if (!data.vis_member().v) { flags |= Flag::Left; } - result->setAdminRights(tl_is_true(data.vis_anonymous()) + result->setAdminRights(data.vis_anonymous().v ? ChatAdminRight::Anonymous : ChatAdminRight()); result->setRestrictions(ChatRestrictionsInfo()); @@ -1368,7 +1368,7 @@ not_null Session::processChannel( }, [&](const TLDchatMemberStatusAdministrator &data) { using Flag = ChatAdminRight; const auto bit = [&](const TLbool &check, Flag value) { - return tl_is_true(check) ? value : Flag(0); + return check.v ? value : Flag(0); }; result->setAdminRights(AdminRightsFromChatMemberStatus(data)); result->setRestrictions(ChatRestrictionsInfo()); @@ -1382,7 +1382,7 @@ not_null Session::processChannel( RestrictionsFromPermissions(data.vpermissions()), data.vrestricted_until_date().v, }); - if (!tl_is_true(data.vis_member())) { + if (!data.vis_member().v) { flags |= Flag::Left; } }, [&](const TLDchatMemberStatusLeft &data) { diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index b1aab17e58d87..86333a5855199 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -575,10 +575,10 @@ void ApplyUserUpdate( //MTPDuserFull::Flag::f_video_calls_available; // #TODO tdlib //update.vsupports_video_calls(); //user->setFullFlags(update.vflags().v); - user->setIsBlocked(tl_is_true(update.vis_blocked())); - user->setCallsStatus(tl_is_true(update.vhas_private_calls()) + user->setIsBlocked(update.vis_blocked().v); + user->setCallsStatus(update.vhas_private_calls().v ? UserData::CallsStatus::Private - : tl_is_true(update.vcan_be_called()) + : update.vcan_be_called().v ? UserData::CallsStatus::Enabled : UserData::CallsStatus::Disabled); user->setAbout(update.vbio().v); diff --git a/Telegram/SourceFiles/intro/intro_password_check.cpp b/Telegram/SourceFiles/intro/intro_password_check.cpp index 9f167f10c0115..8c23366669329 100644 --- a/Telegram/SourceFiles/intro/intro_password_check.cpp +++ b/Telegram/SourceFiles/intro/intro_password_check.cpp @@ -487,7 +487,7 @@ void PasswordCheckWidget::recoverFail(const Error &error) { void PasswordCheckWidget::handleAuthorizationState( const TLauthorizationState &state) { state.match([&](const TLDauthorizationStateWaitPassword &data) { - const auto has = tl_is_true(data.vhas_recovery_email_address()); + const auto has = data.vhas_recovery_email_address().v; if (_passwordState.hasRecovery != has || _passwordState.hint != data.vpassword_hint().v) { getData()->pwdState.hasRecovery = has; diff --git a/Telegram/SourceFiles/intro/intro_step.cpp b/Telegram/SourceFiles/intro/intro_step.cpp index aca6f7a92bc60..89bce25d35dc5 100644 --- a/Telegram/SourceFiles/intro/intro_step.cpp +++ b/Telegram/SourceFiles/intro/intro_step.cpp @@ -599,8 +599,7 @@ void Step::handleAuthorizationState(const TLauthorizationState &state) { fillTerms(data.vterms_of_service()); go(StepType::SignUp); }, [&](const TLDauthorizationStateWaitPassword &data) { - getData()->pwdState.hasRecovery = tl_is_true( - data.vhas_recovery_email_address()); + getData()->pwdState.hasRecovery = data.vhas_recovery_email_address().v; getData()->pwdState.hint = data.vpassword_hint().v; //getData()->pwdState.notEmptyPassport = data.is_has_secure_values(); // #TODO tdlib go(StepType::Password); diff --git a/Telegram/SourceFiles/window/window_lock_widgets.cpp b/Telegram/SourceFiles/window/window_lock_widgets.cpp index a68b416e192fd..5be7ad2d75763 100644 --- a/Telegram/SourceFiles/window/window_lock_widgets.cpp +++ b/Telegram/SourceFiles/window/window_lock_widgets.cpp @@ -198,7 +198,7 @@ TermsLock TermsLock::FromTL( {}, // #TODO legacy std::move(text), (minAge ? std::make_optional(minAge) : std::nullopt), - Tdb::tl_is_true(data.vshow_popup()) + data.vshow_popup().v }; } From 43cf73f6f1500816bc777dbe78bbd3177c73bdac Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 23 Aug 2021 12:37:19 +0300 Subject: [PATCH 016/350] Provide and use generic accessor for single data type. --- Telegram/SourceFiles/tdb/details/tdb_tl_generate.py | 1 + Telegram/SourceFiles/tdb/tdb_sender.h | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Telegram/SourceFiles/tdb/details/tdb_tl_generate.py b/Telegram/SourceFiles/tdb/details/tdb_tl_generate.py index 18624a7d46e0b..e9bda3a9609ec 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_tl_generate.py +++ b/Telegram/SourceFiles/tdb/details/tdb_tl_generate.py @@ -65,5 +65,6 @@ 'builtinIncludeFrom': 'tdb/details/tdb_tl_core_conversion_from.h', 'builtinIncludeTo': 'tdb/details/tdb_tl_core_conversion_to.h', }, + 'optimizeSingleData': True, }) diff --git a/Telegram/SourceFiles/tdb/tdb_sender.h b/Telegram/SourceFiles/tdb/tdb_sender.h index 4364c4f8a7f71..b367bdad2c50e 100644 --- a/Telegram/SourceFiles/tdb/tdb_sender.h +++ b/Telegram/SourceFiles/tdb/tdb_sender.h @@ -59,15 +59,11 @@ class Sender final { Handler, const SingleDataType&, RequestId>) { - result.match([&](const SingleDataType &data) { - onstack(data, requestId); - }); + onstack(result.data(), requestId); } else if constexpr (IsCallable< Handler, const SingleDataType&>) { - result.match([&](const SingleDataType &data) { - onstack(data); - }); + onstack(result.data()); } else { static_assert(false_t(Handler{}), "Bad done handler."); } From 245ac52f4948f0945d18940a5c4615f400d7fd8c Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 29 Sep 2021 15:40:44 +0400 Subject: [PATCH 017/350] Update TDLib. --- Telegram/SourceFiles/data/data_peer_id.cpp | 12 ++++++------ Telegram/build/prepare/prepare.py | 9 ++++----- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Telegram/SourceFiles/data/data_peer_id.cpp b/Telegram/SourceFiles/data/data_peer_id.cpp index 6aacd7b67c1aa..74cfcb2e44b40 100644 --- a/Telegram/SourceFiles/data/data_peer_id.cpp +++ b/Telegram/SourceFiles/data/data_peer_id.cpp @@ -13,10 +13,10 @@ PeerId peerFromTdbChat(Tdb::TLint53 id) noexcept { //constexpr int64 MIN_SECRET_ID = -2002147483648ll; // From TDLib. //constexpr int64 ZERO_SECRET_ID = -2000000000000ll; //constexpr int64 MAX_SECRET_ID = -1997852516353ll; - constexpr int64 MIN_CHANNEL_ID = -1002147483647ll; + constexpr int64 MIN_CHANNEL_ID = -1997852516352ll; constexpr int64 MAX_CHANNEL_ID = -1000000000000ll; - constexpr int64 MIN_CHAT_ID = -2147483647ll; - //constexpr int64 MAX_USER_ID = 2147483647ll; + constexpr int64 MIN_CHAT_ID = -999999999999ll; + //constexpr int64 MAX_USER_ID = 999999999999ll; if (id.v > 0) { return UserId(BareId(id.v)); } else if (id.v < 0 && id.v > MIN_CHAT_ID) { @@ -31,10 +31,10 @@ Tdb::TLint53 peerToTdbChat(PeerId id) noexcept { //constexpr int64 MIN_SECRET_ID = -2002147483648ll; // From TDLib. //constexpr int64 ZERO_SECRET_ID = -2000000000000ll; //constexpr int64 MAX_SECRET_ID = -1997852516353ll; - //constexpr int64 MIN_CHANNEL_ID = -1002147483647ll; + //constexpr int64 MIN_CHANNEL_ID = -1997852516352ll; constexpr int64 MAX_CHANNEL_ID = -1000000000000ll; - //constexpr int64 MIN_CHAT_ID = -2147483647ll; - //constexpr int64 MAX_USER_ID = 2147483647ll; + //constexpr int64 MIN_CHAT_ID = -999999999999ll; + //constexpr int64 MAX_USER_ID = 999999999999ll; if (const auto userId = peerToUser(id)) { return Tdb::tl_int53(int64(userId.bare)); } else if (const auto chatId = peerToChat(id)) { diff --git a/Telegram/build/prepare/prepare.py b/Telegram/build/prepare/prepare.py index fbd60140920a9..48cad9518288b 100644 --- a/Telegram/build/prepare/prepare.py +++ b/Telegram/build/prepare/prepare.py @@ -1572,9 +1572,7 @@ def runStages(): win: git clone https://github.com/tdlib/td.git cd td - git checkout c582ab0bbf -depends:patches/tdlib/*.patch - for /r %%i in (..\\patches\\tdlib\\*) do git apply %%i + git checkout 2ce0be4fe7 SET OPENSSL_DIR=%LIBS_DIR%\\openssl SET OPENSSL_LIBS_DIR=%OPENSSL_DIR%\\out SET ZLIB_DIR=%LIBS_DIR%\\zlib @@ -1583,7 +1581,7 @@ def runStages(): cd out mkdir Debug cd Debug - cmake -A Win32 ^ + cmake -A %WIN32X64% ^ -DOPENSSL_FOUND=1 ^ -DOPENSSL_INCLUDE_DIR=%OPENSSL_DIR%\include ^ -DOPENSSL_CRYPTO_LIBRARY="%OPENSSL_LIBS_DIR%.dbg\libcrypto.lib" ^ @@ -1597,10 +1595,11 @@ def runStages(): -DTD_ENABLE_MULTI_PROCESSOR_COMPILATION=ON ^ ../.. cmake --build . --config Debug --target tdclient +release: cd .. mkdir Release cd Release - cmake -A Win32 ^ + cmake -A %WIN32X64% ^ -DOPENSSL_FOUND=1 ^ -DOPENSSL_INCLUDE_DIR=%OPENSSL_DIR%\include ^ -DOPENSSL_CRYPTO_LIBRARY="%OPENSSL_LIBS_DIR%\libcrypto.lib" ^ From cc41ebe43919e972d51092730a37386400f1787a Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 29 Sep 2021 15:41:21 +0400 Subject: [PATCH 018/350] Use std::thread + std::atomic flag instead of std::jthread. --- Telegram/SourceFiles/tdb/details/tdb_instance.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/tdb/details/tdb_instance.cpp b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp index 2787ef083c3bd..8987cab115295 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_instance.cpp +++ b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp @@ -31,6 +31,8 @@ class Instance::Manager final public: Manager(PrivateTag); + ~Manager(); + [[nodiscard]] static std::shared_ptr Instance(); [[nodiscard]] ClientId createClient(not_null impl); @@ -67,7 +69,8 @@ class Instance::Manager final std::atomic _closingId = 0; crl::semaphore _closing; - std::jthread _thread; + std::thread _thread; + std::atomic _stopRequested = false; }; @@ -148,6 +151,12 @@ Instance::Manager::Manager(PrivateTag) , _thread([=] { loop(); }) { } +Instance::Manager::~Manager() { + Expects(_stopRequested); + + _thread.join(); +} + std::shared_ptr Instance::Manager::Instance() { auto result = ManagerInstance.lock(); if (!result) { @@ -168,7 +177,7 @@ void Instance::Manager::destroyClient(ClientId id) { _clients.remove(id); if (_clients.empty()) { - _thread.request_stop(); + _stopRequested = true; // Force wake. sendToExternal(id, api::make_object()); @@ -205,7 +214,7 @@ void Instance::Manager::sendToExternal( } void Instance::Manager::loop() { - while (!_thread.get_stop_source().stop_requested()) { + while (!_stopRequested) { auto response = _manager->receive(60.); if (!response.object) { continue; From 9ab33da22859306ec211476220e8e432a7f8e30e Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 29 Sep 2021 16:50:42 +0400 Subject: [PATCH 019/350] Wait for all TDLib clients to close before quit. --- .../SourceFiles/tdb/details/tdb_instance.cpp | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/tdb/details/tdb_instance.cpp b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp index 8987cab115295..2778f08cba212 100644 --- a/Telegram/SourceFiles/tdb/details/tdb_instance.cpp +++ b/Telegram/SourceFiles/tdb/details/tdb_instance.cpp @@ -60,8 +60,16 @@ class Instance::Manager final FnMut &&handler); const not_null _manager; + + // Lives on the main thread. base::flat_map> _clients; + // Lives on the main thread before _stopRequested, on _thread - after. + base::flat_set _waiting; + + // Lives on _thread. + base::flat_set _closed; + QMutex _mutex; base::flat_map _callbacks; @@ -153,8 +161,10 @@ Instance::Manager::Manager(PrivateTag) Instance::Manager::~Manager() { Expects(_stopRequested); - - _thread.join(); + Expects(!_thread.joinable()); + Expects(_clients.empty()); + Expects(_waiting.empty()); + Expects(_closed.empty()); } std::shared_ptr Instance::Manager::Instance() { @@ -167,21 +177,31 @@ std::shared_ptr Instance::Manager::Instance() { [[nodiscard]] ClientId Instance::Manager::createClient( not_null impl) { + Expects(!_stopRequested); + const auto result = _manager->create_client_id(); _clients.emplace(result, impl); return result; } void Instance::Manager::destroyClient(ClientId id) { - sendToExternal(id, api::make_object()); + Expects(!_stopRequested); + + LOG(("Tdb Info: Destroying client %1.").arg(id)); + _clients.remove(id); + _waiting.emplace(id); - if (_clients.empty()) { + const auto finishing = _clients.empty(); + if (finishing) { _stopRequested = true; - - // Force wake. - sendToExternal(id, api::make_object()); } + sendToExternal(id, api::make_object()); + if (finishing) { + _thread.join(); + } + + Ensures(!finishing || _waiting.empty()); } RequestId Instance::Manager::allocateRequestId() { @@ -214,11 +234,18 @@ void Instance::Manager::sendToExternal( } void Instance::Manager::loop() { - while (!_stopRequested) { + auto stopping = false; + while (!stopping || !_waiting.empty()) { auto response = _manager->receive(60.); if (!response.object) { continue; } + if (!stopping && _stopRequested) { + stopping = true; + for (const auto clientId : base::take(_closed)) { + _waiting.remove(clientId); + } + } if (response.object->get_id() == api::error::ID) { const auto error = static_cast( response.object.get()); @@ -231,10 +258,19 @@ void Instance::Manager::loop() { const auto requestId = RequestId(response.request_id); const auto object = response.object.get(); if (!requestId) { + auto update = tl_from(object); + if (ClientClosedUpdate(update)) { + LOG(("Tdb Info: Client %1 finished closing.").arg(clientId)); + if (stopping) { + _waiting.remove(clientId); + } else { + _closed.emplace(clientId); + } + } crl::on_main(weak_from_this(), [ this, clientId, - update = tl_from(object) + update = std::move(update) ]() mutable { handleUpdateOnMain(clientId, std::move(update)); }); @@ -264,12 +300,16 @@ void Instance::Manager::loop() { void Instance::Manager::handleUpdateOnMain( ClientId clientId, TLupdate &&update) { + const auto closed = ClientClosedUpdate(update); + if (closed) { + _waiting.remove(clientId); + } const auto i = _clients.find(clientId); if (i == end(_clients)) { return; } const auto instance = i->second; - if (ClientClosedUpdate(update)) { + if (closed) { _clients.erase(i); } instance->handleUpdate(std::move(update)); From 4ae32d3ca0e6f13cd2c3e0f8ada94aa309e8c814 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 30 Sep 2021 21:20:54 +0400 Subject: [PATCH 020/350] Start adding last dialog messages. --- Telegram/SourceFiles/api/api_updates.cpp | 7 +- Telegram/SourceFiles/apiwrap.cpp | 60 +++++++------- Telegram/SourceFiles/data/data_session.cpp | 41 ++++++++++ Telegram/SourceFiles/data/data_session.h | 8 ++ Telegram/SourceFiles/history/history.cpp | 80 +++++++++++++++++++ Telegram/SourceFiles/history/history.h | 26 ++++++ Telegram/SourceFiles/history/history_item.cpp | 2 + Telegram/SourceFiles/history/history_item.h | 11 +++ .../history/history_item_helpers.cpp | 29 +++++++ .../history/history_item_helpers.h | 6 ++ 10 files changed, 238 insertions(+), 32 deletions(-) diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 4063ff900c043..15f1400d472f4 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -2567,12 +2567,9 @@ void Updates::applyUpdate(const TLupdate &update) { }, [&](const TLDupdateNewChat &data) { session().data().processPeer(data.vchat()); }, [&](const TLDupdateChatLastMessage &data) { - //data.vchat_id(); - //data.vlast_message(); - //data.vpositions(); + session().data().applyLastMessage(data); }, [&](const TLDupdateChatPosition &data) { - //data.vchat_id(); - //data.vposition(); + session().data().applyDialogPosition(data); }, [&](const TLDupdateUserFullInfo &data) { const auto user = session().data().user(UserId(data.vuser_id())); data.vuser_full_info().match([&](const TLDuserFullInfo &data) { diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 4162fb4d57dfb..353cf0f502e42 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -116,7 +116,7 @@ constexpr auto kFileLoaderQueueStopTimeout = crl::time(5000); constexpr auto kStickersByEmojiInvalidateTimeout = crl::time(6 * 1000); constexpr auto kNotifySettingSaveTimeout = crl::time(1000); constexpr auto kDialogsFirstLoad = 20; -constexpr auto kDialogsPerPage = 500; +constexpr auto kDialogsPerPage = 100; constexpr auto kStatsSessionKillTimeout = 10 * crl::time(1000); using namespace Tdb; @@ -163,8 +163,7 @@ struct ApiWrap::DialogsLoadState { RequestId pinnedRequestId = 0; bool pinnedReceived = false; - ResolveChatsRequest request; - int64 offsetChatId = 0; + bool firstRequested = false; }; ApiWrap::ApiWrap(not_null session) @@ -866,7 +865,7 @@ void ApiWrap::requestMoreDialogs(Data::Folder *folder) { const auto state = dialogsLoadState(folder); if (!state || !tdb().ready()) { return; - } else if (state->requestId || state->request) { + } else if (state->requestId) { return; } else if (_dialogsLoadBlockedByDate.current()) { return; @@ -934,43 +933,50 @@ void ApiWrap::requestMoreDialogs(Data::Folder *folder) { } #endif - const auto firstLoad = !state->offsetChatId; + const auto firstLoad = !state->firstRequested; const auto loadCount = firstLoad ? kDialogsFirstLoad : kDialogsPerPage; - state->request.send(sender(), TLgetChats( + state->requestId = sender().request(TLloadChats( folder ? tl_chatListArchive() : tl_chatListMain(), tl_int32(loadCount) - ), [=] { - return &dialogsLoadState(folder)->request; - }, [=](const ResolvedChats &result) { + )).done([=] { const auto state = dialogsLoadState(folder); if (!state) { return; } - const auto count = result.count; - if (result.ids.isEmpty()) { - state->listReceived = true; - state->pinnedReceived = true; - dialogsLoadFinish(folder); // may kill 'state'. - } else { - state->offsetChatId = result.ids.back().v; - } - _session->data().processUsers(result.users); - _session->data().processChats(result.chats); - _session->data().processChannels(result.channels); - _session->data().processPeers(result.dialogs); + state->firstRequested = true; + state->requestId = 0; + //const auto count = result.count; + //if (result.ids.isEmpty()) { + // state->listReceived = true; + // state->pinnedReceived = true; + // dialogsLoadFinish(folder); // may kill 'state'. + //} else { + // state->offsetChatId = result.ids.back().v; + //} + //_session->data().processUsers(result.users); + //_session->data().processChats(result.chats); + //_session->data().processChannels(result.channels); + //_session->data().processPeers(result.dialogs); //_session->data().applyDialogs( // folder, // data.vmessages().v, // data.vdialogs().v, // count); - if (!folder - && (!_dialogsLoadState || !_dialogsLoadState->listReceived)) { - refreshDialogsLoadBlocked(); + //if (!folder + // && (!_dialogsLoadState || !_dialogsLoadState->listReceived)) { + // refreshDialogsLoadBlocked(); + //} + //requestMoreDialogsIfNeeded(); + //_session->data().chatsListChanged(folder); + }).fail([=] { + const auto state = dialogsLoadState(folder); + if (!state) { + return; } - requestMoreDialogsIfNeeded(); - _session->data().chatsListChanged(folder); - }); + state->firstRequested = true; + state->requestId = 0; + }).send(); if (!folder) { refreshDialogsLoadBlocked(); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 3277462cea46f..7176d4bcd7411 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -2488,6 +2488,29 @@ void Session::applyDialog( setPinnedFromEntryList(folder, data.is_pinned()); } +void Session::applyLastMessage(const TLDupdateChatLastMessage &data) { + const auto history = this->history(peerFromTdbChat(data.vchat_id())); + for (const auto &position : data.vpositions().v) { + history->applyPosition(position.data()); + } + if (const auto message = data.vlast_message()) { + history->applyLastMessage(*message); + } else { + history->clearLastMessage(); + } +} + +void Session::applyDialogPosition(const TLDupdateChatPosition &data) { + const auto &position = data.vposition().data(); + const auto peerId = peerFromTdbChat(data.vchat_id()); + const auto history = position.vorder().v + ? this->history(peerId).get() + : this->historyLoaded(peerId); + if (history) { + history->applyPosition(position); + } +} + bool Session::pinnedCanPin(not_null thread) const { if (const auto topic = thread->asTopic()) { const auto forum = topic->forum(); @@ -2993,6 +3016,24 @@ HistoryItem *Session::addNewMessage( return result; } +HistoryItem *Session::addNewMessage( + const TLmessage &data, + MessageFlags localFlags, + NewMessageType type) { + const auto peerId = peerFromTdbChat(data.data().vchat_id()); + Assert(peerId != 0); + + const auto result = history(peerId)->addNewMessage( + data.data().vid().v, + data, + localFlags, + type); + if (result && type == NewMessageType::Unread) { + CheckForSwitchInlineButton(result); + } + return result; +} + int Session::unreadBadge() const { return computeUnreadBadge(_chatsList.unreadState()); } diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 53553ee95ea95..3eeefe5b257e0 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -485,6 +485,11 @@ class Session final { MessageFlags localFlags, NewMessageType type); + HistoryItem *addNewMessage( + const Tdb::TLmessage &data, + MessageFlags localFlags, + NewMessageType type); + [[nodiscard]] int unreadBadge() const; [[nodiscard]] bool unreadBadgeMuted() const; [[nodiscard]] int unreadBadgeIgnoreOne(Dialogs::Key key) const; @@ -747,6 +752,9 @@ class Session final { void clearLocalStorage(); + void applyLastMessage(const Tdb::TLDupdateChatLastMessage &data); + void applyDialogPosition(const Tdb::TLDupdateChatPosition &data); + private: using Messages = std::unordered_map>; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 331395a173935..4f59a8c39383f 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -68,6 +68,7 @@ namespace { constexpr auto kNewBlockEachMessage = 50; constexpr auto kSkipCloudDraftsFor = TimeId(2); +using namespace Tdb; using UpdateFlag = Data::HistoryUpdate::Flag; } // namespace @@ -443,6 +444,20 @@ std::vector> History::createItems( return result; } +HistoryItem *History::createItem( + MsgId id, + const TLmessage &message, + MessageFlags localFlags, + bool detachExistingItem) { + if (const auto result = owner().message(peer, id)) { + if (detachExistingItem) { + result->removeMainView(); + } + return result; + } + return makeMessage(id, message.data(), localFlags); +} + not_null History::addNewMessage( MsgId id, const MTPMessage &msg, @@ -460,6 +475,26 @@ not_null History::addNewMessage( return addNewItem(item, unread); } +HistoryItem *History::addNewMessage( + MsgId id, + const TLmessage &msg, + MessageFlags localFlags, + NewMessageType type) { + const auto detachExistingItem = (type == NewMessageType::Unread); + const auto item = createItem(id, msg, localFlags, detachExistingItem); + if (!item) { + return nullptr; + } + if (type == NewMessageType::Existing || item->mainView()) { + return item; + } + const auto unread = (type == NewMessageType::Unread); + if (unread && item->isHistoryEntry()) { + applyMessageChanges(item, msg); + } + return addNewItem(item, unread); +} + not_null History::insertItem( std::unique_ptr item) { Expects(item != nullptr); @@ -1226,6 +1261,19 @@ void History::applyServiceChanges( #endif } +void History::applyMessageChanges( + not_null item, + const TLmessage &data) { + //data.data().vcontent().match(); // #TODO tdlib + //if (data.type() == mtpc_messageService) { + // applyServiceChanges(item, data.c_messageService()); + //} + owner().stickers().checkSavedGif(item); + session().changes().messageUpdated( + item, + Data::MessageUpdate::Flag::NewAdded); +} + void History::mainViewRemoved( not_null block, not_null view) { @@ -2829,6 +2877,38 @@ void History::applyDialog( owner().histories().dialogEntryApplied(this); } +void History::applyPosition(const TLDchatPosition &data) { + const auto pinned = data.vis_pinned().v; + const auto order = data.vorder().v; + if (const auto source = data.vsource()) { + source->match([&](const TLDchatSourceMtprotoProxy &) { + owner().setTopPromoted(this, QString(), QString()); + }, [&](const TLDchatSourcePublicServiceAnnouncement &data) { + owner().setTopPromoted(this, data.vtype().v, data.vtext().v); + }); + } + data.vlist().match([&](const TLDchatListMain &) { + clearFolder(); + }, [&](const TLDchatListArchive &) { + setFolder(owner().folder(Data::Folder::kId)); + }, [&](const TLDchatListFilter &data) { + const auto filterId = data.vchat_filter_id().v; + }); +} + +void History::applyLastMessage(const TLmessage &data) { + const auto &message = data.data(); + const auto id = message.vid().v; + addNewMessage(id, data, MessageFlags(), NewMessageType::Last); + applyDialogTopMessage(id); + owner().histories().dialogEntryApplied(this); +} + +void History::clearLastMessage() { + applyDialogTopMessage(0); + owner().histories().dialogEntryApplied(this); +} + void History::dialogEntryApplied() { if (!lastServerMessageKnown()) { setLastServerMessage(nullptr); diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 2ef89cb460588..23881d494de20 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -16,6 +16,11 @@ For license and copyright information please follow this link: #include "base/flat_set.h" #include "base/flags.h" +namespace Tdb { +class TLDchatPosition; +class TLmessage; +} // namespace Tdb + class History; class HistoryBlock; class HistoryTranslation; @@ -201,6 +206,12 @@ class History final : public Data::Thread { Data::SponsoredFrom from, const TextWithEntities &textWithEntities); // sponsored + HistoryItem *addNewMessage( + MsgId id, + const Tdb::TLmessage &msg, + MessageFlags localFlags, + NewMessageType type); + // Used only internally and for channel admin log. not_null createItem( MsgId id, @@ -210,6 +221,12 @@ class History final : public Data::Thread { std::vector> createItems( const QVector &data); + HistoryItem *createItem( + MsgId id, + const Tdb::TLmessage &message, + MessageFlags localFlags, + bool detachExistingItem); + void addOlderSlice(const QVector &slice); void addNewerSlice(const QVector &slice); @@ -271,6 +288,11 @@ class History final : public Data::Thread { void applyDialogTopMessage(MsgId topMessageId); void applyDialog(Data::Folder *requestFolder, const MTPDdialog &data); void applyPinnedUpdate(const MTPDupdateDialogPinned &data); + + void applyPosition(const Tdb::TLDchatPosition &data); + void applyLastMessage(const Tdb::TLmessage &data); + void clearLastMessage(); + void applyDialogFields( Data::Folder *folder, int unreadCount, @@ -542,6 +564,10 @@ class History final : public Data::Thread { not_null item, const MTPDmessageService &data); + void applyMessageChanges( + not_null item, + const Tdb::TLmessage &original); + // After adding a new history slice check lastMessage / loadedAtBottom. void checkLastMessage(); void setLastMessage(HistoryItem *item); diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index ef3cf5172baa7..a19246d8eeaf8 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -73,6 +73,8 @@ For license and copyright information please follow this link: namespace { +using namespace Tdb; + constexpr auto kNotificationTextLimit = 255; constexpr auto kPinnedMessageTextLimit = 16; diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index a5206bdcc0c39..a5ad836c49c9f 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -15,6 +15,11 @@ For license and copyright information please follow this link: #include +namespace Tdb { +class TLmessage; +class TLDmessage; +} // namespace Tdb + class HiddenSenderInfo; class History; struct HistoryMessageReply; @@ -182,6 +187,12 @@ class HistoryItem final : public RuntimeComposer { HistoryItem(not_null history, not_null story); ~HistoryItem(); + HistoryItem( + not_null history, + MsgId id, + const Tdb::TLDmessage &data, + MessageFlags localFlags); + struct Destroyer { void operator()(HistoryItem *value); }; diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index 15b5d5ad8e4bf..0a8facabc1ddc 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -41,8 +41,12 @@ For license and copyright information please follow this link: #include "ui/item_text_options.h" #include "lang/lang_keys.h" +#include "tdb/tdb_tl_scheme.h" + namespace { +using namespace Tdb; + bool PeerCallKnown(not_null peer) { if (peer->groupCall() != nullptr) { return true; @@ -56,6 +60,31 @@ bool PeerCallKnown(not_null peer) { } // namespace +MessageFlags FlagsFromTdb(const TLDmessage &data) { + using Flag = MessageFlag; + const auto mediaUnread = data.vcontent().match([&]( + const TLDmessageVoiceNote &data) { + return !data.vis_listened().v; + }, [&](const TLDmessageVideoNote &data) { + return !data.vis_viewed().v; + }, [](const auto &) { + return false; + }); + return Flag() + | (data.vis_outgoing().v ? Flag::Outgoing : Flag()) + | (data.vcontains_unread_mention().v ? Flag::MentionsMe : Flag()) + | (mediaUnread ? Flag::MediaIsUnread : Flag()) + //| ((flags & MTP::f_silent) ? Flag::Silent : Flag()) // #TODO tdlib + | (data.vis_channel_post().v ? Flag::Post : Flag()) + //| ((flags & MTP::f_legacy) ? Flag::Legacy : Flag()) // #TODO tdlib + | (data.vis_pinned().v ? Flag::Pinned : Flag()) + //| ((flags & MTP::f_from_id) ? Flag::HasFromId : Flag()) // #TODO tdlib + | (data.vreply_to_message_id().v ? Flag::HasReplyInfo : Flag()) + | (data.vreply_markup() ? Flag::HasReplyMarkup : Flag()) + | (data.vscheduling_state() ? Flag::IsOrWasScheduled : Flag()) // #TODO tdlib was scheduled, but now isn't? + | (data.vinteraction_info() ? Flag::HasViews : Flag()); +} + QString GetErrorTextForSending( not_null peer, SendingErrorRequest request) { diff --git a/Telegram/SourceFiles/history/history_item_helpers.h b/Telegram/SourceFiles/history/history_item_helpers.h index cf1045abd61b9..17274011393b6 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.h +++ b/Telegram/SourceFiles/history/history_item_helpers.h @@ -9,6 +9,10 @@ For license and copyright information please follow this link: class History; +namespace Tdb { +class TLDmessage; +} // namespace Tdb + namespace Api { struct SendOptions; struct SendAction; @@ -23,6 +27,8 @@ namespace Main { class Session; } // namespace Main +[[nodiscard]] MessageFlags FlagsFromTdb(const Tdb::TLDmessage &data); + struct PreparedServiceText { TextWithEntities text; std::vector links; From dc5f1e23a3a24ad2484259a66fa9ad872c033e8b Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 7 Oct 2021 18:39:23 +0400 Subject: [PATCH 021/350] Process all message types from TDLib. --- .../SourceFiles/api/api_text_entities.cpp | 10 ++ Telegram/SourceFiles/api/api_text_entities.h | 4 + Telegram/SourceFiles/apiwrap.cpp | 1 + Telegram/SourceFiles/data/data_location.cpp | 8 ++ Telegram/SourceFiles/data/data_location.h | 6 + .../SourceFiles/data/data_media_types.cpp | 41 ++++++ Telegram/SourceFiles/data/data_media_types.h | 13 ++ Telegram/SourceFiles/data/data_peer_id.cpp | 10 +- Telegram/SourceFiles/data/data_peer_id.h | 3 + Telegram/SourceFiles/history/history_item.cpp | 6 + Telegram/SourceFiles/history/history_item.h | 2 + .../history/history_item_reply_markup.cpp | 131 ++++++++++++++++++ .../history/history_item_reply_markup.h | 32 +++++ 13 files changed, 266 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/api/api_text_entities.cpp b/Telegram/SourceFiles/api/api_text_entities.cpp index 8531f9eef7f03..ef9a252ce1b72 100644 --- a/Telegram/SourceFiles/api/api_text_entities.cpp +++ b/Telegram/SourceFiles/api/api_text_entities.cpp @@ -249,4 +249,14 @@ EntitiesInText EntitiesFromTL( return result; } +TextWithEntities FormattedTextFromTL( + Main::Session *session, + const TLformattedText &text) { + const auto &formatted = text.data(); + return TextWithEntities{ + formatted.vtext().v, + Api::EntitiesFromTL(session, formatted.ventities().v) + }; +} + } // namespace Api diff --git a/Telegram/SourceFiles/api/api_text_entities.h b/Telegram/SourceFiles/api/api_text_entities.h index ca69a55a3ccd4..80c7b96820416 100644 --- a/Telegram/SourceFiles/api/api_text_entities.h +++ b/Telegram/SourceFiles/api/api_text_entities.h @@ -34,4 +34,8 @@ enum class ConvertOption { Main::Session *session, const QVector &entities); +[[nodiscard]] TextWithEntities FormattedTextFromTL( + Main::Session *session, + const Tdb::TLformattedText &text); + } // namespace Api diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 353cf0f502e42..1d02be95e39f2 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -976,6 +976,7 @@ void ApiWrap::requestMoreDialogs(Data::Folder *folder) { } state->firstRequested = true; state->requestId = 0; + state->listReceived = true; }).send(); if (!folder) { diff --git a/Telegram/SourceFiles/data/data_location.cpp b/Telegram/SourceFiles/data/data_location.cpp index c08c6688fd92d..de68cd083d14d 100644 --- a/Telegram/SourceFiles/data/data_location.cpp +++ b/Telegram/SourceFiles/data/data_location.cpp @@ -9,10 +9,13 @@ For license and copyright information please follow this link: #include "ui/image/image.h" #include "data/data_file_origin.h" +#include "tdb/tdb_tl_scheme.h" namespace Data { namespace { +using namespace Tdb; + [[nodiscard]] QString AsString(float64 value) { constexpr auto kPrecision = 6; return QString::number(value, 'f', kPrecision); @@ -26,6 +29,11 @@ LocationPoint::LocationPoint(const MTPDgeoPoint &point) , _access(point.vaccess_hash().v) { } +LocationPoint::LocationPoint(const TLlocation &point) +: _lat(point.data().vlatitude().v) +, _lon(point.data().vlongitude().v) { +} + QString LocationPoint::latAsString() const { return AsString(_lat); } diff --git a/Telegram/SourceFiles/data/data_location.h b/Telegram/SourceFiles/data/data_location.h index 7d9a59b4a76b4..d16d7f50c1018 100644 --- a/Telegram/SourceFiles/data/data_location.h +++ b/Telegram/SourceFiles/data/data_location.h @@ -7,6 +7,10 @@ For license and copyright information please follow this link: */ #pragma once +namespace Tdb { +class TLlocation; +} // namespace Tdb + namespace Data { struct FileOrigin; @@ -16,6 +20,8 @@ class LocationPoint { LocationPoint() = default; explicit LocationPoint(const MTPDgeoPoint &point); + explicit LocationPoint(const Tdb::TLlocation &point); + [[nodiscard]] QString latAsString() const; [[nodiscard]] QString lonAsString() const; [[nodiscard]] MTPGeoPoint toMTP() const; diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index 1132d75c49e73..7ab2b88c2919b 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -72,6 +72,8 @@ For license and copyright information please follow this link: #include "styles/style_chat.h" #include "styles/style_dialogs.h" +#include "tdb/tdb_tl_scheme.h" + namespace Data { namespace { @@ -79,6 +81,8 @@ constexpr auto kFastRevokeRestriction = 24 * 60 * TimeId(60); constexpr auto kMaxPreviewImages = 3; constexpr auto kLoadingStoryPhotoId = PhotoId(0x7FFF'DEAD'FFFF'FFFFULL); +using namespace Tdb; + using ItemPreview = HistoryView::ItemPreview; using ItemPreviewImage = HistoryView::ItemPreviewImage; @@ -315,6 +319,7 @@ TextForMimeData WithCaptionClipboardText( return result; } +#if 0 // mtp Invoice ComputeInvoiceData( not_null item, const MTPDmessageMediaInvoice &data) { @@ -385,6 +390,42 @@ Giveaway ComputeGiveawayData( } return result; } +#endif + +Invoice ComputeInvoiceData( + not_null item, + const TLDmessageInvoice &data) { + return { + .receiptMsgId = data.vreceipt_message_id().v, + .amount = uint64(data.vtotal_amount().v), + .currency = data.vcurrency().v, + .title = TextUtilities::SingleLine(data.vtitle().v), + .description = data.vdescription().v, + .photo = nullptr/*(data.vphoto() + ? item->history()->owner().processPhoto(*data.vphoto()) + : nullptr)*/, + .isTest = data.vis_test().v, + }; +} + +Call ComputeCallData(const TLDmessageCall &call) { + auto result = Call(); + result.finishReason = call.vdiscard_reason().match([]( + const TLDcallDiscardReasonDeclined &) { + return CallFinishReason::Busy; + }, [](const TLDcallDiscardReasonDisconnected &) { + return CallFinishReason::Disconnected; + }, [](const TLDcallDiscardReasonHungUp &) { + return CallFinishReason::Hangup; + }, [](const TLDcallDiscardReasonMissed &) { + return CallFinishReason::Missed; + }, [](const TLDcallDiscardReasonEmpty &) { + return CallFinishReason::Hangup; + }); + result.duration = call.vduration().v; + result.video = call.vis_video().v; + return result; +} Media::Media(not_null parent) : _parent(parent) { } diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index b62cf98259d9b..02d9a964e2c67 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -11,6 +11,11 @@ For license and copyright information please follow this link: #include "data/data_location.h" #include "data/data_wall_paper.h" +namespace Tdb { +class TLDmessageInvoice; +class TLDmessageCall; +} // namespace Tdb + class Image; class History; class HistoryItem; @@ -658,6 +663,7 @@ class MediaGiveaway final : public Media { const QString &attachType, TextForMimeData &&caption); +#if 0 // mtp [[nodiscard]] Invoice ComputeInvoiceData( not_null item, const MTPDmessageMediaInvoice &data); @@ -667,5 +673,12 @@ class MediaGiveaway final : public Media { [[nodiscard]] Giveaway ComputeGiveawayData( not_null item, const MTPDmessageMediaGiveaway &data); +#endif + +[[nodiscard]] Invoice ComputeInvoiceData( + not_null item, + const Tdb::TLDmessageInvoice &data); + +[[nodiscard]] Call ComputeCallData(const Tdb::TLDmessageCall &call); } // namespace Data diff --git a/Telegram/SourceFiles/data/data_peer_id.cpp b/Telegram/SourceFiles/data/data_peer_id.cpp index 74cfcb2e44b40..fc3eccc53cb29 100644 --- a/Telegram/SourceFiles/data/data_peer_id.cpp +++ b/Telegram/SourceFiles/data/data_peer_id.cpp @@ -7,7 +7,7 @@ For license and copyright information please follow this link: */ #include "data/data_peer_id.h" -#include "tdb/details/tdb_tl_core.h" +#include "tdb/tdb_tl_scheme.h" PeerId peerFromTdbChat(Tdb::TLint53 id) noexcept { //constexpr int64 MIN_SECRET_ID = -2002147483648ll; // From TDLib. @@ -45,6 +45,14 @@ Tdb::TLint53 peerToTdbChat(PeerId id) noexcept { return Tdb::tl_int53(0); } +PeerId peerFromSender(const Tdb::TLmessageSender &sender) noexcept { + return sender.match([&](const Tdb::TLDmessageSenderUser &data) { + return peerFromUser(data.vuser_id()); + }, [&](const Tdb::TLDmessageSenderChat &data) { + return peerFromTdbChat(data.vchat_id()); + }); +} + PeerId peerFromMTP(const MTPPeer &peer) { return peer.match([](const MTPDpeerUser &data) { return peerFromUser(data.vuser_id()); diff --git a/Telegram/SourceFiles/data/data_peer_id.h b/Telegram/SourceFiles/data/data_peer_id.h index 9f1d8d8af3f26..9f28c35f7972b 100644 --- a/Telegram/SourceFiles/data/data_peer_id.h +++ b/Telegram/SourceFiles/data/data_peer_id.h @@ -15,6 +15,7 @@ class int64_type; namespace Tdb { using TLint53 = tl::int64_type; +class TLmessageSender; } // namespace Tdb struct PeerIdZeroHelper { @@ -224,6 +225,8 @@ bool operator>=(PeerIdZero, PeerId) = delete; } [[nodiscard]] PeerId peerFromTdbChat(Tdb::TLint53 id) noexcept; +[[nodiscard]] PeerId peerFromSender( + const Tdb::TLmessageSender &sender) noexcept; [[nodiscard]] inline constexpr UserId peerToUser(PeerId id) noexcept { return id.to(); diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index a19246d8eeaf8..22c990d5a1626 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -2803,6 +2803,12 @@ bool HistoryItem::hasExtendedMediaPreview() const { return false; } +void HistoryItem::applyTTL(const TLDmessage &data) { + if (const auto period = data.vttl().v) { + applyTTL(data.vdate().v + period); + } +} + void HistoryItem::sendFailed() { Expects(_flags & MessageFlag::BeingSent); Expects(!(_flags & MessageFlag::SendingFailed)); diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index a5ad836c49c9f..1944b232f1c1f 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -637,6 +637,8 @@ class HistoryItem final : public RuntimeComposer { [[nodiscard]] PeerData *computeDisplayFrom() const; + void applyTTL(const Tdb::TLDmessage &data); + const not_null _history; const not_null _from; mutable PeerData *_displayFrom = nullptr; diff --git a/Telegram/SourceFiles/history/history_item_reply_markup.cpp b/Telegram/SourceFiles/history/history_item_reply_markup.cpp index c15381e92a186..682d1a4d36e1f 100644 --- a/Telegram/SourceFiles/history/history_item_reply_markup.cpp +++ b/Telegram/SourceFiles/history/history_item_reply_markup.cpp @@ -14,6 +14,8 @@ For license and copyright information please follow this link: namespace { +using namespace Tdb; + [[nodiscard]] InlineBots::PeerTypes PeerTypesFromMTP( const MTPvector &types) { using namespace InlineBots; @@ -222,6 +224,90 @@ void HistoryMessageMarkupData::fillRows( } } +template +void HistoryMessageMarkupData::fillRows( + const QVector> &list) { + rows.clear(); + if (list.isEmpty()) { + return; + } + + rows.reserve(list.size()); + for (const auto &buttons : list) { + auto row = std::vector