diff --git a/CMake/TdSetUpCompiler.cmake b/CMake/TdSetUpCompiler.cmake index d168a5960..62013f52a 100644 --- a/CMake/TdSetUpCompiler.cmake +++ b/CMake/TdSetUpCompiler.cmake @@ -134,6 +134,10 @@ function(td_set_up_compiler) if (GCC AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)) add_cxx_compiler_flag("-Wno-maybe-uninitialized") # too much false positives endif() + if (WIN32 AND GCC AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)) + # warns about casts of function pointers returned by GetProcAddress + add_cxx_compiler_flag("-Wno-cast-function-type") + endif() if (GCC AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)) # warns about a lot of "return std::move", which are not redundant for compilers without fix for DR 1579, i.e. GCC 4.9 or clang 3.8 # see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1579 diff --git a/CMake/iOS.cmake b/CMake/iOS.cmake index 4a6b213b8..6df984d88 100644 --- a/CMake/iOS.cmake +++ b/CMake/iOS.cmake @@ -195,15 +195,15 @@ set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS su if (IOS_PLATFORM STREQUAL "OS") set (IOS_ARCH "armv7;armv7s;arm64") elseif (IOS_PLATFORM STREQUAL "SIMULATOR") - set (IOS_ARCH "i386;x86_64") + set (IOS_ARCH "i386;x86_64;arm64") elseif (IOS_PLATFORM STREQUAL "WATCHOS") set (IOS_ARCH "armv7k;arm64_32") elseif (IOS_PLATFORM STREQUAL "WATCHSIMULATOR") - set (IOS_ARCH "i386;x86_64") + set (IOS_ARCH "i386;x86_64;arm64") elseif (IOS_PLATFORM STREQUAL "TVOS") set (IOS_ARCH "arm64") elseif (IOS_PLATFORM STREQUAL "TVSIMULATOR") - set (IOS_ARCH "x86_64") + set (IOS_ARCH "x86_64;arm64") else() message (WARNING "Unknown IOS_PLATFORM=<${IOS_PLATFORM}>") endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 4873e3f90..18c433cb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TDLib VERSION 1.7.6 LANGUAGES CXX C) +project(TDLib VERSION 1.7.7 LANGUAGES CXX C) if (NOT DEFINED CMAKE_MODULE_PATH) set(CMAKE_MODULE_PATH "") @@ -31,6 +31,10 @@ if (POLICY CMP0060) # link libraries by full path cmake_policy(SET CMP0060 NEW) endif() +if (POLICY CMP0074) + # use environment variables to find libraries + cmake_policy(SET CMP0074 NEW) +endif() include(PreventInSourceBuild) prevent_in_source_build() @@ -399,6 +403,7 @@ set(TDLIB_SOURCE td/telegram/SendCodeHelper.cpp td/telegram/SequenceDispatcher.cpp td/telegram/SpecialStickerSetType.cpp + td/telegram/SponsoredMessages.cpp td/telegram/StateManager.cpp td/telegram/StickersManager.cpp td/telegram/StorageManager.cpp @@ -407,6 +412,7 @@ set(TDLIB_SOURCE td/telegram/Td.cpp td/telegram/TdDb.cpp td/telegram/TermsOfService.cpp + td/telegram/ThemeManager.cpp td/telegram/TopDialogManager.cpp td/telegram/UpdatesManager.cpp td/telegram/Venue.cpp @@ -612,6 +618,7 @@ set(TDLIB_SOURCE td/telegram/ServerMessageId.h td/telegram/SetWithPosition.h td/telegram/SpecialStickerSetType.h + td/telegram/SponsoredMessages.h td/telegram/StateManager.h td/telegram/StickerSetId.h td/telegram/StickersManager.h @@ -623,6 +630,7 @@ set(TDLIB_SOURCE td/telegram/TdDb.h td/telegram/TdParameters.h td/telegram/TermsOfService.h + td/telegram/ThemeManager.h td/telegram/TopDialogCategory.h td/telegram/TopDialogManager.h td/telegram/UniqueId.h diff --git a/README.md b/README.md index 66d1882a6..a31e9d02b 100644 --- a/README.md +++ b/README.md @@ -216,7 +216,7 @@ target_link_libraries(YourTarget PRIVATE Td::TdStatic) Or you could install `TDLib` and then reference it in your CMakeLists.txt like this: ``` -find_package(Td 1.7.6 REQUIRED) +find_package(Td 1.7.7 REQUIRED) target_link_libraries(YourTarget PRIVATE Td::TdStatic) ``` See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/tree/master/example/cpp/CMakeLists.txt). diff --git a/SplitSource.php b/SplitSource.php index fdb492b55..c8d860e4a 100644 --- a/SplitSource.php +++ b/SplitSource.php @@ -302,6 +302,7 @@ function split_file($file, $chunks, $undo) { 'secret_chats_manager[_(-][^.]|SecretChatsManager' => 'SecretChatsManager', 'stickers_manager[_(-][^.]|StickersManager' => 'StickersManager', '[>](td_db[(][)]|get_td_db_impl[(])|TdDb[^A-Za-z]' => 'TdDb', + 'theme_manager[_(-][^.]|ThemeManager' => "ThemeManager", 'TopDialogCategory|get_top_dialog_category' => 'TopDialogCategory', 'top_dialog_manager[_(-][^.]|TopDialogManager' => 'TopDialogManager', 'updates_manager[_(-][^.]|UpdatesManager|get_difference[)]|updateSentMessage|dummyUpdate' => 'UpdatesManager', diff --git a/benchmark/bench_misc.cpp b/benchmark/bench_misc.cpp index 21aad77f7..34eda6633 100644 --- a/benchmark/bench_misc.cpp +++ b/benchmark/bench_misc.cpp @@ -6,6 +6,7 @@ // #include "td/utils/benchmark.h" #include "td/utils/common.h" +#include "td/utils/format.h" #include "td/utils/logging.h" #include "td/utils/port/Clocks.h" #include "td/utils/port/EventFd.h" @@ -16,6 +17,7 @@ #include "td/utils/port/thread.h" #include "td/utils/Slice.h" #include "td/utils/SliceBuilder.h" +#include "td/utils/Status.h" #include "td/utils/ThreadSafeCounter.h" #include "td/telegram/telegram_api.h" @@ -30,8 +32,11 @@ #include #endif +#include +#include #include #include +#include class F { td::uint32 ∑ @@ -99,7 +104,7 @@ BENCH(NewObj, "new struct, then delete") { } #if !TD_THREAD_UNSUPPORTED -BENCH(ThreadNew, "new struct, then delete in several threads") { +BENCH(ThreadNew, "new struct, then delete in 2 threads") { NewObjBench a, b; td::thread ta([&] { a.run(n / 2); }); td::thread tb([&] { b.run(n - n / 2); }); @@ -418,8 +423,267 @@ std::atomic AtomicCounterBench::counter_; #endif +class IdDuplicateCheckerOld { + public: + static td::string get_description() { + return "Old"; + } + td::Status check(td::int64 message_id) { + if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS) { + auto oldest_message_id = *saved_message_ids_.begin(); + if (message_id < oldest_message_id) { + return td::Status::Error(2, PSLICE() << "Ignore very old message_id " + << td::tag("oldest message_id", oldest_message_id) + << td::tag("got message_id", message_id)); + } + } + if (saved_message_ids_.count(message_id) != 0) { + return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id)); + } + + saved_message_ids_.insert(message_id); + if (saved_message_ids_.size() > MAX_SAVED_MESSAGE_IDS) { + saved_message_ids_.erase(saved_message_ids_.begin()); + } + return td::Status::OK(); + } + + private: + static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000; + std::set saved_message_ids_; +}; + +template +class IdDuplicateCheckerNew { + public: + static td::string get_description() { + return PSTRING() << "New" << MAX_SAVED_MESSAGE_IDS; + } + td::Status check(td::int64 message_id) { + auto insert_result = saved_message_ids_.insert(message_id); + if (!insert_result.second) { + return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id)); + } + if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) { + auto begin_it = saved_message_ids_.begin(); + bool is_very_old = begin_it == insert_result.first; + saved_message_ids_.erase(begin_it); + if (is_very_old) { + return td::Status::Error(2, PSLICE() << "Ignore very old message_id " + << td::tag("oldest message_id", *saved_message_ids_.begin()) + << td::tag("got message_id", message_id)); + } + } + return td::Status::OK(); + } + + private: + std::set saved_message_ids_; +}; + +class IdDuplicateCheckerNewOther { + public: + static td::string get_description() { + return "NewOther"; + } + td::Status check(td::int64 message_id) { + if (!saved_message_ids_.insert(message_id).second) { + return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id)); + } + if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) { + auto begin_it = saved_message_ids_.begin(); + bool is_very_old = *begin_it == message_id; + saved_message_ids_.erase(begin_it); + if (is_very_old) { + return td::Status::Error(2, PSLICE() << "Ignore very old message_id " + << td::tag("oldest message_id", *saved_message_ids_.begin()) + << td::tag("got message_id", message_id)); + } + } + return td::Status::OK(); + } + + private: + static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000; + std::set saved_message_ids_; +}; + +class IdDuplicateCheckerNewSimple { + public: + static td::string get_description() { + return "NewSimple"; + } + td::Status check(td::int64 message_id) { + auto insert_result = saved_message_ids_.insert(message_id); + if (!insert_result.second) { + return td::Status::Error(1, "Ignore duplicated message_id"); + } + if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) { + auto begin_it = saved_message_ids_.begin(); + bool is_very_old = begin_it == insert_result.first; + saved_message_ids_.erase(begin_it); + if (is_very_old) { + return td::Status::Error(2, "Ignore very old message_id"); + } + } + return td::Status::OK(); + } + + private: + static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000; + std::set saved_message_ids_; +}; + +template +class IdDuplicateCheckerArray { + public: + static td::string get_description() { + return PSTRING() << "Array" << max_size; + } + td::Status check(td::int64 message_id) { + if (end_pos_ == 2 * max_size) { + std::copy_n(&saved_message_ids_[max_size], max_size, &saved_message_ids_[0]); + end_pos_ = max_size; + } + if (end_pos_ == 0 || message_id > saved_message_ids_[end_pos_ - 1]) { + // fast path + saved_message_ids_[end_pos_++] = message_id; + return td::Status::OK(); + } + if (end_pos_ >= max_size && message_id < saved_message_ids_[0]) { + return td::Status::Error(2, PSLICE() << "Ignore very old message_id " + << td::tag("oldest message_id", saved_message_ids_[0]) + << td::tag("got message_id", message_id)); + } + auto it = std::lower_bound(&saved_message_ids_[0], &saved_message_ids_[end_pos_], message_id); + if (*it == message_id) { + return td::Status::Error(1, PSLICE() << "Ignore duplicated message_id " << td::tag("message_id", message_id)); + } + std::copy_backward(it, &saved_message_ids_[end_pos_], &saved_message_ids_[end_pos_ + 1]); + *it = message_id; + ++end_pos_; + return td::Status::OK(); + } + + private: + std::array saved_message_ids_; + std::size_t end_pos_ = 0; +}; + +template +class DuplicateCheckerBench final : public td::Benchmark { + td::string get_description() const final { + return PSTRING() << "DuplicateCheckerBench" << T::get_description(); + } + void run(int n) final { + T checker_; + for (int i = 0; i < n; i++) { + checker_.check(i).ensure(); + } + } +}; + +template +class DuplicateCheckerBenchRepeat final : public td::Benchmark { + td::string get_description() const final { + return PSTRING() << "DuplicateCheckerBenchRepeat" << T::get_description(); + } + void run(int n) final { + T checker_; + for (int i = 0; i < n; i++) { + auto iter = i >> 10; + auto pos = i - (iter << 10); + if (pos < 768) { + if (iter >= 3 && pos == 0) { + auto error = checker_.check((iter - 3) * 768 + pos); + CHECK(error.error().code() == 2); + } + checker_.check(iter * 768 + pos).ensure(); + } else { + checker_.check(iter * 768 + pos - 256).ensure_error(); + } + } + } +}; + +template +class DuplicateCheckerBenchRepeatOnly final : public td::Benchmark { + td::string get_description() const final { + return PSTRING() << "DuplicateCheckerBenchRepeatOnly" << T::get_description(); + } + void run(int n) final { + T checker_; + for (int i = 0; i < n; i++) { + auto result = checker_.check(i & 255); + CHECK(result.is_error() == (i >= 256)); + } + } +}; + +template +class DuplicateCheckerBenchReverse final : public td::Benchmark { + td::string get_description() const final { + return PSTRING() << "DuplicateCheckerBenchReverseAdd" << T::get_description(); + } + void run(int n) final { + T checker_; + for (int i = 0; i < n; i++) { + auto pos = i & 255; + checker_.check(i - pos + (255 - pos)).ensure(); + } + } +}; + +template +class DuplicateCheckerBenchEvenOdd final : public td::Benchmark { + td::string get_description() const final { + return PSTRING() << "DuplicateCheckerBenchEvenOdd" << T::get_description(); + } + void run(int n) final { + T checker_; + for (int i = 0; i < n; i++) { + auto pos = i & 255; + checker_.check(i - pos + (pos * 2) % 256 + (pos * 2) / 256).ensure(); + } + } +}; + int main() { SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG)); + + td::bench(DuplicateCheckerBenchEvenOdd>()); + td::bench(DuplicateCheckerBenchEvenOdd>()); + td::bench(DuplicateCheckerBenchEvenOdd>()); + td::bench(DuplicateCheckerBenchEvenOdd>()); + + td::bench(DuplicateCheckerBenchReverse>()); + td::bench(DuplicateCheckerBenchReverse>()); + td::bench(DuplicateCheckerBenchReverse>()); + td::bench(DuplicateCheckerBenchReverse>()); + + td::bench(DuplicateCheckerBenchRepeatOnly>()); + td::bench(DuplicateCheckerBenchRepeatOnly>()); + td::bench(DuplicateCheckerBenchRepeatOnly>()); + td::bench(DuplicateCheckerBenchRepeatOnly>()); + + td::bench(DuplicateCheckerBenchRepeat()); + td::bench(DuplicateCheckerBenchRepeat>()); + td::bench(DuplicateCheckerBenchRepeat()); + td::bench(DuplicateCheckerBenchRepeat()); + td::bench(DuplicateCheckerBenchRepeat>()); + td::bench(DuplicateCheckerBenchRepeat>()); + td::bench(DuplicateCheckerBenchRepeat>()); + + td::bench(DuplicateCheckerBench()); + td::bench(DuplicateCheckerBench>()); + td::bench(DuplicateCheckerBench()); + td::bench(DuplicateCheckerBench()); + td::bench(DuplicateCheckerBench>()); + td::bench(DuplicateCheckerBench>()); + td::bench(DuplicateCheckerBench>()); + td::bench(DuplicateCheckerBench>()); + td::bench(DuplicateCheckerBench>()); + #if !TD_THREAD_UNSUPPORTED for (int i = 1; i <= 16; i *= 2) { td::bench(ThreadSafeCounterBench(i)); diff --git a/build.html b/build.html index 63f237950..d8b21f267 100644 --- a/build.html +++ b/build.html @@ -501,7 +501,6 @@ function onOptionsChanged() { pre_text.push('Download and install Microsoft Visual Studio. Enable C++' + win10_sdk + ' support while installing.'); pre_text.push('Download and install CMake; choose "Add CMake to the system PATH" option while installing.'); pre_text.push('Download and install Git.'); - pre_text.push('Download and install gperf. Add the path to gperf.exe to the PATH environment variable.'); pre_text.push('Download and unpack PHP. Add the path to php.exe to the PATH environment variable.'); if (target === 'C++/CX') { switch (archiver) { @@ -722,12 +721,12 @@ function onOptionsChanged() { commands.push('cd vcpkg'); commands.push(local + 'bootstrap-vcpkg.bat'); if (target === 'C++/CX') { - commands.push(local + 'vcpkg.exe install openssl-uwp:arm-uwp openssl-uwp:x64-uwp openssl-uwp:x86-uwp zlib:arm-uwp zlib:x64-uwp zlib:x86-uwp'); + commands.push(local + 'vcpkg.exe install gperf openssl-uwp:arm-uwp openssl-uwp:x64-uwp openssl-uwp:x86-uwp zlib:arm-uwp zlib:x64-uwp zlib:x86-uwp'); } else { if (build_64bit) { - commands.push(local + 'vcpkg.exe install openssl:x64-windows zlib:x64-windows'); + commands.push(local + 'vcpkg.exe install gperf openssl:x64-windows zlib:x64-windows'); } else { - commands.push(local + 'vcpkg.exe install openssl:x86-windows zlib:x86-windows'); + commands.push(local + 'vcpkg.exe install gperf openssl:x86-windows zlib:x86-windows'); } } commands.push('cd ..'); diff --git a/example/cpp/CMakeLists.txt b/example/cpp/CMakeLists.txt index bd2462000..17bd2b951 100644 --- a/example/cpp/CMakeLists.txt +++ b/example/cpp/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR) project(TdExample VERSION 1.0 LANGUAGES CXX) -find_package(Td 1.7.6 REQUIRED) +find_package(Td 1.7.7 REQUIRED) add_executable(tdjson_example tdjson_example.cpp) target_link_libraries(tdjson_example PRIVATE Td::TdJson) diff --git a/example/cpp/td_example.cpp b/example/cpp/td_example.cpp index c7304ee60..95ed53eb5 100644 --- a/example/cpp/td_example.cpp +++ b/example/cpp/td_example.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -116,16 +115,15 @@ class TdExample { send_query(std::move(send_message), {}); } else if (action == "c") { std::cout << "Loading chat list..." << std::endl; - send_query(td_api::make_object(nullptr, std::numeric_limits::max(), 0, 20), - [this](Object object) { - if (object->get_id() == td_api::error::ID) { - return; - } - auto chats = td::move_tl_object_as(object); - for (auto chat_id : chats->chat_ids_) { - std::cout << "[chat_id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl; - } - }); + send_query(td_api::make_object(nullptr, 20), [this](Object object) { + if (object->get_id() == td_api::error::ID) { + return; + } + auto chats = td::move_tl_object_as(object); + for (auto chat_id : chats->chat_ids_) { + std::cout << "[chat_id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl; + } + }); } } } diff --git a/example/csharp/TdExample.cs b/example/csharp/TdExample.cs index 93de775d9..3b18f1dd9 100644 --- a/example/csharp/TdExample.cs +++ b/example/csharp/TdExample.cs @@ -237,7 +237,7 @@ namespace TdExample _gotAuthorization.Reset(); _gotAuthorization.WaitOne(); - _client.Send(new TdApi.GetChats(null, Int64.MaxValue, 0, 100), _defaultHandler); // preload main chat list + _client.Send(new TdApi.LoadChats(null, 100), _defaultHandler); // preload main chat list while (_haveAuthorization) { GetCommand(); diff --git a/example/ios/Python-Apple-support.patch b/example/ios/Python-Apple-support.patch index fc7e9ae01..13d56ada8 100644 --- a/example/ios/Python-Apple-support.patch +++ b/example/ios/Python-Apple-support.patch @@ -1,16 +1,86 @@ diff --git a/Makefile b/Makefile -index 695be54..bce31b9 100644 +index 695be54..4efe5e5 100644 --- a/Makefile +++ b/Makefile -@@ -56,9 +56,10 @@ CFLAGS-appletvos.arm64=-fembed-bitcode +@@ -5,10 +5,13 @@ + # - iOS - build everything for iOS + # - tvOS - build everything for tvOS + # - watchOS - build everything for watchOS +-# - OpenSSL-macOS - build OpenSSL for macOS +-# - OpenSSL-iOS - build OpenSSL for iOS +-# - OpenSSL-tvOS - build OpenSSL for tvOS +-# - OpenSSL-watchOS - build OpenSSL for watchOS ++# - OpenSSL-macOS - build OpenSSL for macOS ++# - OpenSSL-iOS - build OpenSSL for iOS ++# - OpenSSL-iOS-simulator - build OpenSSL for iOS-simulator ++# - OpenSSL-tvOS - build OpenSSL for tvOS ++# - OpenSSL-tvOS-simulator - build OpenSSL for tvOS-simulator ++# - OpenSSL-watchOS - build OpenSSL for watchOS ++# - OpenSSL-watchOS-simulator - build OpenSSL for watchOS-simulator + # - BZip2-macOS - build BZip2 for macOS + # - BZip2-iOS - build BZip2 for iOS + # - BZip2-tvOS - build BZip2 for tvOS +@@ -36,31 +39,45 @@ OPENSSL_VERSION=$(OPENSSL_VERSION_NUMBER)$(OPENSSL_REVISION) + BZIP2_VERSION=1.0.6 + + # Supported OS +-OS=macOS iOS tvOS watchOS ++OS=macOS iOS iOS-simulator tvOS tvOS-simulator watchOS watchOS-simulator + + # macOS targets +-TARGETS-macOS=macosx.x86_64 ++TARGETS-macOS=macosx.arm64 macosx.x86_64 ++PYTHON_TARGETS-macOS=macOS + CFLAGS-macOS=-mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) + + # iOS targets +-TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.i386 iphoneos.armv7 iphoneos.armv7s iphoneos.arm64 ++TARGETS-iOS=iphoneos.armv7 iphoneos.armv7s iphoneos.arm64 + CFLAGS-iOS=-mios-version-min=7.0 + CFLAGS-iphoneos.armv7=-fembed-bitcode + CFLAGS-iphoneos.armv7s=-fembed-bitcode + CFLAGS-iphoneos.arm64=-fembed-bitcode + ++# iOS-simulator targets ++TARGETS-iOS-simulator=iphonesimulator.x86_64 iphonesimulator.i386 iphonesimulator.arm64 ++CFLAGS-iOS-simulator=-mios-simulator-version-min=7.0 ++ + # tvOS targets +-TARGETS-tvOS=appletvsimulator.x86_64 appletvos.arm64 ++TARGETS-tvOS=appletvos.arm64 + CFLAGS-tvOS=-mtvos-version-min=9.0 + CFLAGS-appletvos.arm64=-fembed-bitcode PYTHON_CONFIGURE-tvOS=ac_cv_func_sigaltstack=no ++# tvOS-simulator targets ++TARGETS-tvOS-simulator=appletvsimulator.x86_64 appletvsimulator.arm64 ++CFLAGS-tvOS-simulator=-mtvos-simulator-version-min=9.0 ++ # watchOS targets -TARGETS-watchOS=watchsimulator.i386 watchos.armv7k -+TARGETS-watchOS=watchsimulator.i386 watchsimulator.x86_64 watchos.armv7k watchos.arm64_32 ++TARGETS-watchOS=watchos.armv7k watchos.arm64_32 CFLAGS-watchOS=-mwatchos-version-min=4.0 CFLAGS-watchos.armv7k=-fembed-bitcode +CFLAGS-watchos.arm64_32=-fembed-bitcode PYTHON_CONFIGURE-watchOS=ac_cv_func_sigaltstack=no ++# watchOS-simulator targets ++TARGETS-watchOS-simulator=watchsimulator.i386 watchsimulator.x86_64 watchsimulator.arm64 ++CFLAGS-watchOS-simulator=-mwatchos-simulator-version-min=4.0 ++ # override machine types for arm64 + MACHINE_DETAILED-arm64=aarch64 + MACHINE_SIMPLE-arm64=arm +@@ -194,9 +211,11 @@ endif + + # Configure the build + ifeq ($2,macOS) ++ # Patch openssl-darwin-arm64 ++ cd $$(OPENSSL_DIR-$1) && git apply ../../../../openssl-1.0.2n-darwin-arm64.patch + cd $$(OPENSSL_DIR-$1) && \ + CC="$$(CC-$1)" MACOSX_DEPLOYMENT_TARGET=$$(MACOSX_DEPLOYMENT_TARGET) \ +- ./Configure darwin64-x86_64-cc --openssldir=$(PROJECT_DIR)/build/$2/openssl ++ ./Configure darwin64-$$(ARCH-$1)-cc --openssldir=$(PROJECT_DIR)/build/$2/openssl + else + cd $$(OPENSSL_DIR-$1) && \ + CC="$$(CC-$1)" \ diff --git a/example/ios/README.md b/example/ios/README.md index bfdcacb04..e8aa403fc 100644 --- a/example/ios/README.md +++ b/example/ios/README.md @@ -26,8 +26,8 @@ cmake --build . --target prepare_cross_compiling cd /example/ios ./build-openssl.sh ``` -Here we use scripts from [Python Apple support](https://github.com/pybee/Python-Apple-support), but any other OpenSSL builds should work too. -[Python Apple support](https://github.com/pybee/Python-Apple-support) has known problems with spaces in the path to the current directory, so +Here we use scripts from [Python Apple support](https://github.com/beeware/Python-Apple-support), but any other OpenSSL builds should work too. +[Python Apple support](https://github.com/beeware/Python-Apple-support) has known problems with spaces in the path to the current directory, so you need to ensure that there is no spaces in the path. Built libraries should be stored in `third_party/openssl/`, because the next script will rely on this location. * Build TDLib for iOS, watchOS, tvOS and macOS: @@ -36,7 +36,7 @@ cd /example/ios ./build.sh ``` This may take a while, because TDLib will be built about 10 times. -Resulting library for iOS will work on any architecture (armv7, armv7s, arm64) and even on a simulator. +Resulting library for iOS will work on any architecture (armv7, armv7s, arm64) and even on a simulator (Intel, Apple Silicon). We use [CMake/iOS.cmake](https://github.com/tdlib/td/blob/master/CMake/iOS.cmake) toolchain, other toolchains may work too. Built libraries will be stored in `tdjson` directory. diff --git a/example/ios/build-openssl.sh b/example/ios/build-openssl.sh index 3477530d6..ce489e717 100755 --- a/example/ios/build-openssl.sh +++ b/example/ios/build-openssl.sh @@ -1,6 +1,6 @@ #!/bin/sh -git clone https://github.com/pybee/Python-Apple-support +git clone https://github.com/beeware/Python-Apple-support cd Python-Apple-support git checkout 60b990128d5f1f04c336ff66594574515ab56604 git apply ../Python-Apple-support.patch @@ -8,17 +8,29 @@ cd .. #TODO: change openssl version platforms="macOS iOS watchOS tvOS" -#platforms="watchOS" + for platform in $platforms; do - echo $platform - cd Python-Apple-support - #NB: -j will fail - make OpenSSL-$platform - cd .. - rm -rf third_party/openssl/$platform - mkdir -p third_party/openssl/$platform/lib - cp ./Python-Apple-support/build/$platform/libcrypto.a third_party/openssl/$platform/lib/ - cp ./Python-Apple-support/build/$platform/libssl.a third_party/openssl/$platform/lib/ - cp -r ./Python-Apple-support/build/$platform/Support/OpenSSL/Headers/ third_party/openssl/$platform/include + if [[ $platform = "macOS" ]]; then + simulators="0" + else + simulators="0 1" + fi + + for simulator in $simulators; + do + if [[ $simulator = "1" ]]; then + platform="${platform}-simulator" + fi + echo $platform + cd Python-Apple-support + #NB: -j will fail + make OpenSSL-$platform + cd .. + rm -rf third_party/openssl/$platform + mkdir -p third_party/openssl/$platform/lib + cp ./Python-Apple-support/build/$platform/libcrypto.a third_party/openssl/$platform/lib/ + cp ./Python-Apple-support/build/$platform/libssl.a third_party/openssl/$platform/lib/ + cp -r ./Python-Apple-support/build/$platform/Support/OpenSSL/Headers/ third_party/openssl/$platform/include + done done diff --git a/example/ios/build.sh b/example/ios/build.sh index 34bfe58ea..e554b5b18 100755 --- a/example/ios/build.sh +++ b/example/ios/build.sh @@ -5,34 +5,45 @@ rm -rf build mkdir -p build cd build -platforms="macOS iOS watchOS tvOS" -#platforms="watchOS" -for platform in $platforms; -do - echo "Platform = ${platform} Simulator = ${simulator}" - openssl_path=$(grealpath ../third_party/openssl/${platform}) +set_cmake_options () { + # Set CMAKE options depending on platform passed $1 + openssl_path=$(grealpath ../third_party/openssl/$1) echo "OpenSSL path = ${openssl_path}" openssl_crypto_library="${openssl_path}/lib/libcrypto.a" openssl_ssl_library="${openssl_path}/lib/libssl.a" + options="" options="$options -DOPENSSL_FOUND=1" options="$options -DOPENSSL_CRYPTO_LIBRARY=${openssl_crypto_library}" options="$options -DOPENSSL_SSL_LIBRARY=${openssl_ssl_library}" options="$options -DOPENSSL_INCLUDE_DIR=${openssl_path}/include" options="$options -DOPENSSL_LIBRARIES=${openssl_crypto_library};${openssl_ssl_library}" options="$options -DCMAKE_BUILD_TYPE=Release" +} + +platforms="macOS iOS watchOS tvOS" +#platforms="watchOS" +for platform in $platforms; +do + echo "Platform = ${platform}" if [[ $platform = "macOS" ]]; then + set_cmake_options $platform build="build-${platform}" install="install-${platform}" rm -rf $build mkdir -p $build mkdir -p $install cd $build - cmake $td_path $options -DCMAKE_INSTALL_PREFIX=../${install} + cmake $td_path $options -DCMAKE_INSTALL_PREFIX=../${install} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" make -j3 install || exit cd .. mkdir -p $platform cp $build/libtdjson.dylib $platform/libtdjson.dylib install_name_tool -id @rpath/libtdjson.dylib $platform/libtdjson.dylib + + mkdir -p ../tdjson/${platform}/include + rsync --recursive ${install}/include/ ../tdjson/${platform}/include/ + mkdir -p ../tdjson/${platform}/lib + cp ${platform}/libtdjson.dylib ../tdjson/${platform}/lib/ else simulators="0 1" for simulator in $simulators; @@ -42,9 +53,15 @@ do if [[ $simulator = "1" ]]; then build="${build}-simulator" install="${install}-simulator" + platform_path="${platform}-simulator" ios_platform="SIMULATOR" + lib="${install}/lib/libtdjson.dylib" + set_cmake_options ${platform_path} else + platform_path=${platform} ios_platform="OS" + lib="${install}/lib/libtdjson.dylib" + set_cmake_options ${platform_path} fi watchos="" if [[ $platform = "watchOS" ]]; then @@ -62,16 +79,29 @@ do cmake $td_path $options $watchos -DIOS_PLATFORM=${ios_platform} -DCMAKE_TOOLCHAIN_FILE=${td_path}/CMake/iOS.cmake -DCMAKE_INSTALL_PREFIX=../${install} make -j3 install || exit cd .. + + install_name_tool -id @rpath/libtdjson.dylib $lib + + mkdir -p ../tdjson/${platform_path}/include + rsync --recursive ${install}/include/ ../tdjson/${platform_path}/include/ + mkdir -p ../tdjson/${platform_path}/lib + cp ${lib} ../tdjson/${platform_path}/lib/ done - lib="install-${platform}/lib/libtdjson.dylib" - lib_simulator="install-${platform}-simulator/lib/libtdjson.dylib" - mkdir -p $platform - lipo -create $lib $lib_simulator -o $platform/libtdjson.dylib - install_name_tool -id @rpath/libtdjson.dylib $platform/libtdjson.dylib fi - mkdir -p ../tdjson/$platform/include - rsync --recursive ${install}/include/ ../tdjson/${platform}/include/ - mkdir -p ../tdjson/$platform/lib - cp $platform/libtdjson.dylib ../tdjson/$platform/lib/ done + +produced_dylibs=(install-*/lib/libtdjson.dylib) +xcodebuild_frameworks=() + +for dylib in "${produced_dylibs[@]}"; +do + xcodebuild_frameworks+=(-library $(grealpath "${dylib}")) +done + +# Make xcframework +xcodebuild -create-xcframework \ + "${xcodebuild_frameworks[@]}" \ + -output "libtdjson.xcframework" + +rsync --recursive libtdjson.xcframework ../tdjson/ \ No newline at end of file diff --git a/example/ios/openssl-1.0.2n-darwin-arm64.patch b/example/ios/openssl-1.0.2n-darwin-arm64.patch new file mode 100644 index 000000000..5239d94c3 --- /dev/null +++ b/example/ios/openssl-1.0.2n-darwin-arm64.patch @@ -0,0 +1,12 @@ +--- Configure 2019-12-20 14:02:41.000000000 +0100 ++++ Configure 2020-11-22 16:23:13.000000000 +0100 +@@ -650,7 +650,9 @@ + "darwin-i386-cc","cc:-arch i386 -O3 -fomit-frame-pointer -DL_ENDIAN::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:BN_LLONG RC4_INT RC4_CHUNK DES_UNROLL BF_PTR:".eval{my $asm=$x86_asm;$asm=~s/cast\-586\.o//;$asm}.":macosx:dlfcn:darwin-shared:-fPIC -fno-common:-arch i386 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", + "debug-darwin-i386-cc","cc:-arch i386 -g3 -DL_ENDIAN::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:BN_LLONG RC4_INT RC4_CHUNK DES_UNROLL BF_PTR:${x86_asm}:macosx:dlfcn:darwin-shared:-fPIC -fno-common:-arch i386 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", + "darwin64-x86_64-cc","cc:-arch x86_64 -O3 -DL_ENDIAN -Wall::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:".eval{my $asm=$x86_64_asm;$asm=~s/rc4\-[^:]+//;$asm}.":macosx:dlfcn:darwin-shared:-fPIC -fno-common:-arch x86_64 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", ++"darwin64-arm64-cc","cc:-arch arm64 -O3 -DL_ENDIAN -Wall::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${no_asm}:dlfcn:darwin-shared:-fPIC -fno-common:-arch arm64 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", + "debug-darwin64-x86_64-cc","cc:-arch x86_64 -ggdb -g2 -O0 -DL_ENDIAN -Wall::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:".eval{my $asm=$x86_64_asm;$asm=~s/rc4\-[^:]+//;$asm}.":macosx:dlfcn:darwin-shared:-fPIC -fno-common:-arch x86_64 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", ++"debug-darwin64-arm64-cc","cc:-arch arm64 -ggdb -g2 -O0 -DL_ENDIAN -Wall::-D_REENTRANT:MACOSX:-Wl,-search_paths_first%:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${no_asm}:dlfcn:darwin-shared:-fPIC -fno-common:-arch arm64 -dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", + "debug-darwin-ppc-cc","cc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -DB_ENDIAN -g -Wall -O::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${ppc32_asm}:osx32:dlfcn:darwin-shared:-fPIC:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", + # iPhoneOS/iOS + "iphoneos-cross","llvm-gcc:-O3 -isysroot \$(CROSS_TOP)/SDKs/\$(CROSS_SDK) -fomit-frame-pointer -fno-common::-D_REENTRANT:macOS:-Wl,-search_paths_first%:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}:dlfcn:darwin-shared:-fPIC -fno-common:-dynamiclib:.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib", diff --git a/example/java/CMakeLists.txt b/example/java/CMakeLists.txt index 057c8eca9..6a03776b2 100644 --- a/example/java/CMakeLists.txt +++ b/example/java/CMakeLists.txt @@ -1,11 +1,25 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if (POLICY CMP0065) + # do not export symbols from executables + # affects compiler checks in project(), so must be set before it + cmake_policy(SET CMP0065 NEW) +endif() + project(TdJavaExample VERSION 1.0 LANGUAGES CXX) if (POLICY CMP0054) # do not expand quoted arguments cmake_policy(SET CMP0054 NEW) endif() +if (POLICY CMP0060) + # link libraries by full path + cmake_policy(SET CMP0060 NEW) +endif() +if (POLICY CMP0074) + # use environment variables to find libraries + cmake_policy(SET CMP0074 NEW) +endif() find_package(Td REQUIRED) diff --git a/example/java/org/drinkless/tdlib/example/Example.java b/example/java/org/drinkless/tdlib/example/Example.java index 804cf5df4..72569bafc 100644 --- a/example/java/org/drinkless/tdlib/example/Example.java +++ b/example/java/org/drinkless/tdlib/example/Example.java @@ -249,27 +249,20 @@ public final class Example { synchronized (mainChatList) { if (!haveFullMainChatList && limit > mainChatList.size()) { // send GetChats request if there are some unknown chats and have not enough known chats - long offsetOrder = Long.MAX_VALUE; - long offsetChatId = 0; - if (!mainChatList.isEmpty()) { - OrderedChat last = mainChatList.last(); - offsetOrder = last.position.order; - offsetChatId = last.chatId; - } - client.send(new TdApi.GetChats(new TdApi.ChatListMain(), offsetOrder, offsetChatId, limit - mainChatList.size()), new Client.ResultHandler() { + client.send(new TdApi.LoadChats(new TdApi.ChatListMain(), limit - mainChatList.size()), new Client.ResultHandler() { @Override public void onResult(TdApi.Object object) { switch (object.getConstructor()) { case TdApi.Error.CONSTRUCTOR: - System.err.println("Receive an error for GetChats:" + newLine + object); - break; - case TdApi.Chats.CONSTRUCTOR: - long[] chatIds = ((TdApi.Chats) object).chatIds; - if (chatIds.length == 0) { + if (((TdApi.Error) object).code == 404) { synchronized (mainChatList) { haveFullMainChatList = true; } + } else { + System.err.println("Receive an error for GetChats:" + newLine + object); } + break; + case TdApi.Ok.CONSTRUCTOR: // chats had already been received through updates, let's retry request getMainChatList(limit); break; diff --git a/example/uwp/extension.vsixmanifest b/example/uwp/extension.vsixmanifest index 028b129c2..8e220172c 100644 --- a/example/uwp/extension.vsixmanifest +++ b/example/uwp/extension.vsixmanifest @@ -1,6 +1,6 @@ - + TDLib for Universal Windows Platform TDLib is a library for building Telegram clients https://core.telegram.org/tdlib diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 03dcbae08..58eb15af7 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -801,6 +801,14 @@ messages total_count:int32 messages:vector = Messages; foundMessages total_count:int32 messages:vector next_offset:string = FoundMessages; +//@description Describes a sponsored message @id Unique sponsored message identifier @sponsor_chat_id Chat identifier +//@start_parameter Parameter for the bot start message if the sponsored chat is a chat with a bot @content Content of the message +sponsoredMessage id:bytes sponsor_chat_id:int53 start_parameter:string content:MessageContent = SponsoredMessage; + +//@description Contains a list of sponsored messages @messages List of sponsored messages +sponsoredMessages messages:vector = SponsoredMessages; + + //@class NotificationSettingsScope @description Describes the types of chats to which notification settings are relevant //@description Notification settings applied to all private and secret chats when the corresponding chat setting has a default value @@ -942,12 +950,13 @@ voiceChat group_call_id:int32 has_participants:Bool default_participant_id:Messa //@unread_mention_count Number of unread messages with a mention/reply in the chat //@notification_settings Notification settings for this chat //@message_ttl_setting Current message Time To Live setting (self-destruct timer) for the chat; 0 if not defined. TTL is counted from the time message or its content is viewed in secret chats and from the send date in other chats +//@theme_name If non-empty, name of the theme set for the chat //@action_bar Describes actions which should be possible to do through a chat action bar; may be null //@voice_chat Contains information about voice chat of the chat //@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat //@draft_message A draft of a message in the chat; may be null //@client_data Contains application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used -chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 action_bar:ChatActionBar voice_chat:voiceChat reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; +chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 theme_name:string action_bar:ChatActionBar voice_chat:voiceChat reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; //@description Represents a list of chats @total_count Approximate total count of chats found @chat_ids List of chat identifiers chats total_count:int32 chat_ids:vector = Chats; @@ -1078,9 +1087,10 @@ loginUrlInfoRequestConfirmation url:string domain:string bot_user_id:int32 reque //@chat_id Identifier of the chat to which the message thread belongs //@message_thread_id Message thread identifier, unique within the chat //@reply_info Contains information about the message thread +//@unread_message_count Approximate number of unread messages in the message thread //@messages The messages from which the thread starts. The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id) //@draft_message A draft of a message in the message thread; may be null -messageThreadInfo chat_id:int53 message_thread_id:int53 reply_info:messageReplyInfo messages:vector draft_message:draftMessage = MessageThreadInfo; +messageThreadInfo chat_id:int53 message_thread_id:int53 reply_info:messageReplyInfo unread_message_count:int32 messages:vector draft_message:draftMessage = MessageThreadInfo; //@class RichText @description Describes a text object inside an instant-view web page @@ -1316,7 +1326,7 @@ countries countries:vector = Countries; //@description Contains information about a phone number //@country Information about the country to which the phone number belongs; may be null //@country_calling_code The part of the phone number denoting country calling code or its part -//@formatted_phone_number The phone number without country calling code formatted accordingly to local rules +//@formatted_phone_number The phone number without country calling code formatted accordingly to local rules. Expected digits are returned as '-', but even more digits might be entered by the user phoneNumberInfo country:countryInfo country_calling_code:string formatted_phone_number:string = PhoneNumberInfo; @@ -1395,7 +1405,7 @@ paymentForm id:int64 invoice:invoice url:string seller_bot_user_id:int32 payment //@description Contains a temporary identifier of validated order information, which is stored for one hour. Also contains the available shipping options @order_info_id Temporary identifier of the order information @shipping_options Available shipping options validatedOrderInfo order_info_id:string shipping_options:vector = ValidatedOrderInfo; -//@description Contains the result of a payment request @success True, if the payment request was successful; otherwise the verification_url will be not empty @verification_url URL for additional payment credentials verification +//@description Contains the result of a payment request @success True, if the payment request was successful; otherwise the verification_url will be non-empty @verification_url URL for additional payment credentials verification paymentResult success:Bool verification_url:string = PaymentResult; //@description Contains information about a successful payment @@ -1469,7 +1479,7 @@ date day:int32 month:int32 year:int32 = Date; personalDetails first_name:string middle_name:string last_name:string native_first_name:string native_middle_name:string native_last_name:string birthdate:date gender:string country_code:string residence_country_code:string = PersonalDetails; //@description An identity document @number Document number; 1-24 characters @expiry_date Document expiry date; may be null @front_side Front side of the document -//@reverse_side Reverse side of the document; only for driver license and identity card @selfie Selfie with the document; may be null @translation List of files containing a certified English translation of the document +//@reverse_side Reverse side of the document; only for driver license and identity card; may be null @selfie Selfie with the document; may be null @translation List of files containing a certified English translation of the document identityDocument number:string expiry_date:date front_side:datedFile reverse_side:datedFile selfie:datedFile translation:vector = IdentityDocument; //@description An identity document to be saved to Telegram Passport @number Document number; 1-24 characters @expiry_date Document expiry date, if available @front_side Front side of the document @@ -1780,6 +1790,9 @@ messagePinMessage message_id:int53 = MessageContent; //@description A screenshot of a message in the chat has been taken messageScreenshotTaken = MessageContent; +//@description A theme in the chat has been changed @theme_name If non-empty, name of the new theme set for the chat. Otherwise theme was deleted in the chat +messageChatSetTheme theme_name:string = MessageContent; + //@description The TTL (Time To Live) setting for messages in the chat has been changed @ttl New message TTL setting messageChatSetTtl ttl:int32 = MessageContent; @@ -2032,28 +2045,43 @@ searchMessagesFilterPinned = SearchMessagesFilter; //@description The user is typing a message chatActionTyping = ChatAction; + //@description The user is recording a video chatActionRecordingVideo = ChatAction; + //@description The user is uploading a video @progress Upload progress, as a percentage chatActionUploadingVideo progress:int32 = ChatAction; + //@description The user is recording a voice note chatActionRecordingVoiceNote = ChatAction; + //@description The user is uploading a voice note @progress Upload progress, as a percentage chatActionUploadingVoiceNote progress:int32 = ChatAction; + //@description The user is uploading a photo @progress Upload progress, as a percentage chatActionUploadingPhoto progress:int32 = ChatAction; + //@description The user is uploading a document @progress Upload progress, as a percentage chatActionUploadingDocument progress:int32 = ChatAction; + +//@description The user is picking a sticker to send +chatActionChoosingSticker = ChatAction; + //@description The user is picking a location or venue to send chatActionChoosingLocation = ChatAction; + //@description The user is picking a contact to send chatActionChoosingContact = ChatAction; + //@description The user has started to play a game chatActionStartPlayingGame = ChatAction; + //@description The user is recording a video note chatActionRecordingVideoNote = ChatAction; + //@description The user is uploading a video note @progress Upload progress, as a percentage chatActionUploadingVideoNote progress:int32 = ChatAction; + //@description The user has canceled the previous action chatActionCancel = ChatAction; @@ -2173,6 +2201,18 @@ callStateDiscarded reason:CallDiscardReason need_rating:Bool need_debug_informat callStateError error:error = CallState; +//@class GroupCallVideoQuality @description Describes the quality of a group call video + +//@description The worst available video quality +groupCallVideoQualityThumbnail = GroupCallVideoQuality; + +//@description The medium video quality +groupCallVideoQualityMedium = GroupCallVideoQuality; + +//@description The best available video quality +groupCallVideoQualityFull = GroupCallVideoQuality; + + //@description Describes a recently speaking participant in a group call @participant_id Group call participant identifier @is_speaking True, is the user has spoken recently groupCallRecentSpeaker participant_id:MessageSender is_speaking:Bool = GroupCallRecentSpeaker; @@ -2194,8 +2234,9 @@ groupCallRecentSpeaker participant_id:MessageSender is_speaking:Bool = GroupCall //@mute_new_participants True, if only group call administrators can unmute new participants //@can_change_mute_new_participants True, if the current user can enable or disable mute_new_participants setting //@record_duration Duration of the ongoing group call recording, in seconds; 0 if none. An updateGroupCall update is not triggered when value of this field changes, but the same recording goes on +//@is_video_recorded True, if a video file is being recorded for the call //@duration Call duration, in seconds; for ended calls only -groupCall id:int32 title:string scheduled_start_date:int32 enabled_start_notification:Bool is_active:Bool is_joined:Bool need_rejoin:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector is_my_video_enabled:Bool is_my_video_paused:Bool can_enable_video:Bool mute_new_participants:Bool can_change_mute_new_participants:Bool record_duration:int32 duration:int32 = GroupCall; +groupCall id:int32 title:string scheduled_start_date:int32 enabled_start_notification:Bool is_active:Bool is_joined:Bool need_rejoin:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector is_my_video_enabled:Bool is_my_video_paused:Bool can_enable_video:Bool mute_new_participants:Bool can_change_mute_new_participants:Bool record_duration:int32 is_video_recorded:Bool duration:int32 = GroupCall; //@description Describes a group of video synchronization source identifiers @semantics The semantics of sources, one of "SIM" or "FID" @source_ids The list of synchronization source identifiers groupCallVideoSourceGroup semantics:string source_ids:vector = GroupCallVideoSourceGroup; @@ -2491,6 +2532,9 @@ chatEventUsernameChanged old_username:string new_username:string = ChatEventActi //@description The chat photo was changed @old_photo Previous chat photo value; may be null @new_photo New chat photo value; may be null chatEventPhotoChanged old_photo:chatPhoto new_photo:chatPhoto = ChatEventAction; +//@description The chat theme was changed @old_theme_name Previous chat theme name; empty if none @new_theme_name New chat theme name; empty if none +chatEventThemeChanged old_theme_name:string new_theme_name:string = ChatEventAction; + //@description The can_invite_users permission of a supergroup chat was toggled @can_invite_users New value of can_invite_users permission chatEventInvitesToggled can_invite_users:Bool = ChatEventAction; @@ -2689,6 +2733,24 @@ inputBackgroundLocal background:InputFile = InputBackground; inputBackgroundRemote background_id:int64 = InputBackground; +//@description Describes theme settings +//@accent_color Theme accent color in ARGB format +//@background The background to be used in chats; may be null +//@message_fill The fill to be used as a background for outgoing messages +//@animate_message_fill If true, the freeform gradient fill needs to be animated on every sent message +themeSettings accent_color:int32 background:background message_fill:BackgroundFill animate_message_fill:Bool = ThemeSettings; + + +//@description Describes a chat theme +//@name Theme name +//@light_settings Theme settings for a light chat theme +//@dark_settings Theme settings for a dark chat theme +chatTheme name:string light_settings:themeSettings dark_settings:themeSettings = ChatTheme; + +//@description Contains a list of chat themes @chat_themes A list of chat themes +chatThemes chat_themes:vector = ChatThemes; + + //@description Contains a list of hashtags @hashtags A list of hashtags hashtags hashtags:vector = Hashtags; @@ -2831,6 +2893,9 @@ pushMessageContentChatChangePhoto = PushMessageContent; //@description A chat title was edited @title New chat title pushMessageContentChatChangeTitle title:string = PushMessageContent; +//@description A chat theme was edited @theme_name Name of the new chat theme +pushMessageContentChatChangeTheme theme_name:string = PushMessageContent; + //@description A chat member was deleted @member_name Name of the deleted member @is_current_user True, if the current user was deleted from the group //@is_left True, if the user has left the group themselves pushMessageContentChatDeleteMember member_name:string is_current_user:Bool is_left:Bool = PushMessageContent; @@ -3634,6 +3699,9 @@ updateChatMessageTtlSetting chat_id:int53 message_ttl_setting:int32 = Update; //@description The chat action bar was changed @chat_id Chat identifier @action_bar The new value of the action bar; may be null updateChatActionBar chat_id:int53 action_bar:ChatActionBar = Update; +//@description The chat theme was changed @chat_id Chat identifier @theme_name The new name of the chat theme; may be empty if none +updateChatTheme chat_id:int53 theme_name:string = Update; + //@description The default chat reply markup was changed. Can occur because new messages with reply markup were received or because an old reply markup was hidden by the user //@chat_id Chat identifier @reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat updateChatReplyMarkup chat_id:int53 reply_markup_message_id:int53 = Update; @@ -4049,12 +4117,13 @@ getChannelDifference channel_difference_id:int64 = Ok; //@remote_file_id Remote identifier of the file to get @file_type File type, if known getRemoteFile remote_file_id:string file_type:FileType = File; -//@description Returns an ordered list of chats in a chat list. Chats are sorted by the pair (chat.position.order, chat.id) in descending order. (For example, to get a list of chats from the beginning, the offset_order should be equal to a biggest signed 64-bit number 9223372036854775807 == 2^63 - 1). -//-For optimal performance, the number of returned chats is chosen by TDLib -//@chat_list The chat list in which to return chats -//@offset_order Chat order to return chats from @offset_chat_id Chat identifier to return chats from -//@limit The maximum number of chats to be returned. For optimal performance, the number of returned chats is chosen by TDLib and can be smaller than the specified limit, even if the end of the list is not reached -getChats chat_list:ChatList offset_order:int64 offset_chat_id:int53 limit:int32 = Chats; +//@description Loads more chats from a chat list. The loaded chats and their positions in the chat list will be sent through updates. Chats are sorted by the pair (chat.position.order, chat.id) in descending order. Returns a 404 error if all chats has been loaded +//@chat_list The chat list in which to load chats +//@limit The maximum number of chats to be loaded. For optimal performance, the number of loaded chats is chosen by TDLib and can be smaller than the specified limit, even if the end of the list is not reached +loadChats chat_list:ChatList limit:int32 = Ok; + +//@description Returns an ordered list of chats from the beginning of a chat list. For informational purposes only. Use loadChats instead to maintain chat lists @chat_list The chat list in which to return chats @limit The maximum number of chats to be returned +getChats chat_list:ChatList limit:int32 = Chats; //@description Searches a public chat by its username. Currently only private chats, supergroups and channels can be public. Returns the chat if found; otherwise an error is returned @username Username to be resolved searchPublicChat username:string = Chat; @@ -4194,6 +4263,12 @@ getChatScheduledMessages chat_id:int53 = Messages; //@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit getMessagePublicForwards chat_id:int53 message_id:int53 offset:string limit:int32 = FoundMessages; +//@description Returns sponsored messages to be shown in a chat; for channel chats only @chat_id Identifier of the chat +getChatSponsoredMessages chat_id:int53 = SponsoredMessages; + +//@description Informs TDLib that a sponsored message was viewed by the user @chat_id Chat identifier @message_id The identifier of the sponsored message being viewed +viewSponsoredMessage chat_id:int53 message_id:bytes = Ok; + //@description Removes an active notification from notification list. Needs to be called only if the notification is removed by the current user @notification_group_id Identifier of notification group to which the notification belongs @notification_id Identifier of removed notification removeNotification notification_group_id:int32 notification_id:int32 = Ok; @@ -4254,9 +4329,10 @@ sendInlineQueryResultMessage chat_id:int53 message_thread_id:int53 reply_to_mess //@from_chat_id Identifier of the chat from which to forward messages //@message_ids Identifiers of the messages to forward. Message identifiers must be in a strictly increasing order. At most 100 messages can be forwarded simultaneously //@options Options to be used to send the messages -//@send_copy True, if content of the messages needs to be copied without links to the original messages. Always true if the messages are forwarded to a secret chat -//@remove_caption True, if media caption of message copies needs to be removed. Ignored if send_copy is false -forwardMessages chat_id:int53 from_chat_id:int53 message_ids:vector options:messageSendOptions send_copy:Bool remove_caption:Bool = Messages; +//@send_copy If true, content of the messages will be copied without links to the original messages. Always true if the messages are forwarded to a secret chat +//@remove_caption If true, media caption of message copies will be removed. Ignored if send_copy is false +//@only_preview If true, messages will not be forwarded and instead fake messages will be returned +forwardMessages chat_id:int53 from_chat_id:int53 message_ids:vector options:messageSendOptions send_copy:Bool remove_caption:Bool only_preview:Bool = Messages; //@description Resends messages which failed to send. Can be called only for messages for which messageSendingStateFailed.can_retry is true and after specified in messageSendingStateFailed.retry_after time passed. //-If a message is re-sent, the corresponding failed to send message is deleted. Returns the sent messages in the same order as the message identifiers passed in message_ids. If a message can't be re-sent, null will be returned instead of the message @@ -4546,6 +4622,10 @@ setChatMessageTtlSetting chat_id:int53 ttl:int32 = Ok; //@chat_id Chat identifier @permissions New non-administrator members permissions in the chat setChatPermissions chat_id:int53 permissions:chatPermissions = Ok; +//@description Changes the chat theme. Requires can_change_info administrator right in groups, supergroups and channels @chat_id Chat identifier +//@theme_name Name of the new chat theme; may be empty to return the default theme +setChatTheme chat_id:int53 theme_name:string = Ok; + //@description Changes the draft message in a chat @chat_id Chat identifier @message_thread_id If not 0, a message thread identifier in which the draft was changed @draft_message New draft message; may be null setChatDraftMessage chat_id:int53 message_thread_id:int53 draft_message:draftMessage = Ok; @@ -4861,7 +4941,8 @@ inviteGroupCallParticipants group_call_id:int32 user_ids:vector = Ok; getGroupCallInviteLink group_call_id:int32 can_self_unmute:Bool = HttpUrl; //@description Starts recording of an active group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title Group call recording title; 0-64 characters -startGroupCallRecording group_call_id:int32 title:string = Ok; +//@record_video Pass true to record a video file instead of an audio file @use_portrait_orientation Pass true to use portrait orientation for video instead of landscape one +startGroupCallRecording group_call_id:int32 title:string record_video:Bool use_portrait_orientation:Bool = Ok; //@description Ends recording of an active group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier endGroupCallRecording group_call_id:int32 = Ok; @@ -4900,11 +4981,13 @@ leaveGroupCall group_call_id:int32 = Ok; //@description Discards a group call. Requires groupCall.can_be_managed @group_call_id Group call identifier discardGroupCall group_call_id:int32 = Ok; -//@description Returns a file with a segment of a group call stream in a modified OGG format +//@description Returns a file with a segment of a group call stream in a modified OGG format for audio or MPEG-4 format for video //@group_call_id Group call identifier //@time_offset Point in time when the stream segment begins; Unix timestamp in milliseconds //@scale Segment duration scale; 0-1. Segment's duration is 1000/(2**scale) milliseconds -getGroupCallStreamSegment group_call_id:int32 time_offset:int53 scale:int32 = FilePart; +//@channel_id Identifier of an audio/video channel to get as received from tgcalls +//@video_quality Video quality as received from tgcalls +getGroupCallStreamSegment group_call_id:int32 time_offset:int53 scale:int32 channel_id:int32 video_quality:GroupCallVideoQuality = FilePart; //@description Changes the block state of a message sender. Currently, only users and supergroup chats can be blocked @sender Message Sender @is_blocked New value of is_blocked @@ -5205,6 +5288,10 @@ removeBackground background_id:int64 = Ok; resetBackgrounds = Ok; +//@description Returns the list of available chat themes +getChatThemes = ChatThemes; + + //@description Returns information about the current localization target. This is an offline request if only_local is true. Can be called before authorization @only_local If true, returns only locally available information without sending network requests getLocalizationTargetInfo only_local:Bool = LocalizationTargetInfo; @@ -5481,6 +5568,10 @@ getCountryCode = Text; //@description Returns information about a phone number by its prefix. Can be called before authorization @phone_number_prefix The phone number prefix getPhoneNumberInfo phone_number_prefix:string = PhoneNumberInfo; +//@description Returns information about a phone number by its prefix synchronously. getCountries must be called at least once after changing localization to the specified language if properly localized country information is expected. Can be called synchronously +//@language_code A two-letter ISO 639-1 country code for country information localization @phone_number_prefix The phone number prefix +getPhoneNumberInfoSync language_code:string phone_number_prefix:string = PhoneNumberInfo; + //@description Returns the link for downloading official Telegram application to be used when the current user invites friends to Telegram getApplicationDownloadLink = HttpUrl; diff --git a/td/generate/scheme/telegram_api.tl b/td/generate/scheme/telegram_api.tl index c475e091b..893c7fb46 100644 --- a/td/generate/scheme/telegram_api.tl +++ b/td/generate/scheme/telegram_api.tl @@ -82,7 +82,7 @@ inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes th inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; -inputGroupCallStream#bba51639 call:InputGroupCall time_ms:long scale:int = InputFileLocation; +inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; @@ -118,8 +118,8 @@ chatForbidden#7328bdb id:int title:string = Chat; channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; -chatFull#8a1e2983 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer = ChatFull; -channelFull#548c3f93 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer = ChatFull; +chatFull#49a0a5d9 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string = ChatFull; +channelFull#2f532f3c flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; @@ -177,6 +177,7 @@ messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int messageActionInviteToGroupCall#76b9f11a call:InputGroupCall users:Vector = MessageAction; messageActionSetMessagesTTL#aa1afbfd period:int = MessageAction; messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; +messageActionSetChatTheme#aa786345 emoticon:string = MessageAction; dialog#2c171f72 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; @@ -224,7 +225,7 @@ inputReportReasonCopyright#9b89f93a = ReportReason; inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; inputReportReasonFake#f5ddd6e7 = ReportReason; -userFull#139a9a77 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int = UserFull; +userFull#d697ff05 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; @@ -455,6 +456,7 @@ sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; speakingInGroupCallAction#d92c2285 = SendMessageAction; sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction; +sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction; contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; @@ -892,6 +894,7 @@ channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvit channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; +channelAdminLogEventActionChangeTheme#fe69018d prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; @@ -1106,7 +1109,7 @@ restrictionReason#d072acb4 platform:string reason:string text:string = Restricti inputTheme#3c5693e9 id:long access_hash:long = InputTheme; inputThemeSlug#f5890df1 slug:string = InputTheme; -theme#28f1114 flags:# creator:flags.0?true default:flags.1?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?ThemeSettings installs_count:int = Theme; +theme#e802b8dc flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?ThemeSettings installs_count:flags.4?int = Theme; account.themesNotModified#f41eb622 = account.Themes; account.themes#7f676421 hash:int themes:Vector = account.Themes; @@ -1125,9 +1128,9 @@ baseThemeNight#b7b31ea8 = BaseTheme; baseThemeTinted#6d5f77ee = BaseTheme; baseThemeArctic#5b11125a = BaseTheme; -inputThemeSettings#bd507cd1 flags:# base_theme:BaseTheme accent_color:int message_top_color:flags.0?int message_bottom_color:flags.0?int wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; +inputThemeSettings#ff38f912 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int message_colors:flags.0?Vector wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; -themeSettings#9c14984a flags:# base_theme:BaseTheme accent_color:int message_top_color:flags.0?int message_bottom_color:flags.0?int wallpaper:flags.1?WallPaper = ThemeSettings; +themeSettings#8db4e76c flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int message_colors:flags.0?Vector wallpaper:flags.1?WallPaper = ThemeSettings; webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settings:flags.1?ThemeSettings = WebPageAttribute; @@ -1185,7 +1188,7 @@ messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:fla messages.messageViews#b6c4f543 views:Vector chats:Vector users:Vector = messages.MessageViews; -messages.discussionMessage#f5dd8f9d flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int chats:Vector users:Vector = messages.DiscussionMessage; +messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; messageReplyHeader#a6d57763 flags:# reply_to_msg_id:int reply_to_peer_id:flags.0?Peer reply_to_top_id:flags.1?int = MessageReplyHeader; @@ -1196,7 +1199,7 @@ peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats; groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#d597650c flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int = GroupCall; +groupCall#d597650c flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int = GroupCall; inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; @@ -1255,6 +1258,15 @@ account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordR account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; account.resetPasswordOk#e926d63e = account.ResetPasswordResult; +chatTheme#ed0b5c33 emoticon:string theme:Theme dark_theme:Theme = ChatTheme; + +account.chatThemesNotModified#e011e1c4 = account.ChatThemes; +account.chatThemes#fe4cbebd hash:int themes:Vector = account.ChatThemes; + +sponsoredMessage#2a3c381f flags:# random_id:bytes from_id:Peer start_param:flags.0?string message:string entities:flags.1?Vector = SponsoredMessage; + +messages.sponsoredMessages#65a4c7d5 messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1355,6 +1367,7 @@ account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = Globa account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; account.resetPassword#9308ce1b = account.ResetPasswordResult; account.declinePasswordReset#4c9409f6 = Bool; +account.getChatThemes#d6d71d7b hash:int = account.ChatThemes; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; @@ -1392,7 +1405,7 @@ messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int = Updates; messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int = Updates; -messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer schedule_date:flags.10?int = Updates; +messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer schedule_date:flags.10?int = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.report#8953ab4e peer:InputPeer id:Vector reason:ReportReason message:string = Bool; @@ -1523,6 +1536,7 @@ messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithI messages.getChatInviteImporters#26fb7289 peer:InputPeer link:string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; +messages.setChatTheme#e63be13f peer:InputPeer emoticon:string = Updates; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; @@ -1601,6 +1615,8 @@ channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint addr channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates; channels.getInactiveChannels#11e831ee = messages.InactiveChats; channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; +channels.viewSponsoredMessage#beaedb94 channel:InputChannel random_id:bytes = Bool; +channels.getSponsoredMessages#ec210fbf channel:InputChannel = messages.SponsoredMessages; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; @@ -1642,7 +1658,7 @@ phone.toggleGroupCallSettings#74bbb43d flags:# reset_invite_hash:flags.1?true ca phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall; phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector = Vector; -phone.toggleGroupCallRecord#c02a66d7 flags:# start:flags.0?true call:InputGroupCall title:flags.1?string = Updates; +phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates; phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates; phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; diff --git a/td/mtproto/AuthData.cpp b/td/mtproto/AuthData.cpp index 365218ad1..2dfff4bcd 100644 --- a/td/mtproto/AuthData.cpp +++ b/td/mtproto/AuthData.cpp @@ -17,26 +17,31 @@ namespace td { namespace mtproto { -Status MessageIdDuplicateChecker::check(int64 message_id) { +Status check_message_id_duplicates(int64 *saved_message_ids, size_t max_size, size_t &end_pos, int64 message_id) { // In addition, the identifiers (msg_id) of the last N messages received from the other side must be stored, and if // a message comes in with msg_id lower than all or equal to any of the stored values, that message is to be // ignored. Otherwise, the new message msg_id is added to the set, and, if the number of stored msg_id values is // greater than N, the oldest (i. e. the lowest) is forgotten. - if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS) { - auto oldest_message_id = *saved_message_ids_.begin(); - if (message_id < oldest_message_id) { - return Status::Error(2, PSLICE() << "Ignore very old message_id " << tag("oldest message_id", oldest_message_id) - << tag("got message_id", message_id)); - } + if (end_pos == 2 * max_size) { + std::copy_n(&saved_message_ids[max_size], max_size, &saved_message_ids[0]); + end_pos = max_size; } - if (saved_message_ids_.count(message_id) != 0) { + if (end_pos == 0 || message_id > saved_message_ids[end_pos - 1]) { + // fast path + saved_message_ids[end_pos++] = message_id; + return Status::OK(); + } + if (end_pos >= max_size && message_id < saved_message_ids[0]) { + return Status::Error(2, PSLICE() << "Ignore very old message_id " << tag("oldest message_id", saved_message_ids[0]) + << tag("got message_id", message_id)); + } + auto it = std::lower_bound(&saved_message_ids[0], &saved_message_ids[end_pos], message_id); + if (*it == message_id) { return Status::Error(1, PSLICE() << "Ignore duplicated message_id " << tag("message_id", message_id)); } - - saved_message_ids_.insert(message_id); - if (saved_message_ids_.size() > MAX_SAVED_MESSAGE_IDS) { - saved_message_ids_.erase(saved_message_ids_.begin()); - } + std::copy_backward(it, &saved_message_ids[end_pos], &saved_message_ids[end_pos + 1]); + *it = message_id; + ++end_pos; return Status::OK(); } diff --git a/td/mtproto/AuthData.h b/td/mtproto/AuthData.h index 4a9717048..ef44aca82 100644 --- a/td/mtproto/AuthData.h +++ b/td/mtproto/AuthData.h @@ -12,7 +12,7 @@ #include "td/utils/Slice.h" #include "td/utils/Status.h" -#include +#include namespace td { namespace mtproto { @@ -37,13 +37,18 @@ void parse(ServerSalt &salt, ParserT &parser) { salt.valid_until = parser.fetch_double(); } +Status check_message_id_duplicates(int64 *saved_message_ids, size_t max_size, size_t &end_pos, int64 message_id); + +template class MessageIdDuplicateChecker { public: - Status check(int64 message_id); + Status check(int64 message_id) { + return check_message_id_duplicates(&saved_message_ids_[0], max_size, end_pos_, message_id); + } private: - static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000; - std::set saved_message_ids_; + std::array saved_message_ids_; + size_t end_pos_ = 0; }; class AuthData { @@ -240,6 +245,10 @@ class AuthData { return updates_duplicate_checker_.check(message_id); } + Status recheck_update(int64 message_id) { + return updates_duplicate_rechecker_.check(message_id); + } + int32 next_seq_no(bool is_content_related) { int32 res = seq_no_; if (is_content_related) { @@ -274,8 +283,9 @@ class AuthData { std::vector future_salts_; - MessageIdDuplicateChecker duplicate_checker_; - MessageIdDuplicateChecker updates_duplicate_checker_; + MessageIdDuplicateChecker<1000> duplicate_checker_; + MessageIdDuplicateChecker<1000> updates_duplicate_checker_; + MessageIdDuplicateChecker<100> updates_duplicate_rechecker_; void update_salt(double now); }; diff --git a/td/mtproto/RawConnection.cpp b/td/mtproto/RawConnection.cpp index e4b5d6086..58462c8d0 100644 --- a/td/mtproto/RawConnection.cpp +++ b/td/mtproto/RawConnection.cpp @@ -26,8 +26,8 @@ #include "td/utils/Status.h" #include "td/utils/StorerBase.h" -#include #include +#include #include namespace td { @@ -130,7 +130,7 @@ class RawConnectionDefault final : public RawConnection { PublicFields extra_; BufferedFd socket_fd_; unique_ptr transport_; - std::map quick_ack_to_token_; + std::unordered_map quick_ack_to_token_; bool has_error_{false}; unique_ptr stats_callback_; diff --git a/td/mtproto/SessionConnection.cpp b/td/mtproto/SessionConnection.cpp index 47305b0af..6958d5631 100644 --- a/td/mtproto/SessionConnection.cpp +++ b/td/mtproto/SessionConnection.cpp @@ -31,7 +31,6 @@ #include #include -#include namespace td { @@ -192,7 +191,6 @@ unique_ptr SessionConnection::move_as_raw_connection() { return std::move(raw_connection_); } -/*** SessionConnection ***/ BufferSlice SessionConnection::as_buffer_slice(Slice packet) { return current_buffer_slice_->from_slice(packet); } @@ -250,6 +248,10 @@ Status SessionConnection::on_packet_rpc_result(const MsgInfo &info, Slice packet if (parser.get_error()) { return Status::Error(PSLICE() << "Failed to parse mtproto_api::rpc_result: " << parser.get_error()); } + if (req_msg_id == 0) { + LOG(ERROR) << "Receive an update in rpc_result: message_id = " << info.message_id << ", seq_no = " << info.seq_no; + return Status::Error("Receive an update in rpc_result"); + } auto object_begin_pos = packet.size() - parser.get_left_len(); int32 id = parser.fetch_int(); @@ -304,8 +306,7 @@ Status SessionConnection::on_packet(const MsgInfo &info, uint64 req_msg_id, cons if (req_msg_id != 0) { callback_->on_message_result_error(req_msg_id, rpc_error.error_code_, rpc_error.error_message_.str()); } else { - LOG(ERROR) << "Receive rpc_error as update: [" << rpc_error.error_code_ << "][" << rpc_error.error_message_ - << "]"; + LOG(ERROR) << "Receive rpc_error as update: [" << rpc_error.error_code_ << "][" << rpc_error.error_message_ << "]"; } return Status::OK(); } @@ -426,7 +427,7 @@ Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::pong } Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::future_salts &salts) { VLOG(mtproto) << "FUTURE_SALTS"; - std::vector new_salts; + vector new_salts; for (auto &it : salts.salts_) { new_salts.push_back( ServerSalt{it->salt_, static_cast(it->valid_since_), static_cast(it->valid_until_)}); @@ -437,7 +438,7 @@ Status SessionConnection::on_packet(const MsgInfo &info, const mtproto_api::futu return Status::OK(); } -Status SessionConnection::on_msgs_state_info(const std::vector &ids, Slice info) { +Status SessionConnection::on_msgs_state_info(const vector &ids, Slice info) { if (ids.size() != info.size()) { return Status::Error(PSLICE() << tag("ids.size()", ids.size()) << " != " << tag("info.size()", info.size())); } @@ -497,14 +498,25 @@ Status SessionConnection::on_slice_packet(const MsgInfo &info, Slice packet) { // It is an update... I hope. auto status = auth_data_->check_update(info.message_id); + auto recheck_status = auth_data_->recheck_update(info.message_id); + if (recheck_status.is_error() && recheck_status.code() == 2) { + LOG(WARNING) << "Receive very old update from " << get_name() << " created in " << (Time::now() - created_at_) + << " in container " << container_id_ << " from session " << auth_data_->get_session_id() + << " with message_id " << info.message_id << ", main_message_id = " << main_message_id_ + << ", seq_no = " << info.seq_no << " and original size " << info.size << ": " << status << ' ' + << recheck_status; + } if (status.is_error()) { if (status.code() == 2) { - LOG(WARNING) << "Receive too old update: " << status; + LOG(WARNING) << "Receive too old update from " << get_name() << " created in " << (Time::now() - created_at_) + << " in container " << container_id_ << " from session " << auth_data_->get_session_id() + << " with message_id " << info.message_id << ", main_message_id = " << main_message_id_ + << ", seq_no = " << info.seq_no << " and original size " << info.size << ": " << status; callback_->on_session_failed(Status::Error("Receive too old update")); return status; } - VLOG(mtproto) << "Skip update " << info.message_id << " from " << get_name() << " created in " - << (Time::now() - created_at_) << ": " << status; + VLOG(mtproto) << "Skip update " << info.message_id << " of size " << info.size << " with seq_no " << info.seq_no + << " from " << get_name() << " created in " << (Time::now() - created_at_) << ": " << status; return Status::OK(); } else { VLOG(mtproto) << "Got update from " << get_name() << " created in " << (Time::now() - created_at_) @@ -891,7 +903,7 @@ void SessionConnection::flush_packet() { send_till++; } } - std::vector queries; + vector queries; if (send_till == to_send_.size()) { queries = std::move(to_send_); } else if (send_till != 0) { @@ -916,14 +928,16 @@ void SessionConnection::flush_packet() { << tag("resend", to_resend_answer_.size()) << tag("cancel", to_cancel_answer_.size()) << tag("destroy_key", destroy_auth_key) << tag("auth_id", auth_data_->get_auth_key().id()); - auto cut_tail = [](auto &v, size_t size, Slice name) { + auto cut_tail = [](vector &v, size_t size, Slice name) { if (size >= v.size()) { - return std::move(v); + auto result = std::move(v); + v.clear(); + return result; } - LOG(WARNING) << "Too much ids in container: " << v.size() << " " << name; - std::decay_t res(std::make_move_iterator(v.end() - size), std::make_move_iterator(v.end())); + LOG(WARNING) << "Too much message identifiers in container " << name << ": " << v.size() << " instead of " << size; + vector result(v.end() - size, v.end()); v.resize(v.size() - size); - return res; + return result; }; // no more than 8192 ids per container.. diff --git a/td/mtproto/SessionConnection.h b/td/mtproto/SessionConnection.h index 24bc82103..69db54bb4 100644 --- a/td/mtproto/SessionConnection.h +++ b/td/mtproto/SessionConnection.h @@ -164,15 +164,15 @@ class SessionConnection final struct ServiceQuery { enum Type { GetStateInfo, ResendAnswer } type; - std::vector message_ids; + vector message_ids; }; - std::vector to_resend_answer_; - std::vector to_cancel_answer_; - std::vector to_get_state_info_; + vector to_resend_answer_; + vector to_cancel_answer_; + vector to_get_state_info_; std::unordered_map service_queries_; // nobody cleans up this map. But it should be really small. - std::unordered_map> container_to_service_msg_; + std::unordered_map> container_to_service_msg_; double last_read_at_ = 0; double last_ping_at_ = 0; @@ -233,7 +233,7 @@ class SessionConnection final Status on_packet(const MsgInfo &info, const mtproto_api::pong &pong) TD_WARN_UNUSED_RESULT; Status on_packet(const MsgInfo &info, const mtproto_api::future_salts &salts) TD_WARN_UNUSED_RESULT; - Status on_msgs_state_info(const std::vector &ids, Slice info) TD_WARN_UNUSED_RESULT; + Status on_msgs_state_info(const vector &ids, Slice info) TD_WARN_UNUSED_RESULT; Status on_packet(const MsgInfo &info, const mtproto_api::msgs_state_info &msgs_state_info) TD_WARN_UNUSED_RESULT; Status on_packet(const MsgInfo &info, const mtproto_api::msgs_all_info &msgs_all_info) TD_WARN_UNUSED_RESULT; Status on_packet(const MsgInfo &info, const mtproto_api::msg_detailed_info &msg_detailed_info) TD_WARN_UNUSED_RESULT; diff --git a/td/telegram/AnimationsManager.cpp b/td/telegram/AnimationsManager.cpp index ade265a8b..21bcf5cca 100644 --- a/td/telegram/AnimationsManager.cpp +++ b/td/telegram/AnimationsManager.cpp @@ -159,19 +159,19 @@ int32 AnimationsManager::get_animation_duration(FileId file_id) const { return it->second->duration; } -tl_object_ptr AnimationsManager::get_animation_object(FileId file_id, const char *source) { +tl_object_ptr AnimationsManager::get_animation_object(FileId file_id) const { if (!file_id.is_valid()) { return nullptr; } - auto &animation = animations_[file_id]; + auto it = animations_.find(file_id); + if (it == animations_.end()) { + return nullptr; + } + auto animation = it->second.get(); if (animation == nullptr) { return nullptr; } - LOG_CHECK(animation != nullptr) << source << " " << file_id << " " - << static_cast(td_->file_manager_->get_file_view(file_id).get_type()); - // TODO can we make that function const? - animation->is_changed = false; auto thumbnail = animation->animated_thumbnail.file_id.is_valid() ? get_thumbnail_object(td_->file_manager_.get(), animation->animated_thumbnail, PhotoFormat::Mpeg4) @@ -195,27 +195,22 @@ FileId AnimationsManager::on_get_animation(unique_ptr new_animation, if (a->mime_type != new_animation->mime_type) { LOG(DEBUG) << "Animation " << file_id << " info has changed"; a->mime_type = new_animation->mime_type; - a->is_changed = true; } if (a->file_name != new_animation->file_name) { LOG(DEBUG) << "Animation " << file_id << " file name has changed"; a->file_name = std::move(new_animation->file_name); - a->is_changed = true; } if (a->dimensions != new_animation->dimensions) { LOG(DEBUG) << "Animation " << file_id << " dimensions has changed"; a->dimensions = new_animation->dimensions; - a->is_changed = true; } if (a->duration != new_animation->duration) { LOG(DEBUG) << "Animation " << file_id << " duration has changed"; a->duration = new_animation->duration; - a->is_changed = true; } if (!G()->shared_config().get_option_boolean("disable_minithumbnails")) { if (a->minithumbnail != new_animation->minithumbnail) { a->minithumbnail = std::move(new_animation->minithumbnail); - a->is_changed = true; } } if (a->thumbnail != new_animation->thumbnail) { @@ -226,7 +221,6 @@ FileId AnimationsManager::on_get_animation(unique_ptr new_animation, << new_animation->thumbnail; } a->thumbnail = new_animation->thumbnail; - a->is_changed = true; } if (a->animated_thumbnail != new_animation->animated_thumbnail) { if (!a->animated_thumbnail.file_id.is_valid()) { @@ -236,15 +230,12 @@ FileId AnimationsManager::on_get_animation(unique_ptr new_animation, << " to " << new_animation->animated_thumbnail; } a->animated_thumbnail = new_animation->animated_thumbnail; - a->is_changed = true; } if (a->has_stickers != new_animation->has_stickers && new_animation->has_stickers) { a->has_stickers = new_animation->has_stickers; - a->is_changed = true; } if (a->sticker_file_ids != new_animation->sticker_file_ids && !new_animation->sticker_file_ids.empty()) { a->sticker_file_ids = std::move(new_animation->sticker_file_ids); - a->is_changed = true; } } @@ -300,24 +291,18 @@ FileId AnimationsManager::dup_animation(FileId new_id, FileId old_id) { return new_id; } -bool AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_delete_old) { - if (!old_id.is_valid()) { - LOG(ERROR) << "Old file identifier is invalid"; - return true; - } +void AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_delete_old) { + CHECK(old_id.is_valid() && new_id.is_valid()); + CHECK(new_id != old_id); LOG(INFO) << "Merge animations " << new_id << " and " << old_id; const Animation *old_ = get_animation(old_id); CHECK(old_ != nullptr); - if (old_id == new_id) { - return old_->is_changed; - } bool need_merge = true; auto new_it = animations_.find(new_id); if (new_it == animations_.end() || new_it->second == nullptr) { auto &old = animations_[old_id]; - old->is_changed = true; if (!can_delete_old) { dup_animation(new_id, old_id); } else { @@ -328,7 +313,6 @@ bool AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_ Animation *new_ = new_it->second.get(); CHECK(new_ != nullptr); - new_->is_changed = true; if (old_->thumbnail != new_->thumbnail) { // LOG_STATUS(td_->file_manager_->merge(new_->thumbnail.file_id, old_->thumbnail.file_id)); } @@ -342,7 +326,6 @@ bool AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_ if (can_delete_old) { animations_.erase(old_id); } - return true; } void AnimationsManager::create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail, diff --git a/td/telegram/AnimationsManager.h b/td/telegram/AnimationsManager.h index c03c1c26b..f628014ac 100644 --- a/td/telegram/AnimationsManager.h +++ b/td/telegram/AnimationsManager.h @@ -37,7 +37,7 @@ class AnimationsManager final : public Actor { int32 get_animation_duration(FileId file_id) const; - tl_object_ptr get_animation_object(FileId file_id, const char *source); + tl_object_ptr get_animation_object(FileId file_id) const; void create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail, AnimationSize animated_thumbnail, bool has_stickers, vector &&sticker_file_ids, string file_name, string mime_type, @@ -59,7 +59,7 @@ class AnimationsManager final : public Actor { FileId dup_animation(FileId new_id, FileId old_id); - bool merge_animations(FileId new_id, FileId old_id, bool can_delete_old); + void merge_animations(FileId new_id, FileId old_id, bool can_delete_old); void on_update_animation_search_emojis(string animation_search_emojis); @@ -114,8 +114,6 @@ class AnimationsManager final : public Actor { vector sticker_file_ids; FileId file_id; - - bool is_changed = true; }; void memory_cleanup(bool full); diff --git a/td/telegram/AudiosManager.cpp b/td/telegram/AudiosManager.cpp index f387326ba..0336feb3f 100644 --- a/td/telegram/AudiosManager.cpp +++ b/td/telegram/AudiosManager.cpp @@ -31,16 +31,19 @@ int32 AudiosManager::get_audio_duration(FileId file_id) const { return it->second->duration; } -tl_object_ptr AudiosManager::get_audio_object(FileId file_id) { +tl_object_ptr AudiosManager::get_audio_object(FileId file_id) const { if (!file_id.is_valid()) { return nullptr; } - auto &audio = audios_[file_id]; + auto it = audios_.find(file_id); + if (it == audios_.end()) { + return nullptr; + } + auto audio = it->second.get(); if (audio == nullptr) { return nullptr; } - audio->is_changed = false; return make_tl_object( audio->duration, audio->title, audio->performer, audio->file_name, audio->mime_type, get_minithumbnail_object(audio->minithumbnail), @@ -60,23 +63,19 @@ FileId AudiosManager::on_get_audio(unique_ptr