Merge remote-tracking branch 'td/master'

This commit is contained in:
Andrea Cavalli 2021-09-04 16:03:33 +02:00
commit a20e8b6db3
109 changed files with 2895 additions and 1172 deletions

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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).

View File

@ -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',

View File

@ -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 <semaphore.h>
#endif
#include <algorithm>
#include <array>
#include <atomic>
#include <cstdint>
#include <set>
class F {
td::uint32 &sum;
@ -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<td::int64> AtomicCounterBench<StrictOrder>::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<td::int64> saved_message_ids_;
};
template <size_t MAX_SAVED_MESSAGE_IDS>
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<td::int64> 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<td::int64> 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<td::int64> saved_message_ids_;
};
template <size_t max_size>
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<td::int64, 2 * max_size> saved_message_ids_;
std::size_t end_pos_ = 0;
};
template <class T>
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 T>
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 T>
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 T>
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 T>
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<IdDuplicateCheckerNew<1000>>());
td::bench(DuplicateCheckerBenchEvenOdd<IdDuplicateCheckerNew<300>>());
td::bench(DuplicateCheckerBenchEvenOdd<IdDuplicateCheckerArray<1000>>());
td::bench(DuplicateCheckerBenchEvenOdd<IdDuplicateCheckerArray<300>>());
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerNew<1000>>());
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerNew<300>>());
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerArray<1000>>());
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerArray<300>>());
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerNew<1000>>());
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerNew<300>>());
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerArray<1000>>());
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerArray<300>>());
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerOld>());
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNew<1000>>());
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNewOther>());
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNewSimple>());
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNew<300>>());
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerArray<1000>>());
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerArray<300>>());
td::bench(DuplicateCheckerBench<IdDuplicateCheckerOld>());
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<1000>>());
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNewOther>());
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNewSimple>());
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<300>>());
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<100>>());
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<10>>());
td::bench(DuplicateCheckerBench<IdDuplicateCheckerArray<1000>>());
td::bench(DuplicateCheckerBench<IdDuplicateCheckerArray<300>>());
#if !TD_THREAD_UNSUPPORTED
for (int i = 1; i <= 16; i *= 2) {
td::bench(ThreadSafeCounterBench(i));

View File

@ -501,7 +501,6 @@ function onOptionsChanged() {
pre_text.push('Download and install <a href="https://visualstudio.microsoft.com/vs/community/">Microsoft Visual Studio</a>. Enable C++' + win10_sdk + ' support while installing.');
pre_text.push('Download and install <a href="https://cmake.org/download/">CMake</a>; choose "Add CMake to the system PATH" option while installing.');
pre_text.push('Download and install <a href="https://git-scm.com/download/win">Git</a>.');
pre_text.push('Download and install <a href="https://sourceforge.net/projects/gnuwin32/files/gperf/3.0.1/">gperf</a>. Add the path to gperf.exe to the PATH environment variable.');
pre_text.push('Download and unpack <a href="https://windows.php.net/download#php-7.2">PHP</a>. 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 ..');

View File

@ -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)

View File

@ -11,7 +11,6 @@
#include <cstdint>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <memory>
#include <sstream>
@ -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<td_api::getChats>(nullptr, std::numeric_limits<std::int64_t>::max(), 0, 20),
[this](Object object) {
if (object->get_id() == td_api::error::ID) {
return;
}
auto chats = td::move_tl_object_as<td_api::chats>(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<td_api::getChats>(nullptr, 20), [this](Object object) {
if (object->get_id() == td_api::error::ID) {
return;
}
auto chats = td::move_tl_object_as<td_api::chats>(object);
for (auto chat_id : chats->chat_ids_) {
std::cout << "[chat_id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl;
}
});
}
}
}

View File

@ -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();

View File

@ -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)" \

View File

@ -26,8 +26,8 @@ cmake --build . --target prepare_cross_compiling
cd <path to TDLib sources>/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/<platform>`, because the next script will rely on this location.
* Build TDLib for iOS, watchOS, tvOS and macOS:
@ -36,7 +36,7 @@ cd <path to TDLib sources>/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.

View File

@ -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

View File

@ -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/

View File

@ -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",

View File

@ -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)

View File

@ -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;

View File

@ -1,6 +1,6 @@
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
<Metadata>
<Identity Id="Telegram.Td.UWP" Version="1.7.6" Language="en-US" Publisher="Telegram LLC" />
<Identity Id="Telegram.Td.UWP" Version="1.7.7" Language="en-US" Publisher="Telegram LLC" />
<DisplayName>TDLib for Universal Windows Platform</DisplayName>
<Description>TDLib is a library for building Telegram clients</Description>
<MoreInfo>https://core.telegram.org/tdlib</MoreInfo>

View File

@ -801,6 +801,14 @@ messages total_count:int32 messages:vector<message> = Messages;
foundMessages total_count:int32 messages:vector<message> 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<sponsoredMessage> = 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<chatPosition> 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<chatPosition> 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<int53> = 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<message> draft_message:draftMessage = MessageThreadInfo;
messageThreadInfo chat_id:int53 message_thread_id:int53 reply_info:messageReplyInfo unread_message_count:int32 messages:vector<message> draft_message:draftMessage = MessageThreadInfo;
//@class RichText @description Describes a text object inside an instant-view web page
@ -1316,7 +1326,7 @@ countries countries:vector<countryInfo> = 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<shippingOption> = 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<datedFile> = 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<groupCallRecentSpeaker> 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<groupCallRecentSpeaker> 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<int32> = 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<chatTheme> = ChatThemes;
//@description Contains a list of hashtags @hashtags A list of hashtags
hashtags hashtags:vector<string> = 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<int53> 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<int53> 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<int32> = 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;

View File

@ -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<RestrictionReason> 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<BotInfo> 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<BotInfo> 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<string> 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<BotInfo> 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<BotInfo> 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<string> 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<int> = 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<Peer> results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = 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<Theme> = 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<int> 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<int> wallpaper:flags.1?WallPaper = ThemeSettings;
webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector<Document> 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<MessageViews> chats:Vector<Chat> users:Vector<User> = messages.MessageViews;
messages.discussionMessage#f5dd8f9d flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage;
messages.discussionMessage#a6341782 flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector<Chat> users:Vector<User> = 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<ChatTheme> = account.ChatThemes;
sponsoredMessage#2a3c381f flags:# random_id:bytes from_id:Peer start_param:flags.0?string message:string entities:flags.1?Vector<MessageEntity> = SponsoredMessage;
messages.sponsoredMessages#65a4c7d5 messages:Vector<SponsoredMessage> chats:Vector<Chat> users:Vector<User> = 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<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
@ -1392,7 +1405,7 @@ messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
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<MessageEntity> 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<MessageEntity> 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<int> random_id:Vector<long> 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<int> random_id:Vector<long> 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<int> 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<InputPeer> sources:Vector<int> offset:string limit:int = phone.GroupParticipants;
phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector<int> = Vector<int>;
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;

View File

@ -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();
}

View File

@ -12,7 +12,7 @@
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include <set>
#include <array>
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 <size_t max_size>
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<int64> saved_message_ids_;
std::array<int64, 2 * max_size> 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<ServerSalt> 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);
};

View File

@ -26,8 +26,8 @@
#include "td/utils/Status.h"
#include "td/utils/StorerBase.h"
#include <map>
#include <memory>
#include <unordered_map>
#include <utility>
namespace td {
@ -130,7 +130,7 @@ class RawConnectionDefault final : public RawConnection {
PublicFields extra_;
BufferedFd<SocketFd> socket_fd_;
unique_ptr<IStreamTransport> transport_;
std::map<uint32, uint64> quick_ack_to_token_;
std::unordered_map<uint32, uint64> quick_ack_to_token_;
bool has_error_{false};
unique_ptr<StatsCallback> stats_callback_;

View File

@ -31,7 +31,6 @@
#include <algorithm>
#include <iterator>
#include <type_traits>
namespace td {
@ -192,7 +191,6 @@ unique_ptr<RawConnection> 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<ServerSalt> new_salts;
vector<ServerSalt> new_salts;
for (auto &it : salts.salts_) {
new_salts.push_back(
ServerSalt{it->salt_, static_cast<double>(it->valid_since_), static_cast<double>(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<int64> &ids, Slice info) {
Status SessionConnection::on_msgs_state_info(const vector<int64> &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<MtprotoQuery> queries;
vector<MtprotoQuery> 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<int64> &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<decltype(v)> 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<int64> result(v.end() - size, v.end());
v.resize(v.size() - size);
return res;
return result;
};
// no more than 8192 ids per container..

View File

@ -164,15 +164,15 @@ class SessionConnection final
struct ServiceQuery {
enum Type { GetStateInfo, ResendAnswer } type;
std::vector<int64> message_ids;
vector<int64> message_ids;
};
std::vector<int64> to_resend_answer_;
std::vector<int64> to_cancel_answer_;
std::vector<int64> to_get_state_info_;
vector<int64> to_resend_answer_;
vector<int64> to_cancel_answer_;
vector<int64> to_get_state_info_;
std::unordered_map<uint64, ServiceQuery> service_queries_;
// nobody cleans up this map. But it should be really small.
std::unordered_map<uint64, std::vector<uint64>> container_to_service_msg_;
std::unordered_map<uint64, vector<uint64>> 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<int64> &ids, Slice info) TD_WARN_UNUSED_RESULT;
Status on_msgs_state_info(const vector<int64> &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;

View File

@ -159,19 +159,19 @@ int32 AnimationsManager::get_animation_duration(FileId file_id) const {
return it->second->duration;
}
tl_object_ptr<td_api::animation> AnimationsManager::get_animation_object(FileId file_id, const char *source) {
tl_object_ptr<td_api::animation> 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<int32>(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<Animation> 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<Animation> 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<Animation> 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,

View File

@ -37,7 +37,7 @@ class AnimationsManager final : public Actor {
int32 get_animation_duration(FileId file_id) const;
tl_object_ptr<td_api::animation> get_animation_object(FileId file_id, const char *source);
tl_object_ptr<td_api::animation> get_animation_object(FileId file_id) const;
void create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail, AnimationSize animated_thumbnail,
bool has_stickers, vector<FileId> &&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<FileId> sticker_file_ids;
FileId file_id;
bool is_changed = true;
};
void memory_cleanup(bool full);

View File

@ -31,16 +31,19 @@ int32 AudiosManager::get_audio_duration(FileId file_id) const {
return it->second->duration;
}
tl_object_ptr<td_api::audio> AudiosManager::get_audio_object(FileId file_id) {
tl_object_ptr<td_api::audio> 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<td_api::audio>(
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<Audio> new_audio, bool replace) {
if (a->mime_type != new_audio->mime_type) {
LOG(DEBUG) << "Audio " << file_id << " info has changed";
a->mime_type = new_audio->mime_type;
a->is_changed = true;
}
if (a->duration != new_audio->duration || a->title != new_audio->title || a->performer != new_audio->performer) {
LOG(DEBUG) << "Audio " << file_id << " info has changed";
a->duration = new_audio->duration;
a->title = new_audio->title;
a->performer = new_audio->performer;
a->is_changed = true;
}
if (a->file_name != new_audio->file_name) {
LOG(DEBUG) << "Audio " << file_id << " file name has changed";
a->file_name = std::move(new_audio->file_name);
a->is_changed = true;
}
if (a->minithumbnail != new_audio->minithumbnail) {
a->minithumbnail = std::move(new_audio->minithumbnail);
a->is_changed = true;
}
if (a->thumbnail != new_audio->thumbnail) {
if (!a->thumbnail.file_id.is_valid()) {
@ -86,7 +85,6 @@ FileId AudiosManager::on_get_audio(unique_ptr<Audio> new_audio, bool replace) {
<< new_audio->thumbnail;
}
a->thumbnail = new_audio->thumbnail;
a->is_changed = true;
}
}
@ -114,23 +112,17 @@ FileId AudiosManager::dup_audio(FileId new_id, FileId old_id) {
return new_id;
}
bool AudiosManager::merge_audios(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 AudiosManager::merge_audios(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 audios " << new_id << " and " << old_id;
const Audio *old_ = get_audio(old_id);
CHECK(old_ != nullptr);
if (old_id == new_id) {
return old_->is_changed;
}
auto new_it = audios_.find(new_id);
if (new_it == audios_.end() || new_it->second == nullptr) {
auto &old = audios_[old_id];
old->is_changed = true;
if (!can_delete_old) {
dup_audio(new_id, old_id);
} else {
@ -145,7 +137,6 @@ bool AudiosManager::merge_audios(FileId new_id, FileId old_id, bool can_delete_o
LOG(INFO) << "Audio has changed: mime_type = (" << old_->mime_type << ", " << new_->mime_type << ")";
}
new_->is_changed = true;
if (old_->thumbnail != new_->thumbnail) {
// LOG_STATUS(td_->file_manager_->merge(new_->thumbnail.file_id, old_->thumbnail.file_id));
}
@ -154,7 +145,6 @@ bool AudiosManager::merge_audios(FileId new_id, FileId old_id, bool can_delete_o
if (can_delete_old) {
audios_.erase(old_id);
}
return true;
}
string AudiosManager::get_audio_search_text(FileId file_id) const {

View File

@ -32,7 +32,7 @@ class AudiosManager {
int32 get_audio_duration(FileId file_id) const;
tl_object_ptr<td_api::audio> get_audio_object(FileId file_id);
tl_object_ptr<td_api::audio> get_audio_object(FileId file_id) const;
void create_audio(FileId file_id, string minithumbnail, PhotoSize thumbnail, string file_name, string mime_type,
int32 duration, string title, string performer, bool replace);
@ -51,7 +51,7 @@ class AudiosManager {
FileId dup_audio(FileId new_id, FileId old_id);
bool merge_audios(FileId new_id, FileId old_id, bool can_delete_old);
void merge_audios(FileId new_id, FileId old_id, bool can_delete_old);
template <class StorerT>
void store_audio(FileId file_id, StorerT &storer) const;
@ -73,8 +73,6 @@ class AudiosManager {
PhotoSize thumbnail;
FileId file_id;
bool is_changed = true;
};
const Audio *get_audio(FileId file_id) const;

View File

@ -53,7 +53,7 @@ class GetBackgroundQuery final : public Td::ResultHandler {
telegram_api::object_ptr<telegram_api::InputWallPaper> &&input_wallpaper) {
background_id_ = background_id;
background_name_ = background_name;
LOG(INFO) << "Load " << background_id_ << "/" << background_name_ << " from server: " << to_string(input_wallpaper);
LOG(INFO) << "Load " << background_id_ << "/" << background_name_ << " from server";
send_query(G()->net_query_creator().create(telegram_api::account_getWallPaper(std::move(input_wallpaper))));
}
@ -63,7 +63,7 @@ class GetBackgroundQuery final : public Td::ResultHandler {
return on_error(id, result_ptr.move_as_error());
}
td->background_manager_->on_get_background(background_id_, background_name_, result_ptr.move_as_ok());
td->background_manager_->on_get_background(background_id_, background_name_, result_ptr.move_as_ok(), true);
promise_.set_value(Unit());
}
@ -147,7 +147,7 @@ class UploadBackgroundQuery final : public Td::ResultHandler {
type_ = type;
for_dark_theme_ = for_dark_theme;
send_query(G()->net_query_creator().create(telegram_api::account_uploadWallPaper(
std::move(input_file), type_.get_mime_type(), type.get_input_wallpaper_settings())));
std::move(input_file), type_.get_mime_type(), type_.get_input_wallpaper_settings())));
}
void on_result(uint64 id, BufferSlice packet) final {
@ -370,7 +370,7 @@ void BackgroundManager::start_up() {
if (background.id.get() > max_local_background_id_.get()) {
set_max_local_background_id(background.id);
}
add_background(background);
add_background(background, true);
local_background_ids_[for_dark_theme].push_back(background.id);
}
}
@ -397,7 +397,7 @@ void BackgroundManager::start_up() {
set_background_id_[for_dark_theme] = background.id;
set_background_type_[for_dark_theme] = selected_background_log_event[i].set_type_;
add_background(background);
add_background(background, false);
}
if (need_resave) {
@ -413,8 +413,9 @@ void BackgroundManager::tear_down() {
parent_.reset();
}
void BackgroundManager::get_backgrounds(Promise<Unit> &&promise) {
pending_get_backgrounds_queries_.push_back(std::move(promise));
void BackgroundManager::get_backgrounds(bool for_dark_theme,
Promise<td_api::object_ptr<td_api::backgrounds>> &&promise) {
pending_get_backgrounds_queries_.emplace_back(for_dark_theme, std::move(promise));
if (pending_get_backgrounds_queries_.size() == 1) {
auto request_promise = PromiseCreator::lambda(
[actor_id = actor_id(this)](Result<telegram_api::object_ptr<telegram_api::account_WallPapers>> result) {
@ -539,7 +540,7 @@ void BackgroundManager::on_load_background_from_database(string name, string val
LOG(ERROR) << "Expected background " << name << ", but received " << background.name;
name_to_background_id_.emplace(name, background.id);
}
add_background(background);
add_background(background, false);
}
}
@ -551,7 +552,8 @@ void BackgroundManager::on_load_background_from_database(string name, string val
td_api::object_ptr<td_api::updateSelectedBackground> BackgroundManager::get_update_selected_background_object(
bool for_dark_theme) const {
return td_api::make_object<td_api::updateSelectedBackground>(
for_dark_theme, get_background_object(set_background_id_[for_dark_theme], for_dark_theme));
for_dark_theme,
get_background_object(set_background_id_[for_dark_theme], for_dark_theme, &set_background_type_[for_dark_theme]));
}
void BackgroundManager::send_update_selected_background(bool for_dark_theme) const {
@ -595,7 +597,7 @@ BackgroundId BackgroundManager::add_local_background(const BackgroundType &type)
background.is_dark = type.is_dark();
background.type = type;
background.name = type.get_link();
add_background(background);
add_background(background, true);
return background.id;
}
@ -716,8 +718,15 @@ void BackgroundManager::on_installed_background(BackgroundId background_id, Back
return promise.set_error(result.move_as_error());
}
if (!td::contains(installed_background_ids_, background_id)) {
installed_background_ids_.insert(installed_background_ids_.begin(), background_id);
size_t i;
for (i = 0; i < installed_backgrounds_.size(); i++) {
if (installed_backgrounds_[i].first == background_id) {
installed_backgrounds_[i].second = type;
break;
}
}
if (i == installed_backgrounds_.size()) {
installed_backgrounds_.insert(installed_backgrounds_.begin(), {background_id, type});
}
set_background_id(background_id, type, for_dark_theme);
promise.set_value(Unit());
@ -847,11 +856,14 @@ void BackgroundManager::on_uploaded_background_file(FileId file_id, const Backgr
Promise<Unit> &&promise) {
if (!(wallpaper != nullptr)) promise.set_error(Status::Error(500, "Error"));
BackgroundId background_id = on_get_background(BackgroundId(), string(), std::move(wallpaper));
auto added_background = on_get_background(BackgroundId(), string(), std::move(wallpaper), true);
auto background_id = added_background.first;
if (!background_id.is_valid()) {
td_->file_manager_->cancel_upload(file_id);
return promise.set_error(Status::Error(500, "Receive wrong uploaded background"));
}
LOG_IF(ERROR, added_background.second != type)
<< "Type of uploaded background has changed from " << type << " to " << added_background.second;
const auto *background = get_background(background_id);
if (!(background != nullptr)) return promise.set_error(Status::Error(500, "Error"));
@ -894,7 +906,8 @@ void BackgroundManager::on_removed_background(BackgroundId background_id, Result
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
td::remove(installed_background_ids_, background_id);
td::remove_if(installed_backgrounds_,
[background_id](const auto &background) { return background.first == background_id; });
if (background_id == set_background_id_[0]) {
set_background_id(BackgroundId(), BackgroundType(), false);
}
@ -925,7 +938,7 @@ void BackgroundManager::on_reset_background(Result<Unit> &&result, Promise<Unit>
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
installed_background_ids_.clear();
installed_backgrounds_.clear();
set_background_id(BackgroundId(), BackgroundType(), false);
set_background_id(BackgroundId(), BackgroundType(), true);
if (!local_background_ids_[0].empty()) {
@ -940,7 +953,7 @@ void BackgroundManager::on_reset_background(Result<Unit> &&result, Promise<Unit>
promise.set_value(Unit());
}
void BackgroundManager::add_background(const Background &background) {
void BackgroundManager::add_background(const Background &background, bool replace_type) {
LOG(INFO) << "Add " << background.id << " of " << background.type;
CHECK(background.id.is_valid());
@ -956,14 +969,17 @@ void BackgroundManager::add_background(const Background &background) {
if (!result->id.is_valid()) {
result->id = background.id;
result->type = background.type;
} else {
CHECK(result->id == background.id);
if (replace_type) {
result->type = background.type;
}
}
result->access_hash = background.access_hash;
result->is_creator = background.is_creator;
result->is_default = background.is_default;
result->is_dark = background.is_dark;
result->type = background.type;
if (result->name != background.name) {
if (!result->name.empty()) {
@ -1037,9 +1053,9 @@ string BackgroundManager::get_background_name_database_key(const string &name) {
return PSTRING() << "bgn" << name;
}
BackgroundId BackgroundManager::on_get_background(BackgroundId expected_background_id,
const string &expected_background_name,
telegram_api::object_ptr<telegram_api::WallPaper> wallpaper_ptr) {
std::pair<BackgroundId, BackgroundType> BackgroundManager::on_get_background(
BackgroundId expected_background_id, const string &expected_background_name,
telegram_api::object_ptr<telegram_api::WallPaper> wallpaper_ptr, bool replace_type) {
if (!(wallpaper_ptr != nullptr)) return BackgroundId();
if (wallpaper_ptr->get_id() == telegram_api::wallPaperNoFile::ID) {
@ -1047,13 +1063,13 @@ BackgroundId BackgroundManager::on_get_background(BackgroundId expected_backgrou
if (wallpaper->settings_ == nullptr) {
LOG(ERROR) << "Receive wallPaperNoFile without settings: " << to_string(wallpaper);
return BackgroundId();
return {};
}
auto background_id = BackgroundId(wallpaper->id_);
if (!background_id.is_valid() || background_id.is_local()) {
LOG(ERROR) << "Receive " << to_string(wallpaper);
return BackgroundId();
return {};
}
Background background;
@ -1063,16 +1079,16 @@ BackgroundId BackgroundManager::on_get_background(BackgroundId expected_backgrou
background.is_dark = (wallpaper->flags_ & telegram_api::wallPaperNoFile::DARK_MASK) != 0;
background.type = BackgroundType(true, false, std::move(wallpaper->settings_));
background.name = background.type.get_link();
add_background(background);
add_background(background, replace_type);
return background_id;
return {background_id, background.type};
}
auto wallpaper = move_tl_object_as<telegram_api::wallPaper>(wallpaper_ptr);
auto background_id = BackgroundId(wallpaper->id_);
if (!background_id.is_valid() || background_id.is_local() || is_background_name_local(wallpaper->slug_)) {
LOG(ERROR) << "Receive " << to_string(wallpaper);
return BackgroundId();
return {};
}
if (expected_background_id.is_valid() && background_id != expected_background_id) {
LOG(ERROR) << "Expected " << expected_background_id << ", but receive " << to_string(wallpaper);
@ -1081,7 +1097,7 @@ BackgroundId BackgroundManager::on_get_background(BackgroundId expected_backgrou
int32 document_id = wallpaper->document_->get_id();
if (document_id == telegram_api::documentEmpty::ID) {
LOG(ERROR) << "Receive " << to_string(wallpaper);
return BackgroundId();
return {};
}
CHECK(document_id == telegram_api::document::ID);
@ -1093,7 +1109,7 @@ BackgroundId BackgroundManager::on_get_background(BackgroundId expected_backgrou
Document::Type::General, true, is_pattern);
if (!document.file_id.is_valid()) {
LOG(ERROR) << "Receive wrong document in " << to_string(wallpaper);
return BackgroundId();
return {};
}
CHECK(document.type == Document::Type::General); // guaranteed by is_background parameter to on_get_document
@ -1106,7 +1122,7 @@ BackgroundId BackgroundManager::on_get_background(BackgroundId expected_backgrou
background.type = BackgroundType(false, is_pattern, std::move(wallpaper->settings_));
background.name = std::move(wallpaper->slug_);
background.file_id = document.file_id;
add_background(background);
add_background(background, replace_type);
if (!expected_background_name.empty() && background.name != expected_background_name) {
LOG(ERROR) << "Expected background " << expected_background_name << ", but receive " << background.name;
@ -1120,7 +1136,7 @@ BackgroundId BackgroundManager::on_get_background(BackgroundId expected_backgrou
log_event_store(background).as_slice().str(), Auto());
}
return background_id;
return {background_id, background.type};
}
void BackgroundManager::on_get_backgrounds(Result<telegram_api::object_ptr<telegram_api::account_WallPapers>> result) {
@ -1129,11 +1145,11 @@ void BackgroundManager::on_get_backgrounds(Result<telegram_api::object_ptr<teleg
reset_to_empty(pending_get_backgrounds_queries_);
if (result.is_error()) {
// do not clear installed_background_ids_
// do not clear installed_backgrounds_
auto error = result.move_as_error();
for (auto &promise : promises) {
promise.set_error(error.clone());
promise.second.set_error(error.clone());
}
return;
}
@ -1142,22 +1158,22 @@ void BackgroundManager::on_get_backgrounds(Result<telegram_api::object_ptr<teleg
LOG(INFO) << "Receive " << to_string(wallpapers_ptr);
if (wallpapers_ptr->get_id() == telegram_api::account_wallPapersNotModified::ID) {
for (auto &promise : promises) {
promise.set_value(Unit());
promise.second.set_value(get_backgrounds_object(promise.first));
}
return;
}
installed_background_ids_.clear();
installed_backgrounds_.clear();
auto wallpapers = telegram_api::move_object_as<telegram_api::account_wallPapers>(wallpapers_ptr);
for (auto &wallpaper : wallpapers->wallpapers_) {
auto background_id = on_get_background(BackgroundId(), string(), std::move(wallpaper));
if (background_id.is_valid()) {
installed_background_ids_.push_back(background_id);
auto background = on_get_background(BackgroundId(), string(), std::move(wallpaper), false);
if (background.first.is_valid()) {
installed_backgrounds_.push_back(std::move(background));
}
}
for (auto &promise : promises) {
promise.set_value(Unit());
promise.second.set_value(get_backgrounds_object(promise.first));
}
}
@ -1185,16 +1201,24 @@ td_api::object_ptr<td_api::background> BackgroundManager::get_background_object(
}
td_api::object_ptr<td_api::backgrounds> BackgroundManager::get_backgrounds_object(bool for_dark_theme) const {
auto backgrounds = transform(installed_background_ids_, [this, for_dark_theme](BackgroundId background_id) {
return get_background_object(background_id, for_dark_theme);
});
auto backgrounds = transform(installed_backgrounds_,
[this, for_dark_theme](const std::pair<BackgroundId, BackgroundType> &background) {
return get_background_object(background.first, for_dark_theme, &background.second);
});
auto background_id = set_background_id_[for_dark_theme];
if (background_id.is_valid() && !td::contains(installed_background_ids_, background_id)) {
backgrounds.push_back(get_background_object(background_id, for_dark_theme));
bool have_background = false;
for (const auto &background : installed_backgrounds_) {
if (background_id == background.first) {
have_background = true;
break;
}
}
if (background_id.is_valid() && !have_background) {
backgrounds.push_back(get_background_object(background_id, for_dark_theme, nullptr));
}
for (auto local_background_id : local_background_ids_[for_dark_theme]) {
if (local_background_id != background_id) {
backgrounds.push_back(get_background_object(local_background_id, for_dark_theme));
backgrounds.push_back(get_background_object(local_background_id, for_dark_theme, nullptr));
}
}
std::stable_sort(backgrounds.begin(), backgrounds.end(),

View File

@ -37,7 +37,7 @@ class BackgroundManager final : public Actor {
void memory_stats(vector<string> &output);
void get_backgrounds(Promise<Unit> &&promise);
void get_backgrounds(bool for_dark_theme, Promise<td_api::object_ptr<td_api::backgrounds>> &&promise);
Result<string> get_background_url(const string &name,
td_api::object_ptr<td_api::BackgroundType> background_type) const;
@ -55,12 +55,11 @@ class BackgroundManager final : public Actor {
void reset_backgrounds(Promise<Unit> &&promise);
td_api::object_ptr<td_api::background> get_background_object(BackgroundId background_id, bool for_dark_theme,
const BackgroundType *type = nullptr) const;
const BackgroundType *type) const;
td_api::object_ptr<td_api::backgrounds> get_backgrounds_object(bool for_dark_theme) const;
BackgroundId on_get_background(BackgroundId expected_background_id, const string &expected_background_name,
telegram_api::object_ptr<telegram_api::WallPaper> wallpaper_ptr);
std::pair<BackgroundId, BackgroundType> on_get_background(
BackgroundId expected_background_id, const string &expected_background_name,
telegram_api::object_ptr<telegram_api::WallPaper> wallpaper_ptr, bool replace_type);
FileSourceId get_background_file_source_id(BackgroundId background_id, int64 access_hash);
@ -115,6 +114,8 @@ class BackgroundManager final : public Actor {
td_api::object_ptr<td_api::updateSelectedBackground> get_update_selected_background_object(bool for_dark_theme) const;
td_api::object_ptr<td_api::backgrounds> get_backgrounds_object(bool for_dark_theme) const;
void send_update_selected_background(bool for_dark_theme) const;
void set_max_local_background_id(BackgroundId background_id);
@ -123,7 +124,7 @@ class BackgroundManager final : public Actor {
BackgroundId add_local_background(const BackgroundType &type);
void add_background(const Background &background);
void add_background(const Background &background, bool replace_type);
Background *get_background_ref(BackgroundId background_id);
@ -173,9 +174,9 @@ class BackgroundManager final : public Actor {
BackgroundId set_background_id_[2];
BackgroundType set_background_type_[2];
vector<BackgroundId> installed_background_ids_;
vector<std::pair<BackgroundId, BackgroundType>> installed_backgrounds_;
vector<Promise<Unit>> pending_get_backgrounds_queries_;
vector<std::pair<bool, Promise<td_api::object_ptr<td_api::backgrounds>>>> pending_get_backgrounds_queries_;
std::shared_ptr<UploadBackgroundFileCallback> upload_background_file_callback_;

View File

@ -125,6 +125,10 @@ class BackgroundType {
bool operator==(const BackgroundType &lhs, const BackgroundType &rhs);
inline bool operator!=(const BackgroundType &lhs, const BackgroundType &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const BackgroundType &type);
} // namespace td

View File

@ -1493,19 +1493,14 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
if (value->get_id() == telegram_api::jsonArray::ID) {
auto reasons = std::move(static_cast<telegram_api::jsonArray *>(value)->value_);
for (auto &reason : reasons) {
CHECK(reason != nullptr);
if (reason->get_id() == telegram_api::jsonString::ID) {
Slice reason_name = static_cast<telegram_api::jsonString *>(reason.get())->value_;
if (!reason_name.empty() && reason_name.find(',') == Slice::npos) {
if (!ignored_restriction_reasons.empty()) {
ignored_restriction_reasons += ',';
}
ignored_restriction_reasons.append(reason_name.begin(), reason_name.end());
} else {
LOG(ERROR) << "Receive unexpected restriction reason " << reason_name;
auto reason_name = get_json_value_string(std::move(reason), "ignore_restriction_reasons");
if (!reason_name.empty() && reason_name.find(',') == string::npos) {
if (!ignored_restriction_reasons.empty()) {
ignored_restriction_reasons += ',';
}
ignored_restriction_reasons += reason_name;
} else {
LOG(ERROR) << "Receive unexpected restriction reason " << to_string(reason);
LOG(ERROR) << "Receive unexpected restriction reason " << reason_name;
}
}
} else {
@ -1517,17 +1512,12 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
if (value->get_id() == telegram_api::jsonArray::ID) {
auto emojis = std::move(static_cast<telegram_api::jsonArray *>(value)->value_);
for (auto &emoji : emojis) {
CHECK(emoji != nullptr);
if (emoji->get_id() == telegram_api::jsonString::ID) {
Slice emoji_text = static_cast<telegram_api::jsonString *>(emoji.get())->value_;
if (!emoji_text.empty()) {
dice_emoji_index[emoji_text.str()] = dice_emojis.size();
dice_emojis.push_back(emoji_text.str());
} else {
LOG(ERROR) << "Receive empty dice emoji";
}
auto emoji_text = get_json_value_string(std::move(emoji), "emojies_send_dice");
if (!emoji_text.empty()) {
dice_emoji_index[emoji_text] = dice_emojis.size();
dice_emojis.push_back(emoji_text);
} else {
LOG(ERROR) << "Receive unexpected dice emoji " << to_string(emoji);
LOG(ERROR) << "Receive empty dice emoji";
}
}
} else {
@ -1548,8 +1538,7 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
if (dice_key_value->value_->get_id() != telegram_api::jsonNumber::ID) {
continue;
}
auto current_value =
static_cast<int32>(static_cast<telegram_api::jsonNumber *>(dice_key_value->value_.get())->value_);
auto current_value = get_json_value_int(std::move(dice_key_value->value_), Slice());
if (dice_key_value->key_ == "value") {
dice_value = current_value;
}
@ -1572,30 +1561,21 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
continue;
}
if (key == "gif_search_branding") {
if (value->get_id() == telegram_api::jsonString::ID) {
animation_search_provider = std::move(static_cast<telegram_api::jsonString *>(value)->value_);
} else {
LOG(ERROR) << "Receive unexpected gif_search_branding " << to_string(*value);
}
animation_search_provider = get_json_value_string(std::move(key_value->value_), "gif_search_branding");
continue;
}
if (key == "gif_search_emojies") {
if (value->get_id() == telegram_api::jsonArray::ID) {
auto emojis = std::move(static_cast<telegram_api::jsonArray *>(value)->value_);
for (auto &emoji : emojis) {
CHECK(emoji != nullptr);
if (emoji->get_id() == telegram_api::jsonString::ID) {
Slice emoji_str = static_cast<telegram_api::jsonString *>(emoji.get())->value_;
if (!emoji_str.empty() && emoji_str.find(',') == Slice::npos) {
if (!animation_search_emojis.empty()) {
animation_search_emojis += ',';
}
animation_search_emojis.append(emoji_str.begin(), emoji_str.end());
} else {
LOG(ERROR) << "Receive unexpected animation search emoji " << emoji_str;
auto emoji_str = get_json_value_string(std::move(emoji), "gif_search_emojies");
if (!emoji_str.empty() && emoji_str.find(',') == string::npos) {
if (!animation_search_emojis.empty()) {
animation_search_emojis += ',';
}
animation_search_emojis += emoji_str;
} else {
LOG(ERROR) << "Receive unexpected animation search emoji " << to_string(emoji);
LOG(ERROR) << "Receive unexpected animation search emoji " << emoji_str;
}
}
} else {
@ -1607,22 +1587,17 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
if (value->get_id() == telegram_api::jsonArray::ID) {
auto actions = std::move(static_cast<telegram_api::jsonArray *>(value)->value_);
for (auto &action : actions) {
CHECK(action != nullptr);
if (action->get_id() == telegram_api::jsonString::ID) {
Slice action_str = static_cast<telegram_api::jsonString *>(action.get())->value_;
SuggestedAction suggested_action(action_str);
if (!suggested_action.is_empty()) {
if (archive_and_mute &&
suggested_action == SuggestedAction{SuggestedAction::Type::EnableArchiveAndMuteNewChats}) {
LOG(INFO) << "Skip EnableArchiveAndMuteNewChats suggested action";
} else {
suggested_actions.push_back(suggested_action);
}
auto action_str = get_json_value_string(std::move(action), "pending_suggestions");
SuggestedAction suggested_action(action_str);
if (!suggested_action.is_empty()) {
if (archive_and_mute &&
suggested_action == SuggestedAction{SuggestedAction::Type::EnableArchiveAndMuteNewChats}) {
LOG(INFO) << "Skip EnableArchiveAndMuteNewChats suggested action";
} else {
LOG(ERROR) << "Receive unsupported suggested action " << action_str;
suggested_actions.push_back(suggested_action);
}
} else {
LOG(ERROR) << "Receive unexpected suggested action " << to_string(action);
LOG(ERROR) << "Receive unsupported suggested action " << action_str;
}
}
} else {
@ -1631,32 +1606,19 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
continue;
}
if (key == "autoarchive_setting_available") {
if (value->get_id() == telegram_api::jsonBool::ID) {
can_archive_and_mute_new_chats_from_unknown_users =
std::move(static_cast<telegram_api::jsonBool *>(value)->value_);
} else {
LOG(ERROR) << "Receive unexpected autoarchive_setting_available " << to_string(*value);
}
can_archive_and_mute_new_chats_from_unknown_users =
get_json_value_bool(std::move(key_value->value_), "autoarchive_setting_available");
continue;
}
if (key == "autologin_token") {
if (value->get_id() == telegram_api::jsonString::ID) {
autologin_token = url_encode(static_cast<telegram_api::jsonString *>(value)->value_);
} else {
LOG(ERROR) << "Receive unexpected autologin_token " << to_string(*value);
}
autologin_token = get_json_value_string(std::move(key_value->value_), "autologin_token");
continue;
}
if (key == "autologin_domains") {
if (value->get_id() == telegram_api::jsonArray::ID) {
auto domains = std::move(static_cast<telegram_api::jsonArray *>(value)->value_);
for (auto &domain : domains) {
CHECK(domain != nullptr);
if (domain->get_id() == telegram_api::jsonString::ID) {
autologin_domains.push_back(std::move(static_cast<telegram_api::jsonString *>(domain.get())->value_));
} else {
LOG(ERROR) << "Receive unexpected autologin domain " << to_string(domain);
}
autologin_domains.push_back(get_json_value_string(std::move(domain), "autologin_domains"));
}
} else {
LOG(ERROR) << "Receive unexpected autologin_domains " << to_string(*value);
@ -1667,12 +1629,7 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
if (value->get_id() == telegram_api::jsonArray::ID) {
auto domains = std::move(static_cast<telegram_api::jsonArray *>(value)->value_);
for (auto &domain : domains) {
CHECK(domain != nullptr);
if (domain->get_id() == telegram_api::jsonString::ID) {
url_auth_domains.push_back(std::move(static_cast<telegram_api::jsonString *>(domain.get())->value_));
} else {
LOG(ERROR) << "Receive unexpected url auth domain " << to_string(domain);
}
autologin_domains.push_back(get_json_value_string(std::move(domain), "url_auth_domains"));
}
} else {
LOG(ERROR) << "Receive unexpected url_auth_domains " << to_string(*value);
@ -1689,8 +1646,7 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
continue;
}
if (video_note_setting->value_->get_id() == telegram_api::jsonNumber::ID) {
auto setting_value = static_cast<int32>(
static_cast<const telegram_api::jsonNumber *>(video_note_setting->value_.get())->value_);
auto setting_value = get_json_value_int(std::move(video_note_setting->value_), Slice());
if (setting_value > 0) {
if (video_note_setting->key_ == "diameter") {
G()->shared_config().set_option_integer("suggested_video_note_length", setting_value);

View File

@ -4859,7 +4859,7 @@ string ContactsManager::get_dialog_about(DialogId dialog_id) {
break;
}
case DialogType::Channel: {
auto channel_full = get_channel_full_force(dialog_id.get_channel_id(), "get_dialog_about");
auto channel_full = get_channel_full_force(dialog_id.get_channel_id(), false, "get_dialog_about");
if (channel_full != nullptr) {
return channel_full->description;
}
@ -6111,7 +6111,7 @@ void ContactsManager::on_update_bot_commands(DialogId dialog_id, UserId bot_user
}
case DialogType::Channel: {
ChannelId channel_id(dialog_id.get_channel_id());
auto channel_full = get_channel_full(channel_id, "on_update_bot_commands");
auto channel_full = get_channel_full(channel_id, true, "on_update_bot_commands");
if (channel_full != nullptr) {
if (bot_commands.empty()) {
if (td::remove_if(channel_full->bot_commands, is_from_bot)) {
@ -6342,7 +6342,7 @@ void ContactsManager::set_channel_username(ChannelId channel_id, const string &u
}
if (!username.empty() && c->username.empty()) {
auto channel_full = get_channel_full(channel_id, "set_channel_username");
auto channel_full = get_channel_full(channel_id, false, "set_channel_username");
if (channel_full != nullptr && !channel_full->can_set_username) {
return promise.set_error(Status::Error(3, "Can't set supergroup username"));
}
@ -6374,7 +6374,7 @@ void ContactsManager::set_channel_sticker_set(ChannelId channel_id, StickerSetId
}
}
auto channel_full = get_channel_full(channel_id, "set_channel_sticker_set");
auto channel_full = get_channel_full(channel_id, false, "set_channel_sticker_set");
if (channel_full != nullptr && !channel_full->can_set_sticker_set) {
return promise.set_error(Status::Error(3, "Can't set supergroup sticker set"));
}
@ -6602,7 +6602,7 @@ void ContactsManager::get_channel_statistics_dc_id(DialogId dialog_id, bool for_
return promise.set_error(Status::Error(400, "Chat info not found"));
}
auto channel_full = get_channel_full_force(channel_id, "get_channel_statistics_dc_id");
auto channel_full = get_channel_full_force(channel_id, false, "get_channel_statistics_dc_id");
if (channel_full == nullptr || !channel_full->stats_dc_id.is_exact() ||
(for_full_statistics && !channel_full->can_view_statistics)) {
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), channel_id, for_full_statistics,
@ -6623,7 +6623,7 @@ void ContactsManager::get_channel_statistics_dc_id_impl(ChannelId channel_id, bo
return promise.set_error(Status::Error(500, "Request aborted"));
}
auto channel_full = get_channel_full(channel_id, "get_channel_statistics_dc_id_impl");
auto channel_full = get_channel_full(channel_id, false, "get_channel_statistics_dc_id_impl");
if (channel_full == nullptr) {
return promise.set_error(Status::Error(400, "Chat full info not found"));
}
@ -9538,7 +9538,7 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s
// G()->td_db()->get_sqlite_pmc()->erase(get_channel_full_database_key(channel_id), Auto());
// return;
if (get_channel_full(channel_id, "on_load_channel_full_from_database") != nullptr || value.empty()) {
if (get_channel_full(channel_id, true, "on_load_channel_full_from_database") != nullptr || value.empty()) {
return;
}
@ -9627,12 +9627,13 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s
}
}
ContactsManager::ChannelFull *ContactsManager::get_channel_full_force(ChannelId channel_id, const char *source) {
ContactsManager::ChannelFull *ContactsManager::get_channel_full_force(ChannelId channel_id, bool only_local,
const char *source) {
if (!have_channel_force(channel_id)) {
return nullptr;
}
ChannelFull *channel_full = get_channel_full(channel_id, source);
ChannelFull *channel_full = get_channel_full(channel_id, only_local, source);
if (channel_full != nullptr) {
return channel_full;
}
@ -9646,7 +9647,7 @@ ContactsManager::ChannelFull *ContactsManager::get_channel_full_force(ChannelId
LOG(INFO) << "Trying to load full " << channel_id << " from database from " << source;
on_load_channel_full_from_database(
channel_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_channel_full_database_key(channel_id)), source);
return get_channel_full(channel_id, source);
return get_channel_full(channel_id, only_local, source);
}
void ContactsManager::for_each_secret_chat_with_user(UserId user_id, std::function<void(SecretChatId)> f) {
@ -10123,6 +10124,8 @@ void ContactsManager::on_get_user_full(tl_object_ptr<telegram_api::userFull> &&u
td_->messages_manager_->on_update_dialog_notify_settings(DialogId(user_id), std::move(user->notify_settings_),
"on_get_user_full");
td_->messages_manager_->on_update_dialog_theme_name(DialogId(user_id), std::move(user->theme_emoticon_));
{
MessageId pinned_message_id;
if ((user->flags_ & USER_FULL_FLAG_HAS_PINNED_MESSAGE) != 0) {
@ -10439,6 +10442,8 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
td_->messages_manager_->on_update_dialog_notify_settings(DialogId(chat_id), std::move(chat->notify_settings_),
"on_get_chat_full");
td_->messages_manager_->on_update_dialog_theme_name(DialogId(chat_id), std::move(chat->theme_emoticon_));
auto bot_commands = get_bot_commands(std::move(chat->bot_info_), &chat_full->participants);
if (chat_full->bot_commands != bot_commands) {
chat_full->bot_commands = std::move(bot_commands);
@ -10458,7 +10463,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
invalidated_channels_full_.erase(channel_id);
if (!G()->close_flag()) {
auto channel_full = get_channel_full(channel_id, "on_get_channel_full");
auto channel_full = get_channel_full(channel_id, true, "on_get_channel_full");
if (channel_full != nullptr) {
if (channel_full->repair_request_version != 0 &&
channel_full->repair_request_version < channel_full->speculative_version) {
@ -10478,6 +10483,9 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
td_->messages_manager_->on_update_dialog_notify_settings(DialogId(channel_id), std::move(channel->notify_settings_),
"on_get_channel_full");
td_->messages_manager_->on_update_dialog_theme_name(DialogId(channel_id), std::move(channel->theme_emoticon_));
{
MessageTtlSetting message_ttl_setting;
if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_MESSAGE_TTL) != 0) {
@ -10693,7 +10701,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
update_channel_full(channel_full, channel_id);
if (linked_channel_id.is_valid()) {
auto linked_channel_full = get_channel_full_force(linked_channel_id, "on_get_chat_full");
auto linked_channel_full = get_channel_full_force(linked_channel_id, true, "on_get_chat_full");
on_update_channel_full_linked_channel_id(linked_channel_full, linked_channel_id, channel_id);
if (linked_channel_full != nullptr) {
update_channel_full(linked_channel_full, linked_channel_id);
@ -10743,7 +10751,7 @@ void ContactsManager::on_get_channel_full_failed(ChannelId channel_id) {
}
LOG(INFO) << "Failed to get " << channel_id;
auto channel_full = get_channel_full(channel_id, "on_get_channel_full");
auto channel_full = get_channel_full(channel_id, true, "on_get_channel_full");
if (channel_full != nullptr) {
channel_full->repair_request_version = 0;
}
@ -11766,7 +11774,7 @@ void ContactsManager::on_get_channel_participants(
}
if (participant_count != -1 || administrator_count != -1) {
auto channel_full = get_channel_full_force(channel_id, "on_get_channel_participants_success");
auto channel_full = get_channel_full_force(channel_id, true, "on_get_channel_participants_success");
if (channel_full != nullptr) {
if (administrator_count == -1) {
administrator_count = channel_full->administrator_count;
@ -11875,7 +11883,7 @@ bool ContactsManager::speculative_add_count(int32 &count, int32 delta_count, int
void ContactsManager::speculative_add_channel_participants(ChannelId channel_id, const vector<UserId> &added_user_ids,
UserId inviter_user_id, int32 date, bool by_me) {
auto it = cached_channel_participants_.find(channel_id);
auto channel_full = get_channel_full_force(channel_id, "speculative_add_channel_participants");
auto channel_full = get_channel_full_force(channel_id, true, "speculative_add_channel_participants");
bool is_participants_cache_changed = false;
int32 delta_participant_count = 0;
@ -11941,7 +11949,7 @@ void ContactsManager::speculative_delete_channel_participant(ChannelId channel_i
}
if (is_user_bot(deleted_user_id)) {
auto channel_full = get_channel_full_force(channel_id, "speculative_delete_channel_participant");
auto channel_full = get_channel_full_force(channel_id, true, "speculative_delete_channel_participant");
if (channel_full != nullptr && td::remove(channel_full->bot_user_ids, deleted_user_id)) {
channel_full->need_save_to_database = true;
update_channel_full(channel_full, channel_id);
@ -11962,7 +11970,7 @@ void ContactsManager::speculative_add_channel_participant_count(ChannelId channe
return;
}
auto channel_full = get_channel_full_force(channel_id, "speculative_add_channel_participant_count");
auto channel_full = get_channel_full_force(channel_id, true, "speculative_add_channel_participant_count");
auto min_count = channel_full == nullptr ? 0 : channel_full->administrator_count;
auto c = get_channel_force(channel_id);
@ -11992,7 +12000,7 @@ void ContactsManager::speculative_add_channel_user(ChannelId channel_id, UserId
auto c = get_channel_force(channel_id);
// channel full must be loaded before c->participant_count is updated, because on_load_channel_full_from_database
// must copy the initial c->participant_count before it is speculatibely updated
auto channel_full = get_channel_full_force(channel_id, "speculative_add_channel_user");
auto channel_full = get_channel_full_force(channel_id, true, "speculative_add_channel_user");
int32 min_count = 0;
if (channel_full != nullptr) {
channel_full->is_changed |= speculative_add_count(channel_full->administrator_count,
@ -12105,7 +12113,7 @@ void ContactsManager::speculative_add_channel_user(ChannelId channel_id, UserId
void ContactsManager::drop_channel_photos(ChannelId channel_id, bool is_empty, bool drop_channel_full_photo,
const char *source) {
if (drop_channel_full_photo) {
auto channel_full = get_channel_full(channel_id, "drop_channel_photos"); // must not load ChannelFull
auto channel_full = get_channel_full(channel_id, true, "drop_channel_photos"); // must not load ChannelFull
if (channel_full == nullptr) {
return;
}
@ -12124,7 +12132,7 @@ void ContactsManager::drop_channel_photos(ChannelId channel_id, bool is_empty, b
void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool need_drop_slow_mode_delay) {
LOG(INFO) << "Invalidate supergroup full for " << channel_id;
auto channel_full = get_channel_full(channel_id, "invalidate_channel_full"); // must not load ChannelFull
auto channel_full = get_channel_full(channel_id, true, "invalidate_channel_full"); // must not load ChannelFull
if (channel_full != nullptr) {
do_invalidate_channel_full(channel_full, need_drop_slow_mode_delay);
update_channel_full(channel_full, channel_id);
@ -12234,7 +12242,7 @@ void ContactsManager::on_get_permanent_dialog_invite_link(DialogId dialog_id, co
}
case DialogType::Channel: {
auto channel_id = dialog_id.get_channel_id();
auto channel_full = get_channel_full_force(channel_id, "on_get_permanent_dialog_invite_link");
auto channel_full = get_channel_full_force(channel_id, true, "on_get_permanent_dialog_invite_link");
if (channel_full != nullptr && update_permanent_invite_link(channel_full->invite_link, invite_link)) {
channel_full->is_changed = true;
update_channel_full(channel_full, channel_id);
@ -12301,7 +12309,7 @@ void ContactsManager::on_update_channel_full_linked_channel_id(ChannelFull *chan
if (channel_full != nullptr && channel_full->linked_channel_id != linked_channel_id &&
channel_full->linked_channel_id.is_valid()) {
get_channel_force(channel_full->linked_channel_id);
get_channel_full_force(channel_full->linked_channel_id, "on_update_channel_full_linked_channel_id 0");
get_channel_full_force(channel_full->linked_channel_id, true, "on_update_channel_full_linked_channel_id 0");
}
auto old_linked_linked_channel_id = get_linked_channel_id(linked_channel_id);
@ -12323,7 +12331,7 @@ void ContactsManager::on_update_channel_full_linked_channel_id(ChannelFull *chan
reload_channel(channel_full->linked_channel_id, Auto());
}
auto linked_channel_full =
get_channel_full_force(channel_full->linked_channel_id, "on_update_channel_full_linked_channel_id 1");
get_channel_full_force(channel_full->linked_channel_id, true, "on_update_channel_full_linked_channel_id 1");
if (linked_channel_full != nullptr && linked_channel_full->linked_channel_id == channel_id) {
linked_channel_full->linked_channel_id = ChannelId();
linked_channel_full->is_changed = true;
@ -12344,7 +12352,7 @@ void ContactsManager::on_update_channel_full_linked_channel_id(ChannelFull *chan
reload_channel(channel_full->linked_channel_id, Auto());
}
auto linked_channel_full =
get_channel_full_force(channel_full->linked_channel_id, "on_update_channel_full_linked_channel_id 2");
get_channel_full_force(channel_full->linked_channel_id, true, "on_update_channel_full_linked_channel_id 2");
if (linked_channel_full != nullptr && linked_channel_full->linked_channel_id != channel_id) {
linked_channel_full->linked_channel_id = channel_id;
linked_channel_full->is_changed = true;
@ -13142,7 +13150,7 @@ void ContactsManager::on_channel_status_changed(const Channel *c, ChannelId chan
bool need_reload_group_call = old_status.can_manage_calls() != new_status.can_manage_calls();
if (old_status.can_manage_invite_links() && !new_status.can_manage_invite_links()) {
auto channel_full = get_channel_full(channel_id, "on_channel_status_changed");
auto channel_full = get_channel_full(channel_id, true, "on_channel_status_changed");
if (channel_full != nullptr) { // otherwise invite_link will be dropped when the channel is loaded
on_update_channel_full_invite_link(channel_full, nullptr);
do_invalidate_channel_full(channel_full, !c->is_slow_mode_enabled);
@ -13240,7 +13248,7 @@ void ContactsManager::on_channel_username_changed(const Channel *c, ChannelId ch
void ContactsManager::on_update_channel_description(ChannelId channel_id, string &&description) {
CHECK(channel_id.is_valid());
auto channel_full = get_channel_full_force(channel_id, "on_update_channel_description");
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_description");
if (channel_full == nullptr) {
return;
}
@ -13254,7 +13262,7 @@ void ContactsManager::on_update_channel_description(ChannelId channel_id, string
void ContactsManager::on_update_channel_sticker_set(ChannelId channel_id, StickerSetId sticker_set_id) {
CHECK(channel_id.is_valid());
auto channel_full = get_channel_full_force(channel_id, "on_update_channel_sticker_set");
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_sticker_set");
if (channel_full == nullptr) {
return;
}
@ -13267,14 +13275,14 @@ void ContactsManager::on_update_channel_sticker_set(ChannelId channel_id, Sticke
void ContactsManager::on_update_channel_linked_channel_id(ChannelId channel_id, ChannelId group_channel_id) {
if (channel_id.is_valid()) {
auto channel_full = get_channel_full_force(channel_id, "on_update_channel_linked_channel_id 1");
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_linked_channel_id 1");
on_update_channel_full_linked_channel_id(channel_full, channel_id, group_channel_id);
if (channel_full != nullptr) {
update_channel_full(channel_full, channel_id);
}
}
if (group_channel_id.is_valid()) {
auto channel_full = get_channel_full_force(group_channel_id, "on_update_channel_linked_channel_id 2");
auto channel_full = get_channel_full_force(group_channel_id, true, "on_update_channel_linked_channel_id 2");
on_update_channel_full_linked_channel_id(channel_full, group_channel_id, channel_id);
if (channel_full != nullptr) {
update_channel_full(channel_full, group_channel_id);
@ -13283,7 +13291,7 @@ void ContactsManager::on_update_channel_linked_channel_id(ChannelId channel_id,
}
void ContactsManager::on_update_channel_location(ChannelId channel_id, const DialogLocation &location) {
auto channel_full = get_channel_full_force(channel_id, "on_update_channel_location");
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_location");
if (channel_full != nullptr) {
on_update_channel_full_location(channel_full, channel_id, location);
update_channel_full(channel_full, channel_id);
@ -13295,7 +13303,7 @@ void ContactsManager::on_update_channel_slow_mode_delay(ChannelId channel_id, in
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
auto channel_full = get_channel_full_force(channel_id, "on_update_channel_slow_mode_delay");
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_slow_mode_delay");
if (channel_full != nullptr) {
on_update_channel_full_slow_mode_delay(channel_full, channel_id, slow_mode_delay, 0);
update_channel_full(channel_full, channel_id);
@ -13304,7 +13312,7 @@ void ContactsManager::on_update_channel_slow_mode_delay(ChannelId channel_id, in
}
void ContactsManager::on_update_channel_slow_mode_next_send_date(ChannelId channel_id, int32 slow_mode_next_send_date) {
auto channel_full = get_channel_full_force(channel_id, "on_update_channel_slow_mode_next_send_date");
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_slow_mode_next_send_date");
if (channel_full != nullptr) {
on_update_channel_full_slow_mode_next_send_date(channel_full, slow_mode_next_send_date);
update_channel_full(channel_full, channel_id);
@ -13318,7 +13326,7 @@ void ContactsManager::on_update_channel_bot_user_ids(ChannelId channel_id, vecto
return;
}
auto channel_full = get_channel_full_force(channel_id, "on_update_channel_bot_user_ids");
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_bot_user_ids");
if (channel_full == nullptr) {
send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id),
std::move(bot_user_ids), false);
@ -13345,7 +13353,7 @@ void ContactsManager::on_update_channel_is_all_history_available(ChannelId chann
return promise.set_error(Status::Error(500, "Request aborted"));
}
CHECK(channel_id.is_valid());
auto channel_full = get_channel_full_force(channel_id, "on_update_channel_is_all_history_available");
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_is_all_history_available");
if (channel_full != nullptr && channel_full->is_all_history_available != is_all_history_available) {
channel_full->is_all_history_available = is_all_history_available;
channel_full->is_changed = true;
@ -14256,7 +14264,7 @@ bool ContactsManager::get_channel_has_linked_channel(const Channel *c) {
ChannelId ContactsManager::get_channel_linked_channel_id(ChannelId channel_id) {
auto channel_full = get_channel_full_const(channel_id);
if (channel_full == nullptr) {
channel_full = get_channel_full_force(channel_id, "get_channel_linked_channel_id");
channel_full = get_channel_full_force(channel_id, false, "get_channel_linked_channel_id");
if (channel_full == nullptr) {
return ChannelId();
}
@ -14267,7 +14275,7 @@ ChannelId ContactsManager::get_channel_linked_channel_id(ChannelId channel_id) {
int32 ContactsManager::get_channel_slow_mode_delay(ChannelId channel_id) {
auto channel_full = get_channel_full_const(channel_id);
if (channel_full == nullptr) {
channel_full = get_channel_full_force(channel_id, "get_channel_slow_mode_delay");
channel_full = get_channel_full_force(channel_id, false, "get_channel_slow_mode_delay");
if (channel_full == nullptr) {
return 0;
}
@ -14367,14 +14375,15 @@ const ContactsManager::ChannelFull *ContactsManager::get_channel_full(ChannelId
return get_channel_full_const(channel_id);
}
ContactsManager::ChannelFull *ContactsManager::get_channel_full(ChannelId channel_id, const char *source) {
ContactsManager::ChannelFull *ContactsManager::get_channel_full(ChannelId channel_id, bool only_local,
const char *source) {
auto p = channels_full_.find(channel_id);
if (p == channels_full_.end()) {
return nullptr;
}
auto channel_full = p->second.get();
if (channel_full->is_expired() && !td_->auth_manager_->is_bot()) {
if (!only_local && channel_full->is_expired() && !td_->auth_manager_->is_bot()) {
send_get_channel_full_query(channel_full, channel_id, Auto(), source);
}
@ -14391,7 +14400,7 @@ ContactsManager::ChannelFull *ContactsManager::add_channel_full(ChannelId channe
}
bool ContactsManager::load_channel_full(ChannelId channel_id, bool force, Promise<Unit> &&promise, const char *source) {
auto channel_full = get_channel_full_force(channel_id, source);
auto channel_full = get_channel_full_force(channel_id, true, source);
if (channel_full == nullptr) {
send_get_channel_full_query(channel_full, channel_id, std::move(promise), source);
return false;
@ -14401,8 +14410,7 @@ bool ContactsManager::load_channel_full(ChannelId channel_id, bool force, Promis
send_get_channel_full_query(channel_full, channel_id, std::move(promise), "load expired channel_full");
return false;
} else {
// request has already been sent in get_channel_full_force
// send_get_channel_full_query(channel_full, channel_id, Auto(), "load expired channel_full");
send_get_channel_full_query(channel_full, channel_id, Auto(), "load expired channel_full");
}
}
@ -14411,7 +14419,7 @@ bool ContactsManager::load_channel_full(ChannelId channel_id, bool force, Promis
}
void ContactsManager::reload_channel_full(ChannelId channel_id, Promise<Unit> &&promise, const char *source) {
send_get_channel_full_query(get_channel_full(channel_id, "reload_channel_full"), channel_id, std::move(promise),
send_get_channel_full_query(get_channel_full(channel_id, true, "reload_channel_full"), channel_id, std::move(promise),
source);
}
@ -15089,7 +15097,7 @@ void ContactsManager::get_channel_participants(ChannelId channel_id,
return promise.set_error(Status::Error(400, "Parameter offset must be non-negative"));
}
auto channel_full = get_channel_full_force(channel_id, "do_get_channel_participants");
auto channel_full = get_channel_full_force(channel_id, false, "get_channel_participants");
if (channel_full != nullptr && !channel_full->is_expired() && !channel_full->can_get_participants) {
return promise.set_error(Status::Error(400, "Member list is inaccessible"));
}
@ -15216,7 +15224,7 @@ void ContactsManager::on_load_administrator_users_finished(DialogId dialog_id,
}
void ContactsManager::on_update_channel_administrator_count(ChannelId channel_id, int32 administrator_count) {
auto channel_full = get_channel_full_force(channel_id, "on_update_channel_administrator_count");
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_administrator_count");
if (channel_full != nullptr && channel_full->administrator_count != administrator_count) {
channel_full->administrator_count = administrator_count;
channel_full->is_changed = true;
@ -15612,7 +15620,7 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
update_channel(c, channel_id);
if (need_update_participant_count) {
auto channel_full = get_channel_full(channel_id, "on_chat_update");
auto channel_full = get_channel_full(channel_id, true, "on_chat_update");
if (channel_full != nullptr && channel_full->participant_count != participant_count) {
channel_full->participant_count = participant_count;
channel_full->is_changed = true;
@ -15721,7 +15729,7 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co
update_channel(c, channel_id);
if (need_drop_participant_count) {
auto channel_full = get_channel_full(channel_id, "on_chat_update");
auto channel_full = get_channel_full(channel_id, true, "on_chat_update");
if (channel_full != nullptr && channel_full->participant_count != 0) {
channel_full->participant_count = 0;
channel_full->administrator_count = 0;

View File

@ -1135,8 +1135,8 @@ class ContactsManager final : public Actor {
const ChannelFull *get_channel_full(ChannelId channel_id) const;
const ChannelFull *get_channel_full_const(ChannelId channel_id) const;
ChannelFull *get_channel_full(ChannelId channel_id, const char *source);
ChannelFull *get_channel_full_force(ChannelId channel_id, const char *source);
ChannelFull *get_channel_full(ChannelId channel_id, bool only_local, const char *source);
ChannelFull *get_channel_full_force(ChannelId channel_id, bool only_local, const char *source);
ChannelFull *add_channel_full(ChannelId channel_id);

View File

@ -18,8 +18,6 @@
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/Random.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include "td/utils/Time.h"
#include "td/utils/tl_parsers.h"
@ -63,11 +61,11 @@ class GetCountriesListQuery final : public Td::ResultHandler {
}
void send(const string &language_code, int32 hash) {
hash = 0;
send_query(G()->net_query_creator().create_unauth(telegram_api::help_getCountriesList(language_code, hash)));
}
void on_result(uint64 id, BufferSlice packet) final {
// LOG(ERROR) << base64url_encode(gzencode(packet, 0.9));
auto result_ptr = fetch_result<telegram_api::help_getCountriesList>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
@ -105,13 +103,13 @@ struct CountryInfoManager::CountryInfo {
};
struct CountryInfoManager::CountryList {
vector<CountryInfo> countries_;
vector<CountryInfo> countries;
int32 hash = 0;
double next_reload_time = 0.0;
td_api::object_ptr<td_api::countries> get_countries_object() const {
return td_api::make_object<td_api::countries>(
transform(countries_, [](const CountryInfo &info) { return info.get_country_info_object(); }));
transform(countries, [](const CountryInfo &info) { return info.get_country_info_object(); }));
}
};
@ -120,8 +118,20 @@ CountryInfoManager::CountryInfoManager(Td *td, ActorShared<> parent) : td_(td),
CountryInfoManager::~CountryInfoManager() = default;
void CountryInfoManager::start_up() {
std::lock_guard<std::mutex> country_lock(country_mutex_);
manager_count_++;
}
void CountryInfoManager::tear_down() {
parent_.reset();
std::lock_guard<std::mutex> country_lock(country_mutex_);
manager_count_--;
if (manager_count_ == 0) {
LOG(INFO) << "Clear country info";
countries_.clear();
}
}
string CountryInfoManager::get_main_language_code() {
@ -141,23 +151,27 @@ void CountryInfoManager::do_get_countries(string language_code, bool is_recursiv
is_recursive = false;
}
}
auto list = get_country_list(language_code);
if (list == nullptr) {
if (is_recursive) {
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
{
std::lock_guard<std::mutex> country_lock(country_mutex_);
auto list = get_country_list(this, language_code);
if (list != nullptr) {
return promise.set_value(list->get_countries_object());
}
return load_country_list(language_code, 0,
PromiseCreator::lambda([actor_id = actor_id(this), language_code,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &CountryInfoManager::do_get_countries, std::move(language_code),
true, std::move(promise));
}));
}
promise.set_value(list->get_countries_object());
if (is_recursive) {
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
}
load_country_list(language_code, 0,
PromiseCreator::lambda([actor_id = actor_id(this), language_code,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &CountryInfoManager::do_get_countries, std::move(language_code), true,
std::move(promise));
}));
}
void CountryInfoManager::get_phone_number_info(string phone_number_prefix,
@ -178,29 +192,52 @@ void CountryInfoManager::do_get_phone_number_info(string phone_number_prefix, st
is_recursive = false;
}
}
auto list = get_country_list(language_code);
if (list == nullptr) {
if (is_recursive) {
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
{
std::lock_guard<std::mutex> country_lock(country_mutex_);
auto list = get_country_list(this, language_code);
if (list != nullptr) {
return promise.set_value(get_phone_number_info_object(list, phone_number_prefix));
}
return load_country_list(language_code, 0,
PromiseCreator::lambda([actor_id = actor_id(this), phone_number_prefix, language_code,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &CountryInfoManager::do_get_phone_number_info,
std::move(phone_number_prefix), std::move(language_code), true,
std::move(promise));
}));
}
Slice phone_number = phone_number_prefix;
if (is_recursive) {
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
}
load_country_list(language_code, 0,
PromiseCreator::lambda([actor_id = actor_id(this), phone_number_prefix, language_code,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &CountryInfoManager::do_get_phone_number_info,
std::move(phone_number_prefix), std::move(language_code), true, std::move(promise));
}));
}
td_api::object_ptr<td_api::phoneNumberInfo> CountryInfoManager::get_phone_number_info_sync(string language_code,
string phone_number_prefix) {
td::remove_if(phone_number_prefix, [](char c) { return c < '0' || c > '9'; });
if (phone_number_prefix.empty()) {
return td_api::make_object<td_api::phoneNumberInfo>(nullptr, string(), string());
}
std::lock_guard<std::mutex> country_lock(country_mutex_);
auto list = get_country_list(nullptr, language_code);
if (list == nullptr) {
list = get_country_list(nullptr, "en");
}
return get_phone_number_info_object(list, phone_number_prefix);
}
td_api::object_ptr<td_api::phoneNumberInfo> CountryInfoManager::get_phone_number_info_object(const CountryList *list,
Slice phone_number) {
CHECK(list != nullptr);
const CountryInfo *best_country = nullptr;
const CallingCodeInfo *best_calling_code = nullptr;
size_t best_length = 0;
bool is_prefix = false;
for (auto &country : list->countries_) {
bool is_prefix = false; // is phone number a prefix of a valid country_code + prefix
for (auto &country : list->countries) {
for (auto &calling_code : country.calling_codes) {
if (begins_with(phone_number, calling_code.calling_code)) {
auto calling_code_size = calling_code.calling_code.size();
@ -222,12 +259,12 @@ void CountryInfoManager::do_get_phone_number_info(string phone_number_prefix, st
}
}
if (best_country == nullptr) {
return promise.set_value(td_api::make_object<td_api::phoneNumberInfo>(
nullptr, is_prefix ? phone_number_prefix : string(), is_prefix ? string() : phone_number_prefix));
return td_api::make_object<td_api::phoneNumberInfo>(nullptr, is_prefix ? phone_number.str() : string(),
is_prefix ? string() : phone_number.str());
}
string formatted_part = phone_number_prefix.substr(best_calling_code->calling_code.size());
string formatted_phone_number = formatted_part;
Slice formatted_part = phone_number.substr(best_calling_code->calling_code.size());
string formatted_phone_number;
size_t max_matched_digits = 0;
for (auto &pattern : best_calling_code->patterns) {
string result;
@ -240,7 +277,7 @@ void CountryInfoManager::do_get_phone_number_info(string phone_number_prefix, st
result += pattern[current_pattern_pos++];
}
if (current_pattern_pos == pattern.size()) {
result += ' ';
// result += ' ';
}
if (current_pattern_pos >= pattern.size() || pattern[current_pattern_pos] == 'X') {
result += c;
@ -257,15 +294,29 @@ void CountryInfoManager::do_get_phone_number_info(string phone_number_prefix, st
}
}
}
for (size_t i = current_pattern_pos; i < pattern.size(); i++) {
if (is_digit(pattern[i])) {
is_failed_match = true;
}
}
if (!is_failed_match && matched_digits >= max_matched_digits) {
max_matched_digits = matched_digits;
while (current_pattern_pos < pattern.size()) {
if (pattern[current_pattern_pos] == 'X') {
result.push_back('-');
} else {
CHECK(!is_digit(pattern[current_pattern_pos]));
result.push_back(' ');
}
current_pattern_pos++;
}
formatted_phone_number = std::move(result);
}
}
promise.set_value(td_api::make_object<td_api::phoneNumberInfo>(
return td_api::make_object<td_api::phoneNumberInfo>(
best_country->get_country_info_object(), best_calling_code->calling_code,
formatted_phone_number.empty() ? formatted_part : formatted_phone_number));
formatted_phone_number.empty() ? formatted_part.str() : formatted_phone_number);
}
void CountryInfoManager::get_current_country_code(Promise<string> &&promise) {
@ -296,9 +347,19 @@ void CountryInfoManager::on_get_country_list(const string &language_code,
pending_load_country_queries_.erase(query_it);
if (r_country_list.is_error()) {
auto it = countries_.find(language_code);
if (it != countries_.end()) {
it->second->next_reload_time = Time::now() + Random::fast(60, 120);
{
std::lock_guard<std::mutex> country_lock(country_mutex_);
auto it = countries_.find(language_code);
if (it != countries_.end()) {
// don't try to reload countries more often than once in 1-2 minutes
it->second->next_reload_time = max(Time::now() + Random::fast(60, 120), it->second->next_reload_time);
// if we have data for the language, then we don't need to fail promises
for (auto &promise : promises) {
promise.set_value(Unit());
}
return;
}
}
for (auto &promise : promises) {
promise.set_error(r_country_list.error().clone());
@ -306,7 +367,10 @@ void CountryInfoManager::on_get_country_list(const string &language_code,
return;
}
on_get_country_list_impl(language_code, r_country_list.move_as_ok());
{
std::lock_guard<std::mutex> country_lock(country_mutex_);
on_get_country_list_impl(language_code, r_country_list.move_as_ok());
}
for (auto &promise : promises) {
promise.set_value(Unit());
@ -359,7 +423,7 @@ void CountryInfoManager::on_get_country_list_impl(const string &language_code,
continue;
}
countries->countries_.push_back(std::move(info));
countries->countries.push_back(std::move(info));
}
countries->hash = list->hash_;
countries->next_reload_time = Time::now() + Random::fast(86400, 2 * 86400);
@ -370,79 +434,75 @@ void CountryInfoManager::on_get_country_list_impl(const string &language_code,
}
}
const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(const string &language_code) {
const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(CountryInfoManager *manager,
const string &language_code) {
auto it = countries_.find(language_code);
if (it == countries_.end()) {
if (language_code == "en") {
static const BufferSlice en = gzdecode(
base64url_decode(
"eJyNW81y6kiWzmv8f3-qbnd19SwmKhQxET3dEV0doH8tAQPGIMxF4Gt7l0AWZFlILiHZbb9A7-YRZjOLjl7MbuYJ7sx-"
"IuYdZjGbeYU5AhsJ6ZC6EbbBIk_myfP7nZPJP0f_9Zff_Me___3_EkL-4Z_-8gVeyF71jBxVvakfBDT-7A08-7__LNX24LWkGPrrs-"
"Pra2n1s0XbIN-NPB6yqVQN6FhqLHhAQ7aEz3JzWUbl9dnb1USr3-tkriZ5W_1pNqceX4bUy9LvWQpJ0W8mSOhb5GPVC_"
"ksotLvpBoNxtGU5vnYr8i6meLv-"
"JWRrX21yXHVm0XcdSmyl3gOtXCOLsjVHcN2ELlqmlgWNtAGC4bSGurrs9OENrXuJTkE3n3gPEcrq6pYhgNyUg1mDMToZWS3-lxTU-"
"s45EN1wQI-oZ7k0IWfX2-_opvFchrCXqNlGOT3uqcmOj9dU15v73UE_"
"Ma01OWIrvf0SspmVvQZOX8mB9UgGiO0JdkyxHzfktPqMwvGlP9MPcTeLVWo41qVfFfzl6BiMNdzFjyzmf-wEnt-"
"LsU0hDqv1chxbPF06mO-B_"
"aq6kV6qJ2R0xr1Zi6dsuU8z4NplsU8NMhRjbkzHi1yelDkzXzvrl8DSSaW1JrkXS0K7kAEUpMufUwOsqxvy3T9k8zRAjlE7owGPCtHsv"
"Y7Kxl7DvzSeUB5LtZArFJen51cJ8JKaNtAGwWRN-"
"V5HrWMrqRtm61dkIMaeLaH7s8Sy9iOZRwsILLldayqlUId98jHGrDNuHRGg2i5pC5dIHzoyf7xeS6BD9_lD0h80qzKts9m9_-J_"
"FDzPcoD9kfJ4V4oNcCDacijJTiCQ8c0rzfNSultQA5rAX3mbt7fNW3z7P3LwnndOSu90wVdYn4iF8pwCOvPoxD1eUMT6-"
"8z2KcfLh8p7ueyXuDnNysfi1WH5AVxTqndAt_M5c8MkW-5shlXr5LDOvA33dZDCV7fVNY8_z6mUctKSTONkmGWS6aslWRFB9svl_"
"SyCvYjlwzDLMnwXlUqML9eMspWySrDc1OO_"
"RhykVWSTaukqEpJ0bWSWtFhrFHSKlZJU82SXlFKugrzl7WSWTaANh5jwhj4hXW0ilrSDBhrVkom0JgGzAPr6Aq8T-"
"T4LpXntvRYPyMf6z4kSun3Z2zxJ2nA7v_0B0wnqiKUa71JvqtDxoQcJFV_WqfDeC5Uv4o4ftVb5N0LTy_"
"sYPzIYn7OyVvnkYeQmlzqTfM5NZ0TMfo2-VD_8m8hk6b_2H7wwU2xOCW283on3od_J7WXMQ_ZnLSyOd2Uk_"
"FdclCfc5chOVzTxTm8bpPjOgUg4vseLvONLaCxvN5brZ3FO6u1TT0dT1Krp-kvYX3f9RfjXM5Z829kcx9iiwNyWvchCkoDsJ_8HsB_"
"xHsYkf36CsYg62cxVCYe169gbXrPpCsWTDFdK6YwHtYhptWjgH75K83m7Dcvsfv12RsrTXcDcebpHkIZgne0Ap3dgo0-"
"s8k89rRo7PJJfg5VLqfsPI91zwCvtCCXUu8p7yPWar79tc42Qov3_aGiSanpyPuKIemb_"
"2EtRS9XJLVimem1Lsjx2c987EchR21UU4Rx4axDjs6Yt6DBXZ7XJOehsjoD_"
"zjzF9yLLQvDhoZukIKcd3ZJPrzO8RLd4vGlrXnMsrVjntQY-SvGqLvGJPzcxrXVjCE1Q0muKBl_y2PNRp0cNSYRwOUAwS_"
"ieN8Au2ksQx-vzWShLhotctCYPd2HiJ_K5XScSIeaFP0A1g54GDBk3wnuOknMM0XrkAPnnmK4c09RxbV1Y0iOG-Gc-_"
"dojAP7Fdf2TcDLTe5l8xFZ-7qZjLsg-03-c9ZHVuN0I8GAzQ75tkndu3hCUY7RyuWExianNp8EvseWHMGYupVgoOYled-kgc-SyRF5b-"
"LiUVZeTcCozYB6k3w83VOUVE6Rtgx0Q9-qkoMWHftojaBu4-sX4oS2Rj689GQ63JtN_UWeB3Vb36-"
"ldTLHGcTGgMUgEKkzDKXIP1ur2OoHM8RHLEsT2lqrCbKHtSG4tyJOsT4E-KiajD8HWc1z415yl9iXW21y0uJjgG4hDbC6WysL_"
"bnVBfqAsZVlozZi7bSRlk0OW3SFGhB8VRbLtwe0EfcYSivu8bT65LQFoY-5fnSP5HvN2qy9M362PpGPjV8iGvoQgV3phRXMVsU5uAV-"
"EssP9ZOteIjjptYQ5A9ssAV1sfW1srzlK1ns0wLcBPQLJKbtV3SjsJ5ufSbv15v_"
"scahmo5QGWjiOW5iXT7FBozYeYKRzzvk5BxqA6kDf5B1TE281_MeOQb6KUA1tD-rlVWhrZ9D7qkHPhTqSN4zxfXA-"
"ZAcnFMegx9kXUu87ogcnUfejAZ5nKboRGhf7TNy0vamLyEf6Q8mfanTJAwma7chjrUDhtVREBvEsaXdJYftZUBZvk9RsgxxDdeGmgT4R"
"nm2Ktux-4XrhPaSvDvjDGrIFg0mO_K1qgttsv2J7LcD-gtGa-lqoV-"
"2Byt6rB7bs8xiv247IPfJLrmrYt7B1tohdZ8wnGOJ7eXCJkcXdEEB5ubjgWkU9lAvLsnhhR9M0d6QntI5Usde9MnBBb2nGD4zK2mZ4di"
"w0yAHHeY9oXFYE-eEToucdp6C2dPzEu9rWbrQTzrnqxp87E9xezM1cXzotMlxhwd8TPH6SDfF9W8H9Fb3F37g5_"
"tism4JddbpkV87NO5DdngYxj3IHnvgSG_"
"Q1Avrkk6fvO35QTiHIJ3B6GQthwSPdgbkrQMFITJ2rXM5basbnSf0n8lhJ3qEqIrZmiaW1w3Uz_QJat8NwM3vV4HKsmi_"
"t2A39JnezXN2s-oXGmv6eL43evL_GvtuDGEb-3arZL9L0XMMkJ-eopdSppSir5GjLhtTz0f6-"
"npFaIfdOuhkZQvdaJLPc1Ara4Vnh902ed_lbDIPmbcMWbbeWtmBKivJeMjrTsClLvXu0HivZu1gO250IS93-RivhRVxXdZ1Ylkt_"
"XDuI36ji2UF2KvLw3kUn3Bi2NnYws6vDZSEfkROu9GfGUSNKJhh2DudI_"
"Mxq3tFDrs0fMDws2JUxGvfkAOQGR4rK6ZQZnaVHNkQaSYTRGYVcV636-TQ9j068TGexT0v-"
"yxe1536D1jfQRHqym5A7et7YJFsFvh5e1RSvVgbcoENhd-"
"MLidQFCF2sZHtu7QPpn3APiff2jRYzqnrCnvAKXxrd8g369hp0wmb4v0VU3w-ZnfJvk1dvMcmi8_"
"0bMghNsDwBQ2yfO5ZWmoc4Gg77tG7eK6zjIzfZHC4fUkOYIdorWBqBTz2yd-tZMQCD8QUxOXxDvm-"
"1jDlonhlf4r1HYTc479E2NmQpSdjB_HYKODhyukRGYv7X7aztsMlCwKaz1vAb_G9CnsYyw8KdrReF5-v2CNysuafR2hPRxHX-_"
"YV6J66U_6w446LLq7bbcjZQE8fOeZX4vM7-xpo2Z_5JO-_"
"e5qcWuNmxSN9WuLnEfpX9Bnt21hPz3F3ImsTL3hSHCN7ECN7dMHHWE7SxfcienXyvscepTp111EAPTsykvGAe3t8xrD-"
"jSwbQnvoNckH8KeffPf1qArrOyYxqteCffEdfWdFLZRrr01OelBcBHQWYfarlcW4rdcFfMli91-5fL6-qWzwVra3-"
"N4yEp625oSaBWTwSJ-QPmFydoXzAzVLj91TF42DRrE8BkAP_hhhOjaSHl9vRPZ7HCwRtYUES_VuY_"
"k8SreMomefuirez6VN9i8XaN0Kvm0KaftVctiHeLxAz-_Eub3fIPt9FosBOb_brvdzOKjfJN--9Ev7vvv00urA5JT0z_"
"st8m2f3kdUiqX12r7DdKAlNOfkbX_OXX5_D8Pztqcr6biC1_"
"X9Djnu07vVBT9sr1bunhAyRxfk7Od8dW2vZoGsbPLbNb7vc0hBDIo9O45w7natQNY6S84l-lCr9SMWhH58QOu_-"
"liqLjB3naElYyylsH7sO-SkD3FvCdkYOQsHn8r2U7djZ38I8gV8EM1il8TyY0Usn8_kANbPYpMX-0lq1_"
"5NrMdVFHvC1tEKevyfquTgE8V77lbB_"
"cZBgxwPvvwt8viO835dXDcMLsnRwF9g9zL31LLYfgYOOXRYgPbsFVNcaw1G5FeDaAne6UlNNmUAgOIdZOdJ18g7fWAAOGLwCC6AYTAta"
"yPbe3Cq5J1DoylfXdndgWF1XbgXp0a-ceI7D_6mgYDEjiRHO3Vy6rCnyZy5YNxYP9JMdJ4krYT-"
"jBw40RTrjcX3iMS8NkBnjyDwvKz31K3-MULbgtqcezN67wfY3RS94OzdOY9lHcebc-"
"ayzZ2vvbScZNVInRdtdHeYtXunTY4d139gHq4zxRTX605nTQ_hF6VXZXFscLqwlzhqUqnLfC-"
"bi18wkCzmwQY7oOvSxUNrYLPQ9p0eOXLiQpa6CN4T-6ADvu-A77sYftMKeB-A_KB0gAyP7l0ruC_sOK_9vpUlI72DAt6H5Hvny7_"
"40tBffPkbZK5-8OVfvQnHzvBkJd3zfIV8KV6uyNuGKznUfcDvQJTFdahzHdsCmLVNoXJkWByGnChXSEG-c27Ar58CtH9k6YrYHm_"
"JcWP5SOPCFbXFArw2rJPvh1FwF3d86xSy-lLQC9WL76QMz8h-"
"fU6nuF9kartMHTJskf2hP9tx59kU2uXwnBwP55Svj6CRGFVwf254QU6H9Gf-gsryerDEPa1hhxwN_TsGqCGfA6wEMwyhdhnyhR_"
"82AV8w5B8kRprk3exbuJvQOzAisBX2kbXNr6lX4gTQ0AJS_SOkDhWDi_JwdCHuI9i4qQfMhyQw5hPhtRO1lecXw-"
"H5OMQQgqf0imY4dAf09gI8vZnFn9nZXgV8_JA3QjDbgmWHQJ2GFL-iOnaNHWhzw3B54bUe6Y7cpBc8L2WUZUcje7iK_"
"csR6sk3y9I7txl-oqjFjkczXbhHjFmGTmkNHKqObxV-Qq8NboBvoMohrtI3N_GLtl-3-iWnI6ex2y3f2X9e5v-qk5-WGOIK-5NGLz-"
"TgrnTFrfz4lLMSz2Fn_v5qpBTq4gjz5D-YPE3z3tK85pr1rk-1rcTVvOgbtgxkXnSfJX8NQmH0dOdir0bKpcOBf4_xVnIeTrrD_"
"smanvMV2NYBz1Ihoi8ctI_OZzk3zzmboujxNGMwojL3--p5vJHbLP8X271deiMH9c1dXxs73rFvmh5YLnu5Ltj7nLIC2HgJN5CO-"
"eIFIu8vRmap3rDjns-Ev_AcNT5s48vl77inzf9kIWeKtiBFjosfDRh6SYx6mmKafeJz2XmwY5uGELhmFzSzd2xZPV-jdQy9_8mKvlV5-"
"pcnJ2qK7ros2at3ENs8JS6xv3SCzakw0ijAe3Njm83XX_Kunj4rSfyfEtX4zp-BHHwTp6N2T6P3_97_8HHeuAFA==")
"eJyNW81uI0lyzhb13-qeaXs8uwdjQMDAehfwLMj6ryP_RZFFsVmk_m5JMofMUbFKU6ySVnqBve0jGAb2sNiDb_YTtH034LfYi1_"
"BUaTEKlYFsxrobqmpjMzIyIgvvohM_Wv4P3_8h__6z3_8GyHkn_70xy_whexV6uSo4k4936fRz97BZ__"
"334XqHnwtyLr29tnxzU1x9WdLtkG-G7k8YNNixafjYmPBfRqwJfwsM5epl98-e7-aaPX3Jp6rSd5XfprNqcuXAXXT8numTBLymwli-"
"Rb5VHEDPgtp8TfFKvXH4ZRm9dgvS5qR0O_"
"4TZGtfbXJccWdhdxxKLKXaA4ld44u2NUZw3YQu6qq2BYWyPoLhsrqyttnp7FsYt1Lcgi6e6B5RlZSFLENB-"
"Sk4s8YmNFN2W71c1VJrGOTj5UF8_mEukWbLrzsevtlzci30xD2Gi4DP7vXPSU-"
"89O15M32XkegbyRLHY6c9Z5WTvjMSj5l52tyUPHDMSJbkExdrPcdOa28MH9M-c_URfzdVIRnXK2Q76reEo4Y3PWc-"
"S9s5j2uzJ6dSzZ04ZlXq-Q48ng69bDYA39VtLxzqNbJaZW6M4dO2XKe1cEwSmIdGuSoypwZDxeZc5ClzXxnN29AksKSapOcVUP_"
"HkxQbNKlh9lBkrRtm67_xHO0wA6hM6M-T9uRrOPOjMeeg7507lOewRrAKvnts5Ob2FixbBtkQz90pzyro5o6q-"
"K2z1YvyEEVIttF92eKbWxFNvYXgGzZM1aUcu4Z98inKqjNeLFO_XC5pA5dIHpo8f7xeS5BD8_hjwg-qWZ5O2bT-_9Mfqh6LuU--"
"5eizd2g2IAIpgEPlxAINh3T7LmpZuLcBuSw6tMX7mTjXVU3n314XTh7dvbq3OmCLrE4kXJtOIT152GAxryuis_"
"vGvzTC5ZPFI9zScuJ89tVjEVHh-QFcU6p3oHezOEvDLFvqbwZV6uQwxroN90-hwJ8fVde6_"
"zbSEYpyQXV0Au6USoYklqQZA18v1TQSgr4j1TQdaMgwfeKXIb5tYJeMgtmCT43pCiOIReZBckwC7IiF2RNLShlDcbqBbVsFlTFKGhlua"
"ApMH9JLRglHWSjMQaMgb-wjlpWCqoOY41ywQAZQ4d5YB1Nhu9jO54l8tzWOdbq5FPNg0RZ_G2dLX5fHLCH3_"
"8OOxNFFtq11iTf1SBjQg4qVn5ap8NoLvR8ZTF-1Vrk7FWnV3UwfSSxPufkvf3EA0hNDnWn2ZyazImYfJt8rH35j4AVp__"
"cfvQgTDGcUrfjrJiNs1on2ot3X2wvIz3SeWnld5ohxeO75KA25w5D8riqifN4zSLHNQpkxPNc3O4bf0DxvNZbrZ3mPKu1DS2JKYnVk_"
"KXsL7neItxJu-s9dfT-Q_xxwE5rXmAhMUB-FB2DxBD4j2MyH5tRWWQ9dM8KoXJtStYmz6w4hXzp9h5y4YQE2uAa7XQp1_-QtN5-"
"90rfr999s5Myt0C1jw_AJwhnEfNObM78NMXNplH0RaOHT7JzqFIpYSvZ_luHThLC_IpdZ-zcWKu5tt_PbMN_YzmKmub_74v6_"
"H3slYqF5WyaSTXuCDH9Z_52AsDjvqmKgsxod4hR3XmLqh_"
"n9UxzneojeoQF3Vvwd3IozBeqGs6ycl39Uvy8W2OV2SLxhe25jFK5o55EmOkrxij7BoT63MX1VUzhtQLBaksp-"
"IsyzMbNXLUmIRAlX2Eu4ixvgH-0lgGHl6XScKzaLTIQWP2_BAg8SmVkviQhJiE_ADW9nngM2TfMec6iWlDQtYmB_YDxTjnnqyI6-"
"rGkBw3gjn3HlBsA_8V1_VN4MpN7qZzEVnHuBGPuyD7Tf4zGiOabgp9otkh3zapcx8tIso3aqkUy1jk1OIT33PZkiOcUzNjTtS8JB-"
"a1PdYPDlyBhuMPErbsAmctelTd5LF1j1ZTuSX4pbTbuRbFXLQomMPrRmUbb79KhzLVsnH1x5Nh7uzqbfI6qBs-"
"8AboMVz1AEnfRaRQqTu0OW8mG2tcNbzZ0jcmKYq9L9WE2wPawPQt0JOsb4ExK0Sjz8HW80z417zmDi-"
"W21y0uJjoHIB9bE6XC0JY7zVBXmfsZW3oz5i7vSRlkUOW3TFIBC-VRLbtweyIXcZKivu-bT65LQFcMgcL3xAcr9qbtbeiamtz-"
"RT45eQBh6gslN8VQXzVXE-bkGcRPZD42QLI3EO1RqC_UENtqAOtr5akrZiJc2DWsChQH6BYNB-WdNz6-"
"vWNfmw3vyPVQ7VdYjaQBXPcRud5XPkwIifx3z5vENOzqFWKHbgH2QdQxXv9bxHjkF-CrQN7deqJUXo6-eQj2q-"
"B4U7kgsNcR18PiQH55RHhAhZ1xSvOyJH56E7o36Ws8kaEfpXu05O2u70FfKRfmHcpzqNYTBeuw041vYZVlcBNoixpd0lh-"
"2lT1m2b1EwdXFN14b6BPRGdTbL29j9qnUse0nO6pxBTdmi_mRHDlc0oU-2P5P9tk9_wWRNTcmNy_ZgJY_VZnumkR_XbRvsPtlld0WsO_"
"haO6DOM8Z9TLG_XFjk6IIuKFDfLB4Yem5P9eKSHF54_hTtFWmJM0dq2os-"
"ObigDxTjbEY5aTOcL3Ya5KDD3GcUh1VxTui0yGnn2Z89vyzxPpepCeOkc76qx8feFPc3QxXjQ6dNjjvc52OK10yaIa6FO3BuNW_h-"
"V62TyZpYi7Z6ZG_t2nUl-zwIIh6kj32yJFeoaHl1iqdPnnf8_xgDiCd4u1kbYeYj3YG5L0NRSIydn3mUtJXN2cey1-Tw074BKiK-"
"Zoqttct1NL0GergDcHN7leGajNvv3fgN_SF3s8zfrPqH-pr-Wi-d1r8_zX33TjCNvftVsh-l6L3GmA_"
"LSFfTLhSQr5KjrpsTF0P6fNrZaEfdmtwJitf6IaTbJ6D-lnNvUvstsmHLmeTecDcZcDQvr8iifvtXcj1ts-"
"LXereozlASfvGNpZ0IVd3-RivmWVx_da1I_stvWDuIbGkie0HfKzLg3kY3YJifFrf4tNrHEnue0ROu-"
"EfGCBJ6M8wPp7Mm1kc616Rwy4NHjFOLetl8dq35ABshuNn2RDazKqQIwvQZzJBbFYW53qrRg4tz6UTD9NZ3BOz6tG6ztR7xPoTsvCsrA"
"bUw54LXspm_vbaK6ySE71aC_KDBcXgjC4nUCghfrGx7VkyLpM-bZ2Tby3qL-fUcYQ94gTntTrkmzWeWnTCpngfxhDfoVldsm9RB-_"
"FSeJ7PwvyigXUfEH9tJ57ppoYB9zaivr4Dp7_TD0VNylubl2SA9ghWj8Yao6OffLrlY2Y74KZ_Khk3mHft7qmlIdh1ufovP2Au_"
"yXELs_MrV47CAaG_o8WAU9YmNxn8yy1364ZL5Ps7kM9M1_e2ENI_tBEY_W8OI7GGtETtb68xDt88jiHoB1BWdPnSl_"
"3PEORhPX8hbkcZCnTxyLK_Edn3UDsuwPfJKN3z1VSqxxu9KRPi_x-wrtK_"
"qR1l10Ti9RxyLtE68cU4yRPcDIHl3wMZaTNPHbiV6NfOixp2KNOmsUQO-"
"W9Hg8cOEenzGspyNJutAfek3yEeLpJ895u8pC1tJjjOq1YF98R39aVnLt2muTkx4UHD6dhZj_qiUxl-t1gXOyKPxXIZ-"
"tecobDpbuN34w9VinrTmhjgEbPNFnpHcY323h-kAd02MP1EFxUM-3xwDkIR5D7Iz1uO_"
"XG5H9HgdPRH1BjsfdRfZ5Kt4xit6Paop4P5cW2b9coLUsxLYhlO1XyGEf8HiB3u-Jc3u_Qfb7LDIDcr-33QPI8KB-k3z72kPte87za_"
"sDs1P8zqLfIt_26UNIi5G13lp62Bmoscw5ed-fc4c_PMDwrO9pchJX8Fq_3yHHfXq_egSI7dXMvCVC5uiCnb1MrK791cixlUV-"
"teb8fQ4piEEBaEUI52zXD2R9ZvH9RR_qt37I_MCLLnC9txhL1ArGrru2eIwp59aUfZuc9AH3lpCNkbtyiKl0j3UbO_tDsC_"
"wg3AWhSSWH8ti-1yTA1g_zU1e_SeuZ_u30TmuUOwZW0fN6ft_rpCDzxTvw5s5byAHDXI8-PLX0OU73gNo4rphcEmOBt4Ce7u5p5TE_"
"jOwyaHNfLSPLxviWmswIn83CJcQnW6xyaYMCFC0g_Q8ybp5ZwwMgEcMniAEMA6mpn1kew92hZzZNJzy1bPeHRxW04R7savkGzt6E-"
"FtmgoIdsQ52q6RU5s9T-bMAefGepRGfOZx0orl6-"
"TADqdYvyx6ayTWtQFn9gQGz9p6T9nqKSOyLajNuTujD56PvV3Rcu7o7fPI1hHenDOHbd6F7SXtJCl64g5pc3aHab-32-"
"TYdrxH5uJnJhviet3urOUBflF5RRJjg92FvUSoSYtd5rnpXPzKgSSxDhb4AV2XLi5aAxu5vm_3yJEdFbLUQfieOAZtiH0bYt_B-Juao_"
"sA7AelA2R4dO9qzpti237rAa48Gekd5Og-JN_bX_7sFYfe4stfIXP1_S__7k44dq8nyck-6BvlS-"
"hyRd43nKJNnUf8rURJXIfaN5EvgFtbFCpHhuEw5ESpTHLynX0Lcf3so_0jU5PF_nhHjhvLJxoVrqgv5vC1YY18Pwz9-6gLXKOQ1ZeC_"
"qiW_3ZlWCf7tTmd4nGRqu1SdciwRfaH3mzHu2hD6JfDc3I8nFO-vpZGMCrnfd3wgpwO6c_"
"8lZVlz8EU97SGHXI09O4ZsIZsDjBjzjCE2mXIF57_Yxf4DUPyRWKsRc6is4l-S2IHVwS9kj669vGt8wWcGAJLWKJvicRYObwkB0MPcB_"
"lxHE_ZDggh5GeDKmdzK-40x4OyachQAqf0im44dAb08gJsv5n5P9ey_Aq0uWROiHG3WIuOwTuMKT8CTtrw9CEMTeEmBtS94XuyEFSzu-"
"-jCrkaHQfPctnGVk5_h2Es41sqq84apHD0WwX7xFzlpFNCiO7kuFb5a_gW6Nb0NsPI7qL4P42d0n3-"
"0Z35HT0Mma748vI3fdVjfyw5hFX3J0w-PqbYjBnxfW7nagcw_A3__"
"dzrhrk5Apy6QuUQAgG76lfcX971SLfV6OO2nIO2vkzLrpnkr5Cpzb5NLLTU6F3VqXcuQADrjgLIGenY2LPSPy-"
"09UIxlE3pAGCYXocO9dN8s01dRweJY1mGIRu9t5PM-K3ZdfR27zVr09hMbmqraPP9m5a5IeWA9HvFC1vzB0GqTkArswD-"
"O4Z0HKRlTcS69x0yGHHW3qPGKcyduby9dpX5Pu2GzDfXRUkoEKPBU8eJMYsVzUMKfF93He5bZCDW7ZgGD83NX0XpqzWv4V6_vbHTD2_-"
"pkixXeKyro22qx5F9UxKz61fpmP4NGepBMhJtxZ5PBu17usuJeLy16T4zu-GNPxE86FNfTNyJ__99_-9v8o_old")
.ok());
TlBufferParser parser(&en);
auto result = telegram_api::help_getCountriesList::fetch_result(parser);
@ -453,7 +513,9 @@ const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(cons
it = countries_.find(language_code);
CHECK(it != countries_.end())
auto *country = it->second.get();
load_country_list(language_code, country->hash, Auto());
if (manager != nullptr) {
manager->load_country_list(language_code, country->hash, Auto());
}
return country;
}
return nullptr;
@ -461,11 +523,15 @@ const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(cons
auto *country = it->second.get();
CHECK(country != nullptr);
if (country->next_reload_time < Time::now()) {
load_country_list(language_code, country->hash, Auto());
if (manager != nullptr && country->next_reload_time < Time::now()) {
manager->load_country_list(language_code, country->hash, Auto());
}
return country;
}
int32 CountryInfoManager::manager_count_ = 0;
std::mutex CountryInfoManager::country_mutex_;
std::unordered_map<string, unique_ptr<CountryInfoManager::CountryList>> CountryInfoManager::countries_;
} // namespace td

View File

@ -13,8 +13,10 @@
#include "td/actor/PromiseFuture.h"
#include "td/utils/common.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include <mutex>
#include <unordered_map>
namespace td {
@ -32,6 +34,9 @@ class CountryInfoManager final : public Actor {
void get_phone_number_info(string phone_number_prefix,
Promise<td_api::object_ptr<td_api::phoneNumberInfo>> &&promise);
static td_api::object_ptr<td_api::phoneNumberInfo> get_phone_number_info_sync(string language_code,
string phone_number_prefix);
CountryInfoManager(const CountryInfoManager &) = delete;
CountryInfoManager &operator=(const CountryInfoManager &) = delete;
CountryInfoManager(CountryInfoManager &&) = delete;
@ -39,6 +44,7 @@ class CountryInfoManager final : public Actor {
~CountryInfoManager() final;
private:
void start_up() final;
void tear_down() final;
struct CallingCodeInfo;
@ -58,13 +64,21 @@ class CountryInfoManager final : public Actor {
void on_get_country_list(const string &language_code,
Result<tl_object_ptr<telegram_api::help_CountriesList>> r_country_list);
void on_get_country_list_impl(const string &language_code,
tl_object_ptr<telegram_api::help_CountriesList> country_list);
static void on_get_country_list_impl(const string &language_code,
tl_object_ptr<telegram_api::help_CountriesList> country_list);
const CountryList *get_country_list(const string &language_code);
static const CountryList *get_country_list(CountryInfoManager *manager, const string &language_code);
static td_api::object_ptr<td_api::phoneNumberInfo> get_phone_number_info_object(const CountryList *list,
Slice phone_number);
static std::mutex country_mutex_;
static int32 manager_count_;
static std::unordered_map<string, unique_ptr<CountryList>> countries_;
std::unordered_map<string, vector<Promise<Unit>>> pending_load_country_queries_;
std::unordered_map<string, unique_ptr<CountryList>> countries_;
Td *td_;
ActorShared<> parent_;

View File

@ -79,6 +79,9 @@ DialogAction::DialogAction(tl_object_ptr<td_api::ChatAction> &&action) {
init(Type::UploadingVideoNote, uploading_action->progress_);
break;
}
case td_api::chatActionChoosingSticker::ID:
init(Type::ChoosingSticker);
break;
default:
UNREACHABLE();
break;
@ -144,6 +147,9 @@ DialogAction::DialogAction(tl_object_ptr<telegram_api::SendMessageAction> &&acti
init(Type::ImportingMessages, history_import_action->progress_);
break;
}
case telegram_api::sendMessageChooseStickerAction::ID:
init(Type::ChoosingSticker);
break;
default:
UNREACHABLE();
break;
@ -182,6 +188,8 @@ tl_object_ptr<telegram_api::SendMessageAction> DialogAction::get_input_send_mess
return make_tl_object<telegram_api::speakingInGroupCallAction>();
case Type::ImportingMessages:
return make_tl_object<telegram_api::sendMessageHistoryImportAction>(progress_);
case Type::ChoosingSticker:
return make_tl_object<telegram_api::sendMessageChooseStickerAction>();
default:
UNREACHABLE();
return nullptr;
@ -220,6 +228,8 @@ tl_object_ptr<secret_api::SendMessageAction> DialogAction::get_secret_input_send
return make_tl_object<secret_api::sendMessageTypingAction>();
case Type::ImportingMessages:
return make_tl_object<secret_api::sendMessageTypingAction>();
case Type::ChoosingSticker:
return make_tl_object<secret_api::sendMessageTypingAction>();
default:
UNREACHABLE();
return nullptr;
@ -254,6 +264,8 @@ tl_object_ptr<td_api::ChatAction> DialogAction::get_chat_action_object() const {
return td_api::make_object<td_api::chatActionRecordingVideoNote>();
case Type::UploadingVideoNote:
return td_api::make_object<td_api::chatActionUploadingVideoNote>(progress_);
case Type::ChoosingSticker:
return td_api::make_object<td_api::chatActionChoosingSticker>();
case Type::ImportingMessages:
case Type::SpeakingInVoiceChat:
default:
@ -293,9 +305,10 @@ bool DialogAction::is_canceled_by_message_of_type(MessageContentType message_con
case MessageContentType::Location:
case MessageContentType::Venue:
return type_ == Type::ChoosingLocation;
case MessageContentType::Sticker:
return type_ == Type::ChoosingSticker;
case MessageContentType::Game:
case MessageContentType::Invoice:
case MessageContentType::Sticker:
case MessageContentType::Text:
case MessageContentType::Unsupported:
case MessageContentType::ChatCreate:
@ -325,6 +338,7 @@ bool DialogAction::is_canceled_by_message_of_type(MessageContentType message_con
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
return false;
default:
UNREACHABLE();
@ -400,6 +414,8 @@ StringBuilder &operator<<(StringBuilder &string_builder, const DialogAction &act
return "SpeakingInVoiceChat";
case DialogAction::Type::ImportingMessages:
return "ImportingMessages";
case DialogAction::Type::ChoosingSticker:
return "ChoosingSticker";
default:
UNREACHABLE();
return "Cancel";

View File

@ -32,7 +32,8 @@ class DialogAction {
RecordingVideoNote,
UploadingVideoNote,
SpeakingInVoiceChat,
ImportingMessages
ImportingMessages,
ChoosingSticker
};
Type type_ = Type::Cancel;
int32 progress_ = 0;

View File

@ -421,6 +421,10 @@ DialogParticipantStatus get_dialog_participant_status(const tl_object_ptr<td_api
case td_api::chatMemberStatusRestricted::ID: {
auto st = static_cast<const td_api::chatMemberStatusRestricted *>(status.get());
auto permissions = st->permissions_.get();
if (permissions == nullptr) {
return DialogParticipantStatus::Restricted(st->is_member_, st->restricted_until_date_, false, false, false,
false, false, false, false, false, false, false, false);
}
bool can_send_polls = permissions->can_send_polls_;
bool can_send_media = permissions->can_send_media_messages_;
bool can_send_messages = permissions->can_send_messages_ || can_send_media || can_send_polls ||

View File

@ -27,7 +27,6 @@
#include "td/telegram/VoiceNotesManager.h"
#include "td/utils/common.h"
#include "td/utils/format.h"
#include "td/utils/HttpUrl.h"
#include "td/utils/logging.h"
#include "td/utils/MimeType.h"
@ -47,19 +46,17 @@ namespace td {
DocumentsManager::DocumentsManager(Td *td) : td_(td) {
}
tl_object_ptr<td_api::document> DocumentsManager::get_document_object(FileId file_id, PhotoFormat thumbnail_format) {
tl_object_ptr<td_api::document> DocumentsManager::get_document_object(FileId file_id,
PhotoFormat thumbnail_format) const {
if (!file_id.is_valid()) {
return nullptr;
}
LOG(INFO) << "Return document " << file_id << " object";
auto document_it = documents_.find(file_id);
if (document_it == documents_.end() || document_it->second == nullptr) {
return nullptr;
}
auto &document = document_it->second;
LOG_CHECK(document != nullptr) << tag("file_id", file_id);
document->is_changed = false;
auto document = document_it->second.get();
return make_tl_object<td_api::document>(
document->file_name, document->mime_type, get_minithumbnail_object(document->minithumbnail),
get_thumbnail_object(td_->file_manager_.get(), document->thumbnail, thumbnail_format),
@ -490,16 +487,13 @@ FileId DocumentsManager::on_get_document(unique_ptr<GeneralDocument> new_documen
if (d->mime_type != new_document->mime_type) {
LOG(DEBUG) << "Document " << file_id << " mime_type has changed";
d->mime_type = new_document->mime_type;
d->is_changed = true;
}
if (d->file_name != new_document->file_name) {
LOG(DEBUG) << "Document " << file_id << " file_name has changed";
d->file_name = new_document->file_name;
d->is_changed = true;
}
if (d->minithumbnail != new_document->minithumbnail) {
d->minithumbnail = std::move(new_document->minithumbnail);
d->is_changed = true;
}
if (d->thumbnail != new_document->thumbnail) {
if (!d->thumbnail.file_id.is_valid()) {
@ -509,7 +503,6 @@ FileId DocumentsManager::on_get_document(unique_ptr<GeneralDocument> new_documen
<< new_document->thumbnail;
}
d->thumbnail = new_document->thumbnail;
d->is_changed = true;
}
}
@ -665,25 +658,19 @@ FileId DocumentsManager::dup_document(FileId new_id, FileId old_id) {
return new_id;
}
bool DocumentsManager::merge_documents(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 DocumentsManager::merge_documents(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 documents " << new_id << " and " << old_id;
const GeneralDocument *old_ = get_document(old_id);
CHECK(old_ != nullptr);
if (old_id == new_id) {
return old_->is_changed;
}
auto new_it = documents_.find(new_id);
if (new_it == documents_.end() || new_it->second == nullptr) {
auto old_it = documents_.find(old_id);
if (old_it != documents_.end() && old_it->second != nullptr) {
auto &old = old_it->second;
old->is_changed = true;
if (!can_delete_old) {
dup_document(new_id, old_id);
} else {
@ -698,14 +685,11 @@ bool DocumentsManager::merge_documents(FileId new_id, FileId old_id, bool can_de
if (old_->thumbnail != new_->thumbnail) {
// LOG_STATUS(td_->file_manager_->merge(new_->thumbnail.file_id, old_->thumbnail.file_id));
}
new_->is_changed = true;
}
LOG_STATUS(td_->file_manager_->merge(new_id, old_id));
if (can_delete_old) {
documents_.erase(old_id);
}
return true;
}
void DocumentsManager::memory_cleanup() {

View File

@ -75,7 +75,7 @@ class DocumentsManager {
}
};
tl_object_ptr<td_api::document> get_document_object(FileId file_id, PhotoFormat thumbnail_format);
tl_object_ptr<td_api::document> get_document_object(FileId file_id, PhotoFormat thumbnail_format) const;
void memory_cleanup();
@ -105,7 +105,7 @@ class DocumentsManager {
FileId dup_document(FileId new_id, FileId old_id);
bool merge_documents(FileId new_id, FileId old_id, bool can_delete_old);
void merge_documents(FileId new_id, FileId old_id, bool can_delete_old);
template <class StorerT>
void store_document(FileId file_id, StorerT &storer) const;
@ -123,8 +123,6 @@ class DocumentsManager {
string minithumbnail;
PhotoSize thumbnail;
FileId file_id;
bool is_changed = true;
};
const GeneralDocument *get_document(FileId file_id) const;

View File

@ -22,12 +22,15 @@
namespace td {
Game::Game(Td *td, tl_object_ptr<telegram_api::game> &&game, DialogId owner_dialog_id)
Game::Game(Td *td, UserId bot_user_id, tl_object_ptr<telegram_api::game> &&game, FormattedText text,
DialogId owner_dialog_id)
: Game(td, std::move(game->title_), std::move(game->description_), std::move(game->photo_),
std::move(game->document_), owner_dialog_id) {
id_ = game->id_;
access_hash_ = game->access_hash_;
bot_user_id_ = bot_user_id.is_valid() ? bot_user_id : UserId();
short_name_ = game->short_name_;
text_ = std::move(text);
}
Game::Game(Td *td, string title, string description, tl_object_ptr<telegram_api::Photo> &&photo,
@ -61,18 +64,10 @@ Game::Game(UserId bot_user_id, string short_name) : bot_user_id_(bot_user_id), s
photo_.id = 0; // to prevent null photo in td_api
}
bool Game::empty() const {
bool Game::is_empty() const {
return short_name_.empty();
}
void Game::set_bot_user_id(UserId bot_user_id) {
if (bot_user_id.is_valid()) {
bot_user_id_ = bot_user_id;
} else {
bot_user_id_ = UserId();
}
}
UserId Game::get_bot_user_id() const {
return bot_user_id_;
}
@ -83,19 +78,14 @@ vector<FileId> Game::get_file_ids(const Td *td) const {
return result;
}
void Game::set_text(FormattedText &&text) {
text_ = std::move(text);
}
const FormattedText &Game::get_text() const {
return text_;
}
tl_object_ptr<td_api::game> Game::get_game_object(Td *td, bool skip_bot_commands) const {
return make_tl_object<td_api::game>(
id_, short_name_, title_, get_formatted_text_object(text_, skip_bot_commands, -1), description_,
get_photo_object(td->file_manager_.get(), photo_),
td->animations_manager_->get_animation_object(animation_file_id_, "get_game_object"));
return make_tl_object<td_api::game>(id_, short_name_, title_, get_formatted_text_object(text_, skip_bot_commands, -1),
description_, get_photo_object(td->file_manager_.get(), photo_),
td->animations_manager_->get_animation_object(animation_file_id_));
}
bool Game::has_input_media() const {

View File

@ -44,23 +44,22 @@ class Game {
public:
Game() = default;
Game(Td *td, tl_object_ptr<telegram_api::game> &&game, DialogId owner_dialog_id);
Game(Td *td, UserId bot_user_id, tl_object_ptr<telegram_api::game> &&game, FormattedText text,
DialogId owner_dialog_id);
// for inline results
Game(Td *td, string title, string description, tl_object_ptr<telegram_api::Photo> &&photo,
tl_object_ptr<telegram_api::Document> &&document, DialogId owner_dialog_id);
// for outgoing messages
Game(UserId bot_user_id, string short_name);
bool empty() const;
void set_bot_user_id(UserId bot_user_id);
bool is_empty() const;
UserId get_bot_user_id() const;
vector<FileId> get_file_ids(const Td *td) const;
void set_text(FormattedText &&text);
const FormattedText &get_text() const;
tl_object_ptr<td_api::game> get_game_object(Td *td, bool skip_bot_commands) const;

View File

@ -54,6 +54,7 @@ class MemoryManager;
class Td;
class TdDb;
class TempAuthKeyWatchdog;
class ThemeManager;
class TopDialogManager;
class UpdatesManager;
class WebPagesManager;
@ -288,6 +289,13 @@ class Global final : public ActorContext {
memory_manager_ = memory_manager;
}
ActorId<ThemeManager> theme_manager() const {
return theme_manager_;
}
void set_theme_manager(ActorId<ThemeManager> theme_manager) {
theme_manager_ = theme_manager;
}
ActorId<TopDialogManager> top_dialog_manager() const {
return top_dialog_manager_;
}
@ -419,6 +427,7 @@ class Global final : public ActorContext {
ActorId<StickersManager> stickers_manager_;
ActorId<StorageManager> storage_manager_;
ActorId<MemoryManager> memory_manager_;
ActorId<ThemeManager> theme_manager_;
ActorId<TopDialogManager> top_dialog_manager_;
ActorId<UpdatesManager> updates_manager_;
ActorId<WebPagesManager> web_pages_manager_;

View File

@ -41,9 +41,11 @@ class GetGroupCallStreamQuery final : public Td::ResultHandler {
explicit GetGroupCallStreamQuery(Promise<string> &&promise) : promise_(std::move(promise)) {
}
void send(InputGroupCallId input_group_call_id, DcId stream_dc_id, int64 time_offset, int32 scale) {
auto input_stream = make_tl_object<telegram_api::inputGroupCallStream>(input_group_call_id.get_input_group_call(),
time_offset, scale);
void send(InputGroupCallId input_group_call_id, DcId stream_dc_id, int64 time_offset, int32 scale, int32 channel_id,
int32 video_quality) {
int32 stream_flags = 0;
auto input_stream = make_tl_object<telegram_api::inputGroupCallStream>(
stream_flags, input_group_call_id.get_input_group_call(), time_offset, scale, channel_id, video_quality);
int32 flags = 0;
auto query = G()->net_query_creator().create(
telegram_api::upload_getFile(flags, false /*ignored*/, false /*ignored*/, std::move(input_stream), 0, 1 << 20),
@ -639,7 +641,8 @@ class ToggleGroupCallRecordQuery final : public Td::ResultHandler {
explicit ToggleGroupCallRecordQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(InputGroupCallId input_group_call_id, bool is_enabled, const string &title) {
void send(InputGroupCallId input_group_call_id, bool is_enabled, const string &title, bool record_video,
bool use_portrait_orientation) {
int32 flags = 0;
if (is_enabled) {
flags |= telegram_api::phone_toggleGroupCallRecord::START_MASK;
@ -647,8 +650,12 @@ class ToggleGroupCallRecordQuery final : public Td::ResultHandler {
if (!title.empty()) {
flags |= telegram_api::phone_toggleGroupCallRecord::TITLE_MASK;
}
if (record_video) {
flags |= telegram_api::phone_toggleGroupCallRecord::VIDEO_MASK;
}
send_query(G()->net_query_creator().create(telegram_api::phone_toggleGroupCallRecord(
flags, false /*ignored*/, input_group_call_id.get_input_group_call(), title)));
flags, false /*ignored*/, false /*ignored*/, input_group_call_id.get_input_group_call(), title,
use_portrait_orientation)));
}
void on_result(uint64 id, BufferSlice packet) final {
@ -837,6 +844,7 @@ struct GroupCallManager::GroupCall {
bool mute_new_participants = false;
bool allowed_change_mute_new_participants = false;
bool joined_date_asc = false;
bool is_video_recorded = false;
int32 scheduled_start_date = 0;
int32 participant_count = 0;
int32 duration = 0;
@ -873,6 +881,8 @@ struct GroupCallManager::GroupCall {
bool have_pending_record_start_date = false;
int32 pending_record_start_date = 0;
string pending_record_title;
bool pending_record_record_video = false;
bool pending_record_use_portrait_orientation = false;
uint64 toggle_recording_generation = 0;
};
@ -1281,7 +1291,7 @@ void GroupCallManager::set_group_call_default_join_as(DialogId dialog_id, Dialog
if (!dialog_id.is_valid()) {
return promise.set_error(Status::Error(400, "Invalid chat identifier specified"));
}
if (!td_->messages_manager_->have_dialog_force(dialog_id)) {
if (!td_->messages_manager_->have_dialog_force(dialog_id, "set_group_call_default_join_as")) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (!td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
@ -1296,7 +1306,7 @@ void GroupCallManager::set_group_call_default_join_as(DialogId dialog_id, Dialog
break;
case DialogType::Chat:
case DialogType::Channel:
if (!td_->messages_manager_->have_dialog_force(as_dialog_id)) {
if (!td_->messages_manager_->have_dialog_force(as_dialog_id, "set_group_call_default_join_as 2")) {
return promise.set_error(Status::Error(400, "Participant chat not found"));
}
break;
@ -1541,6 +1551,12 @@ int32 GroupCallManager::get_group_call_record_start_date(const GroupCall *group_
: group_call->record_start_date;
}
bool GroupCallManager::get_group_call_is_video_recorded(const GroupCall *group_call) {
CHECK(group_call != nullptr);
return group_call->have_pending_record_start_date ? group_call->pending_record_record_video
: group_call->is_video_recorded;
}
bool GroupCallManager::get_group_call_has_recording(const GroupCall *group_call) {
CHECK(group_call != nullptr);
return get_group_call_record_start_date(group_call) != 0;
@ -2385,6 +2401,8 @@ int32 GroupCallManager::cancel_join_group_call_presentation_request(InputGroupCa
}
void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id, int64 time_offset, int32 scale,
int32 channel_id,
td_api::object_ptr<td_api::GroupCallVideoQuality> quality,
Promise<string> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
@ -2395,16 +2413,16 @@ void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id,
auto *group_call = get_group_call(input_group_call_id);
if (group_call == nullptr || !group_call->is_inited) {
reload_group_call(input_group_call_id,
PromiseCreator::lambda(
[actor_id = actor_id(this), group_call_id, time_offset, scale, promise = std::move(promise)](
Result<td_api::object_ptr<td_api::groupCall>> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &GroupCallManager::get_group_call_stream_segment, group_call_id,
time_offset, scale, std::move(promise));
}
}));
PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, time_offset, scale, channel_id,
quality = std::move(quality), promise = std::move(promise)](
Result<td_api::object_ptr<td_api::groupCall>> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &GroupCallManager::get_group_call_stream_segment, group_call_id,
time_offset, scale, channel_id, std::move(quality), std::move(promise));
}
}));
return;
}
if (!group_call->is_active || !group_call->stream_dc_id.is_exact()) {
@ -2412,14 +2430,14 @@ void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id,
}
if (!group_call->is_joined) {
if (is_group_call_being_joined(input_group_call_id) || group_call->need_rejoin) {
group_call->after_join.push_back(
PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, time_offset, scale,
promise = std::move(promise)](Result<Unit> &&result) mutable {
group_call->after_join.push_back(PromiseCreator::lambda(
[actor_id = actor_id(this), group_call_id, time_offset, scale, channel_id, quality = std::move(quality),
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &GroupCallManager::get_group_call_stream_segment, group_call_id, time_offset,
scale, std::move(promise));
scale, channel_id, std::move(quality), std::move(promise));
}
}));
return;
@ -2427,6 +2445,23 @@ void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id,
return promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING"));
}
int32 video_quality = 0;
if (quality != nullptr) {
switch (quality->get_id()) {
case td_api::groupCallVideoQualityThumbnail::ID:
video_quality = 0;
break;
case td_api::groupCallVideoQualityMedium::ID:
video_quality = 1;
break;
case td_api::groupCallVideoQualityFull::ID:
video_quality = 2;
break;
default:
UNREACHABLE();
}
}
auto query_promise =
PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, audio_source = group_call->audio_source,
promise = std::move(promise)](Result<string> &&result) mutable {
@ -2434,7 +2469,7 @@ void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id,
audio_source, std::move(result), std::move(promise));
});
td_->create_handler<GetGroupCallStreamQuery>(std::move(query_promise))
->send(input_group_call_id, group_call->stream_dc_id, time_offset, scale);
->send(input_group_call_id, group_call->stream_dc_id, time_offset, scale, channel_id, video_quality);
}
void GroupCallManager::finish_get_group_call_stream_segment(InputGroupCallId input_group_call_id, int32 audio_source,
@ -3483,6 +3518,7 @@ void GroupCallManager::get_group_call_invite_link(GroupCallId group_call_id, boo
}
void GroupCallManager::toggle_group_call_recording(GroupCallId group_call_id, bool is_enabled, string title,
bool record_video, bool use_portrait_orientation,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
@ -3492,17 +3528,18 @@ void GroupCallManager::toggle_group_call_recording(GroupCallId group_call_id, bo
auto *group_call = get_group_call(input_group_call_id);
if (group_call == nullptr || !group_call->is_inited) {
reload_group_call(input_group_call_id,
PromiseCreator::lambda(
[actor_id = actor_id(this), group_call_id, is_enabled, title, promise = std::move(promise)](
Result<td_api::object_ptr<td_api::groupCall>> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &GroupCallManager::toggle_group_call_recording, group_call_id,
is_enabled, std::move(title), std::move(promise));
}
}));
reload_group_call(
input_group_call_id,
PromiseCreator::lambda(
[actor_id = actor_id(this), group_call_id, is_enabled, title, record_video, use_portrait_orientation,
promise = std::move(promise)](Result<td_api::object_ptr<td_api::groupCall>> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &GroupCallManager::toggle_group_call_recording, group_call_id, is_enabled,
std::move(title), record_video, use_portrait_orientation, std::move(promise));
}
}));
return;
}
if (!group_call->is_active || !group_call->can_be_managed) {
@ -3518,24 +3555,29 @@ void GroupCallManager::toggle_group_call_recording(GroupCallId group_call_id, bo
// there is no reason to save promise; we will send an update with actual value anyway
if (!group_call->have_pending_record_start_date) {
send_toggle_group_call_recording_query(input_group_call_id, is_enabled, title, toggle_recording_generation_ + 1);
send_toggle_group_call_recording_query(input_group_call_id, is_enabled, title, record_video,
use_portrait_orientation, toggle_recording_generation_ + 1);
}
group_call->have_pending_record_start_date = true;
group_call->pending_record_start_date = is_enabled ? G()->unix_time() : 0;
group_call->pending_record_title = std::move(title);
group_call->pending_record_record_video = record_video;
group_call->pending_record_use_portrait_orientation = use_portrait_orientation;
group_call->toggle_recording_generation = ++toggle_recording_generation_;
send_update_group_call(group_call, "toggle_group_call_recording");
promise.set_value(Unit());
}
void GroupCallManager::send_toggle_group_call_recording_query(InputGroupCallId input_group_call_id, bool is_enabled,
const string &title, uint64 generation) {
const string &title, bool record_video,
bool use_portrait_orientation, uint64 generation) {
auto promise =
PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, generation](Result<Unit> result) {
send_closure(actor_id, &GroupCallManager::on_toggle_group_call_recording, input_group_call_id, generation,
std::move(result));
});
td_->create_handler<ToggleGroupCallRecordQuery>(std::move(promise))->send(input_group_call_id, is_enabled, title);
td_->create_handler<ToggleGroupCallRecordQuery>(std::move(promise))
->send(input_group_call_id, is_enabled, title, record_video, use_portrait_orientation);
}
void GroupCallManager::on_toggle_group_call_recording(InputGroupCallId input_group_call_id, uint64 generation,
@ -3554,13 +3596,17 @@ void GroupCallManager::on_toggle_group_call_recording(InputGroupCallId input_gro
if (group_call->toggle_recording_generation != generation && group_call->can_be_managed) {
// need to send another request
send_toggle_group_call_recording_query(input_group_call_id, group_call->pending_record_start_date != 0,
group_call->pending_record_title, group_call->toggle_recording_generation);
group_call->pending_record_title, group_call->pending_record_record_video,
group_call->pending_record_use_portrait_orientation,
group_call->toggle_recording_generation);
return;
}
int32 current_record_start_date = get_group_call_record_start_date(group_call);
auto current_record_start_date = get_group_call_record_start_date(group_call);
auto current_is_video_recorded = get_group_call_is_video_recorded(group_call);
group_call->have_pending_record_start_date = false;
if (current_record_start_date != get_group_call_record_start_date(group_call)) {
if (current_record_start_date != get_group_call_record_start_date(group_call) ||
current_is_video_recorded != get_group_call_is_video_recorded(group_call)) {
send_update_group_call(group_call, "on_toggle_group_call_recording");
}
}
@ -4179,13 +4225,16 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptr<telegra
}
if ((group_call->flags_ & telegram_api::groupCall::RECORD_START_DATE_MASK) != 0) {
call.record_start_date = group_call->record_start_date_;
call.is_video_recorded = group_call->record_video_active_;
if (call.record_start_date <= 0) {
LOG(ERROR) << "Receive invalid record start date " << group_call->record_start_date_ << " in "
<< input_group_call_id;
call.record_start_date = 0;
call.is_video_recorded = false;
}
} else {
call.record_start_date = 0;
call.is_video_recorded = false;
}
if ((group_call->flags_ & telegram_api::groupCall::SCHEDULE_DATE_MASK) != 0) {
call.scheduled_start_date = group_call->schedule_date_;
@ -4331,12 +4380,16 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptr<telegra
group_call->stream_dc_id_version = call.stream_dc_id_version;
}
// flag call.joined_date_asc must not change
if (call.record_start_date != group_call->record_start_date &&
if ((call.record_start_date != group_call->record_start_date ||
call.is_video_recorded != group_call->is_video_recorded) &&
call.record_start_date_version >= group_call->record_start_date_version) {
int32 old_record_start_date = get_group_call_record_start_date(group_call);
bool old_is_video_recorded = get_group_call_is_video_recorded(group_call);
group_call->record_start_date = call.record_start_date;
group_call->is_video_recorded = call.is_video_recorded;
group_call->record_start_date_version = call.record_start_date_version;
if (old_record_start_date != get_group_call_record_start_date(group_call)) {
if (old_record_start_date != get_group_call_record_start_date(group_call) ||
old_is_video_recorded != get_group_call_is_video_recorded(group_call)) {
need_update = true;
}
}
@ -4744,11 +4797,13 @@ tl_object_ptr<td_api::groupCall> GroupCallManager::get_group_call_object(
bool can_enable_video = get_group_call_can_enable_video(group_call);
int32 record_start_date = get_group_call_record_start_date(group_call);
int32 record_duration = record_start_date == 0 ? 0 : max(G()->unix_time() - record_start_date + 1, 1);
bool is_video_recorded = get_group_call_is_video_recorded(group_call);
return td_api::make_object<td_api::groupCall>(
group_call->group_call_id.get(), get_group_call_title(group_call), scheduled_start_date, start_subscribed,
is_active, is_joined, group_call->need_rejoin, group_call->can_be_managed, group_call->participant_count,
group_call->loaded_all_participants, std::move(recent_speakers), is_my_video_enabled, is_my_video_paused,
can_enable_video, mute_new_participants, can_change_mute_new_participants, record_duration, group_call->duration);
can_enable_video, mute_new_participants, can_change_mute_new_participants, record_duration, is_video_recorded,
group_call->duration);
}
tl_object_ptr<td_api::updateGroupCall> GroupCallManager::get_update_group_call_object(

View File

@ -64,7 +64,8 @@ class GroupCallManager final : public Actor {
void reload_group_call(InputGroupCallId input_group_call_id,
Promise<td_api::object_ptr<td_api::groupCall>> &&promise);
void get_group_call_stream_segment(GroupCallId group_call_id, int64 time_offset, int32 scale,
void get_group_call_stream_segment(GroupCallId group_call_id, int64 time_offset, int32 scale, int32 channel_id,
td_api::object_ptr<td_api::GroupCallVideoQuality> quality,
Promise<string> &&promise);
void start_scheduled_group_call(GroupCallId group_call_id, Promise<Unit> &&promise);
@ -99,7 +100,8 @@ class GroupCallManager final : public Actor {
void get_group_call_invite_link(GroupCallId group_call_id, bool can_self_unmute, Promise<string> &&promise);
void toggle_group_call_recording(GroupCallId group_call_id, bool is_enabled, string title, Promise<Unit> &&promise);
void toggle_group_call_recording(GroupCallId group_call_id, bool is_enabled, string title, bool record_video,
bool use_portrait_orientation, Promise<Unit> &&promise);
void set_group_call_participant_is_speaking(GroupCallId group_call_id, int32 audio_source, bool is_speaking,
Promise<Unit> &&promise, int32 date = 0);
@ -220,6 +222,8 @@ class GroupCallManager final : public Actor {
static int32 get_group_call_record_start_date(const GroupCall *group_call);
static bool get_group_call_is_video_recorded(const GroupCall *group_call);
static bool get_group_call_has_recording(const GroupCall *group_call);
static bool get_group_call_can_enable_video(const GroupCall *group_call);
@ -316,7 +320,8 @@ class GroupCallManager final : public Actor {
Result<Unit> &&result);
void send_toggle_group_call_recording_query(InputGroupCallId input_group_call_id, bool is_enabled,
const string &title, uint64 generation);
const string &title, bool record_video, bool use_portrait_orientation,
uint64 generation);
void on_toggle_group_call_recording(InputGroupCallId input_group_call_id, uint64 generation, Result<Unit> &&result);

View File

@ -1307,8 +1307,7 @@ void InlineQueriesManager::on_get_inline_query_results(DialogId dialog_id, UserI
auto animation = make_tl_object<td_api::inlineQueryResultAnimation>();
animation->id_ = std::move(result->id_);
animation->animation_ =
td_->animations_manager_->get_animation_object(parsed_document.file_id, "inlineQueryResultAnimation");
animation->animation_ = td_->animations_manager_->get_animation_object(parsed_document.file_id);
animation->title_ = std::move(result->title_);
if (!register_inline_message_content(results->query_id_, animation->id_, parsed_document.file_id,
@ -1623,8 +1622,7 @@ void InlineQueriesManager::on_get_inline_query_results(DialogId dialog_id, UserI
} else if (is_animation && parsed_document.type == Document::Type::Animation) {
auto animation = make_tl_object<td_api::inlineQueryResultAnimation>();
animation->id_ = std::move(result->id_);
animation->animation_ =
td_->animations_manager_->get_animation_object(file_id, "inlineQueryResultAnimationCached");
animation->animation_ = td_->animations_manager_->get_animation_object(file_id);
animation->title_ = std::move(result->title_);
if (!register_inline_message_content(results->query_id_, animation->id_, file_id,
std::move(result->send_message_), td_api::inputMessageAnimation::ID,

View File

@ -199,4 +199,31 @@ string get_json_string(const td_api::JsonValue *json_value) {
return json_encode<string>(JsonableJsonValue(json_value));
}
bool get_json_value_bool(telegram_api::object_ptr<telegram_api::JSONValue> &&json_value, Slice name) {
CHECK(json_value != nullptr);
if (json_value->get_id() == telegram_api::jsonBool::ID) {
return static_cast<const telegram_api::jsonBool *>(json_value.get())->value_;
}
LOG(ERROR) << "Expected Boolean as " << name << ", but found " << to_string(json_value);
return false;
}
int32 get_json_value_int(telegram_api::object_ptr<telegram_api::JSONValue> &&json_value, Slice name) {
CHECK(json_value != nullptr);
if (json_value->get_id() == telegram_api::jsonNumber::ID) {
return static_cast<int32>(static_cast<const telegram_api::jsonNumber *>(json_value.get())->value_);
}
LOG(ERROR) << "Expected Integer as " << name << ", but found " << to_string(json_value);
return 0;
}
string get_json_value_string(telegram_api::object_ptr<telegram_api::JSONValue> &&json_value, Slice name) {
CHECK(json_value != nullptr);
if (json_value->get_id() == telegram_api::jsonString::ID) {
return std::move(static_cast<const telegram_api::jsonString *>(json_value.get())->value_);
}
LOG(ERROR) << "Expected String as " << name << ", but found " << to_string(json_value);
return string();
}
} // namespace td

View File

@ -26,4 +26,10 @@ tl_object_ptr<telegram_api::JSONValue> convert_json_value(td_api::object_ptr<td_
string get_json_string(const td_api::JsonValue *json_value);
bool get_json_value_bool(telegram_api::object_ptr<telegram_api::JSONValue> &&json_value, Slice name);
int32 get_json_value_int(telegram_api::object_ptr<telegram_api::JSONValue> &&json_value, Slice name);
string get_json_value_string(telegram_api::object_ptr<telegram_api::JSONValue> &&json_value, Slice name);
} // namespace td

View File

@ -84,6 +84,7 @@
#include "td/utils/tl_helpers.h"
#include "td/utils/utf8.h"
#include <limits>
#include <utility>
namespace td {
@ -723,6 +724,19 @@ class MessageInviteToGroupCall final : public MessageContent {
}
};
class MessageChatSetTheme final : public MessageContent {
public:
string emoji;
MessageChatSetTheme() = default;
explicit MessageChatSetTheme(string &&emoji) : emoji(std::move(emoji)) {
}
MessageContentType get_type() const final {
return MessageContentType::ChatSetTheme;
}
};
template <class StorerT>
static void store(const MessageContent *content, StorerT &storer) {
CHECK(content != nullptr);
@ -1016,6 +1030,11 @@ static void store(const MessageContent *content, StorerT &storer) {
store(m->user_ids, storer);
break;
}
case MessageContentType::ChatSetTheme: {
auto m = static_cast<const MessageChatSetTheme *>(content);
store(m->emoji, storer);
break;
}
default:
UNREACHABLE();
}
@ -1422,6 +1441,12 @@ static void parse(unique_ptr<MessageContent> &content, ParserT &parser) {
content = std::move(m);
break;
}
case MessageContentType::ChatSetTheme: {
auto m = make_unique<MessageChatSetTheme>();
parse(m->emoji, parser);
content = std::move(m);
break;
}
default:
LOG(FATAL) << "Have unknown message content type " << static_cast<int32>(content_type);
}
@ -2035,6 +2060,7 @@ bool can_have_input_media(const Td *td, const MessageContent *content) {
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
return false;
case MessageContentType::Animation:
case MessageContentType::Audio:
@ -2149,6 +2175,7 @@ SecretInputMedia get_secret_input_media(const MessageContent *content, Td *td,
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
break;
default:
UNREACHABLE();
@ -2264,6 +2291,7 @@ static tl_object_ptr<telegram_api::InputMedia> get_input_media_impl(
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
break;
default:
UNREACHABLE();
@ -2427,6 +2455,7 @@ void delete_message_content_thumbnail(MessageContent *content, Td *td) {
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
break;
default:
UNREACHABLE();
@ -2594,6 +2623,7 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
UNREACHABLE();
}
return Status::OK();
@ -2719,6 +2749,7 @@ static int32 get_message_content_media_index_mask(const MessageContent *content,
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
return 0;
default:
UNREACHABLE();
@ -2740,6 +2771,15 @@ MessageId get_message_content_pinned_message_id(const MessageContent *content) {
}
}
string get_message_content_theme_name(const MessageContent *content) {
switch (content->get_type()) {
case MessageContentType::ChatSetTheme:
return static_cast<const MessageChatSetTheme *>(content)->emoji;
default:
return string();
}
}
FullMessageId get_message_content_replied_message_id(DialogId dialog_id, const MessageContent *content) {
switch (content->get_type()) {
case MessageContentType::PinMessage:
@ -2943,8 +2983,10 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
case MessageContentType::Animation: {
auto old_ = static_cast<const MessageAnimation *>(old_content);
auto new_ = static_cast<const MessageAnimation *>(new_content);
if (new_->file_id != old_->file_id &&
(!need_merge_files || td->animations_manager_->merge_animations(new_->file_id, old_->file_id, false))) {
if (new_->file_id != old_->file_id) {
if (need_merge_files) {
td->animations_manager_->merge_animations(new_->file_id, old_->file_id, false);
}
need_update = true;
}
if (old_->caption != new_->caption) {
@ -2955,8 +2997,10 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
case MessageContentType::Audio: {
auto old_ = static_cast<const MessageAudio *>(old_content);
auto new_ = static_cast<const MessageAudio *>(new_content);
if (new_->file_id != old_->file_id &&
(!need_merge_files || td->audios_manager_->merge_audios(new_->file_id, old_->file_id, false))) {
if (new_->file_id != old_->file_id) {
if (need_merge_files) {
td->audios_manager_->merge_audios(new_->file_id, old_->file_id, false);
}
need_update = true;
}
if (old_->caption != new_->caption) {
@ -2975,8 +3019,10 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
case MessageContentType::Document: {
auto old_ = static_cast<const MessageDocument *>(old_content);
auto new_ = static_cast<const MessageDocument *>(new_content);
if (new_->file_id != old_->file_id &&
(!need_merge_files || td->documents_manager_->merge_documents(new_->file_id, old_->file_id, false))) {
if (new_->file_id != old_->file_id) {
if (need_merge_files) {
td->documents_manager_->merge_documents(new_->file_id, old_->file_id, false);
}
need_update = true;
}
if (old_->caption != new_->caption) {
@ -3108,8 +3154,10 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
case MessageContentType::Sticker: {
auto old_ = static_cast<const MessageSticker *>(old_content);
auto new_ = static_cast<const MessageSticker *>(new_content);
if (new_->file_id != old_->file_id &&
(!need_merge_files || td->stickers_manager_->merge_stickers(new_->file_id, old_->file_id, false))) {
if (new_->file_id != old_->file_id) {
if (need_merge_files) {
td->stickers_manager_->merge_stickers(new_->file_id, old_->file_id, false);
}
need_update = true;
}
break;
@ -3129,8 +3177,10 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
case MessageContentType::Video: {
auto old_ = static_cast<const MessageVideo *>(old_content);
auto new_ = static_cast<const MessageVideo *>(new_content);
if (new_->file_id != old_->file_id &&
(!need_merge_files || td->videos_manager_->merge_videos(new_->file_id, old_->file_id, false))) {
if (new_->file_id != old_->file_id) {
if (need_merge_files) {
td->videos_manager_->merge_videos(new_->file_id, old_->file_id, false);
}
need_update = true;
}
if (old_->caption != new_->caption) {
@ -3141,8 +3191,10 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
case MessageContentType::VideoNote: {
auto old_ = static_cast<const MessageVideoNote *>(old_content);
auto new_ = static_cast<const MessageVideoNote *>(new_content);
if (new_->file_id != old_->file_id &&
(!need_merge_files || td->video_notes_manager_->merge_video_notes(new_->file_id, old_->file_id, false))) {
if (new_->file_id != old_->file_id) {
if (need_merge_files) {
td->video_notes_manager_->merge_video_notes(new_->file_id, old_->file_id, false);
}
need_update = true;
}
if (old_->is_viewed != new_->is_viewed) {
@ -3153,8 +3205,10 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
case MessageContentType::VoiceNote: {
auto old_ = static_cast<const MessageVoiceNote *>(old_content);
auto new_ = static_cast<const MessageVoiceNote *>(new_content);
if (new_->file_id != old_->file_id &&
(!need_merge_files || td->voice_notes_manager_->merge_voice_notes(new_->file_id, old_->file_id, false))) {
if (new_->file_id != old_->file_id) {
if (need_merge_files) {
td->voice_notes_manager_->merge_voice_notes(new_->file_id, old_->file_id, false);
}
need_update = true;
}
if (old_->caption != new_->caption) {
@ -3377,6 +3431,14 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
}
break;
}
case MessageContentType::ChatSetTheme: {
auto old_ = static_cast<const MessageChatSetTheme *>(old_content);
auto new_ = static_cast<const MessageChatSetTheme *>(new_content);
if (old_->emoji != new_->emoji) {
need_update = true;
}
break;
}
case MessageContentType::Unsupported: {
auto old_ = static_cast<const MessageUnsupported *>(old_content);
auto new_ = static_cast<const MessageUnsupported *>(new_content);
@ -3512,6 +3574,7 @@ bool merge_message_content_file_id(Td *td, MessageContent *message_content, File
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
LOG(ERROR) << "Receive new file " << new_file_id << " in a sent message of the type " << content_type;
break;
default:
@ -4110,14 +4173,11 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message,
case telegram_api::messageMediaGame::ID: {
auto message_game = move_tl_object_as<telegram_api::messageMediaGame>(media);
auto m = make_unique<MessageGame>(Game(td, std::move(message_game->game_), owner_dialog_id));
if (m->game.empty()) {
auto m =
make_unique<MessageGame>(Game(td, via_bot_user_id, std::move(message_game->game_), message, owner_dialog_id));
if (m->game.is_empty()) {
break;
}
m->game.set_bot_user_id(via_bot_user_id);
m->game.set_text(std::move(message));
return std::move(m);
}
case telegram_api::messageMediaInvoice::ID:
@ -4381,6 +4441,7 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
return nullptr;
default:
UNREACHABLE();
@ -4640,6 +4701,10 @@ unique_ptr<MessageContent> get_action_message_content(Td *td, tl_object_ptr<tele
return make_unique<MessageGroupCall>(InputGroupCallId(scheduled_group_call->call_), -1,
scheduled_group_call->schedule_date_);
}
case telegram_api::messageActionSetChatTheme::ID: {
auto set_chat_theme = move_tl_object_as<telegram_api::messageActionSetChatTheme>(action);
return td::make_unique<MessageChatSetTheme>(std::move(set_chat_theme->emoticon_));
}
default:
UNREACHABLE();
}
@ -4656,7 +4721,7 @@ tl_object_ptr<td_api::MessageContent> get_message_content_object(const MessageCo
case MessageContentType::Animation: {
const MessageAnimation *m = static_cast<const MessageAnimation *>(content);
return make_tl_object<td_api::messageAnimation>(
td->animations_manager_->get_animation_object(m->file_id, "get_message_content_object"),
td->animations_manager_->get_animation_object(m->file_id),
get_formatted_text_object(m->caption, skip_bot_commands, max_media_timestamp), is_content_secret);
}
case MessageContentType::Audio: {
@ -4874,6 +4939,10 @@ tl_object_ptr<td_api::MessageContent> get_message_content_object(const MessageCo
td->group_call_manager_->get_group_call_id(m->input_group_call_id, DialogId()).get(),
td->contacts_manager_->get_user_ids_object(m->user_ids, "MessageInviteToGroupCall"));
}
case MessageContentType::ChatSetTheme: {
const MessageChatSetTheme *m = static_cast<const MessageChatSetTheme *>(content);
return make_tl_object<td_api::messageChatSetTheme>(m->emoji);
}
default:
UNREACHABLE();
return nullptr;
@ -5222,6 +5291,7 @@ string get_message_content_search_text(const Td *td, const MessageContent *conte
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
return string();
default:
UNREACHABLE();
@ -5431,6 +5501,8 @@ void add_message_content_dependencies(Dependencies &dependencies, const MessageC
dependencies.user_ids.insert(content->user_ids.begin(), content->user_ids.end());
break;
}
case MessageContentType::ChatSetTheme:
break;
default:
UNREACHABLE();
break;

View File

@ -134,6 +134,8 @@ int32 get_message_content_index_mask(const MessageContent *content, const Td *td
MessageId get_message_content_pinned_message_id(const MessageContent *content);
string get_message_content_theme_name(const MessageContent *content);
FullMessageId get_message_content_replied_message_id(DialogId dialog_id, const MessageContent *content);
std::pair<InputGroupCallId, bool> get_message_content_group_call_info(const MessageContent *content);

View File

@ -102,6 +102,8 @@ StringBuilder &operator<<(StringBuilder &string_builder, MessageContentType cont
return string_builder << "GroupCall";
case MessageContentType::InviteToGroupCall:
return string_builder << "InviteToGroupCall";
case MessageContentType::ChatSetTheme:
return string_builder << "ChatSetTheme";
default:
UNREACHABLE();
return string_builder;
@ -156,6 +158,7 @@ bool is_allowed_media_group_content(MessageContentType content_type) {
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
return false;
default:
UNREACHABLE();
@ -218,6 +221,7 @@ bool is_secret_message_content(int32 ttl, MessageContentType content_type) {
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
return false;
default:
UNREACHABLE();
@ -273,6 +277,7 @@ bool is_service_message_content(MessageContentType content_type) {
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
return true;
default:
UNREACHABLE();
@ -328,6 +333,7 @@ bool can_have_message_content_caption(MessageContentType content_type) {
case MessageContentType::ProximityAlertTriggered:
case MessageContentType::GroupCall:
case MessageContentType::InviteToGroupCall:
case MessageContentType::ChatSetTheme:
return false;
default:
UNREACHABLE();

View File

@ -60,7 +60,8 @@ enum class MessageContentType : int32 {
Dice,
ProximityAlertTriggered,
GroupCall,
InviteToGroupCall
InviteToGroupCall,
ChatSetTheme
};
StringBuilder &operator<<(StringBuilder &string_builder, MessageContentType content_type);

View File

@ -1873,7 +1873,7 @@ Result<vector<MessageEntity>> parse_markdown(string &text) {
case '[': {
string url;
if (text[i + 1] != '(') {
// use text as a url
// use text as a URL
url.assign(text, begin_pos + 1, i - begin_pos - 1);
} else {
i += 2;
@ -2070,7 +2070,7 @@ static Result<vector<MessageEntity>> do_parse_markdown_v2(CSlice text, string &r
case MessageEntity::Type::TextUrl: {
string url;
if (text[i + 1] != '(') {
// use text as a url
// use text as a URL
url = result.substr(nested_entities.back().entity_begin_pos);
} else {
i += 2;

View File

@ -35,7 +35,7 @@ bool MessageId::is_valid() const {
}
bool MessageId::is_valid_scheduled() const {
if (id <= 0 || id > max().get()) {
if (id <= 0 || id > (static_cast<int64>(1) << 51)) {
return false;
}
int32 type = (id & TYPE_MASK);
@ -43,7 +43,7 @@ bool MessageId::is_valid_scheduled() const {
}
MessageType MessageId::get_type() const {
if (id <= 0 || id > max().get()) {
if (id <= 0 || id > (static_cast<int64>(1) << 51)) {
return MessageType::None;
}

View File

@ -16,6 +16,7 @@ namespace td {
struct MessageThreadInfo {
DialogId dialog_id;
vector<MessageId> message_ids;
int32 unread_message_count = 0;
};
} // namespace td

File diff suppressed because it is too large Load Diff

View File

@ -31,9 +31,9 @@
#include "td/telegram/MessageId.h"
#include "td/telegram/MessageLinkInfo.h"
#include "td/telegram/MessageReplyInfo.h"
#include "td/telegram/MessageThreadInfo.h"
#include "td/telegram/MessagesDb.h"
#include "td/telegram/MessageSearchFilter.h"
#include "td/telegram/MessageThreadInfo.h"
#include "td/telegram/MessageTtlSetting.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/Notification.h"
@ -290,6 +290,8 @@ class MessagesManager final : public Actor {
void on_update_dialog_last_pinned_message_id(DialogId dialog_id, MessageId last_pinned_message_id);
void on_update_dialog_theme_name(DialogId dialog_id, string theme_name);
void on_update_dialog_has_scheduled_server_messages(DialogId dialog_id, bool has_scheduled_server_messages);
void on_update_dialog_folder_id(DialogId dialog_id, FolderId folder_id);
@ -378,7 +380,7 @@ class MessagesManager final : public Actor {
void reload_voice_chat_on_search(const string &username);
Result<MessageId> send_message(
Result<td_api::object_ptr<td_api::message>> send_message(
DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id,
tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
tl_object_ptr<td_api::InputMessageContent> &&input_message_content) TD_WARN_UNUSED_RESULT;
@ -397,10 +399,12 @@ class MessagesManager final : public Actor {
int64 query_id, const string &result_id,
bool hide_via_bot) TD_WARN_UNUSED_RESULT;
Result<vector<MessageId>> forward_messages(DialogId to_dialog_id, DialogId from_dialog_id,
vector<MessageId> message_ids,
tl_object_ptr<td_api::messageSendOptions> &&options, bool in_game_share,
vector<MessageCopyOptions> &&copy_options) TD_WARN_UNUSED_RESULT;
Result<td_api::object_ptr<td_api::messages>> forward_messages(DialogId to_dialog_id, DialogId from_dialog_id,
vector<MessageId> message_ids,
tl_object_ptr<td_api::messageSendOptions> &&options,
bool in_game_share,
vector<MessageCopyOptions> &&copy_options,
bool only_preview) TD_WARN_UNUSED_RESULT;
Result<vector<MessageId>> resend_messages(DialogId dialog_id, vector<MessageId> message_ids) TD_WARN_UNUSED_RESULT;
@ -494,6 +498,8 @@ class MessagesManager final : public Actor {
void set_dialog_permissions(DialogId dialog_id, const td_api::object_ptr<td_api::chatPermissions> &permissions,
Promise<Unit> &&promise);
void set_dialog_theme(DialogId dialog_id, const string &theme_name, Promise<Unit> &&promise);
void pin_dialog_message(DialogId dialog_id, MessageId message_id, bool disable_notification, bool only_for_self,
bool is_unpin, Promise<Unit> &&promise);
@ -513,7 +519,7 @@ class MessagesManager final : public Actor {
string get_dialog_title(DialogId dialog_id) const;
bool have_dialog(DialogId dialog_id) const;
bool have_dialog_force(DialogId dialog_id, const char *source = "have_dialog_force");
bool have_dialog_force(DialogId dialog_id, const char *source);
bool have_dialog_info(DialogId dialog_id) const;
bool have_dialog_info_force(DialogId dialog_id) const;
@ -528,8 +534,13 @@ class MessagesManager final : public Actor {
void get_recommended_dialog_filters(Promise<td_api::object_ptr<td_api::recommendedChatFilters>> &&promise);
std::pair<int32, vector<DialogId>> get_dialogs(DialogListId dialog_list_id, DialogDate offset, int32 limit,
bool force, Promise<Unit> &&promise);
Result<DialogDate> get_dialog_list_last_date(DialogListId dialog_list_id);
vector<DialogId> get_dialogs(DialogListId dialog_list_id, DialogDate offset, int32 limit, bool exact_limit,
bool force, Promise<Unit> &&promise);
void get_dialogs_from_list(DialogListId dialog_list_id, int32 limit,
Promise<td_api::object_ptr<td_api::chats>> &&promise);
vector<DialogId> search_public_dialogs(const string &query, Promise<Unit> &&promise);
@ -1169,6 +1180,7 @@ class MessagesManager final : public Actor {
InputGroupCallId active_group_call_id;
InputGroupCallId expected_active_group_call_id;
DialogId default_join_group_call_as_dialog_id;
string theme_name;
FolderId folder_id;
vector<DialogListId> dialog_list_ids; // TODO replace with mask
@ -1248,6 +1260,7 @@ class MessagesManager final : public Actor {
bool has_expected_active_group_call_id = false;
bool has_bots = false;
bool is_has_bots_inited = false;
bool is_theme_name_inited = false;
bool increment_view_counter = false;
@ -1784,6 +1797,11 @@ class MessagesManager final : public Actor {
bool is_anonymous_administrator(DialogId dialog_id, string *author_signature) const;
unique_ptr<Message> create_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id,
const MessageSendOptions &options, unique_ptr<MessageContent> &&content,
bool suppress_reply_info, unique_ptr<MessageForwardInfo> forward_info,
bool is_copy) const;
Message *get_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id,
const MessageSendOptions &options, unique_ptr<MessageContent> &&content,
bool *need_update_dialog_pos, bool suppress_reply_info = false,
@ -1842,9 +1860,46 @@ class MessagesManager final : public Actor {
void do_forward_messages(DialogId to_dialog_id, DialogId from_dialog_id, const vector<Message *> &messages,
const vector<MessageId> &message_ids, uint64 log_event_id);
Result<MessageId> forward_message(DialogId to_dialog_id, DialogId from_dialog_id, MessageId message_id,
tl_object_ptr<td_api::messageSendOptions> &&options, bool in_game_share,
MessageCopyOptions &&copy_options) TD_WARN_UNUSED_RESULT;
Result<td_api::object_ptr<td_api::message>> forward_message(DialogId to_dialog_id, DialogId from_dialog_id,
MessageId message_id,
tl_object_ptr<td_api::messageSendOptions> &&options,
bool in_game_share,
MessageCopyOptions &&copy_options) TD_WARN_UNUSED_RESULT;
unique_ptr<MessageForwardInfo> create_message_forward_info(DialogId from_dialog_id, DialogId to_dialog_id,
const Message *forwarded_message) const;
void fix_forwarded_message(Message *m, DialogId to_dialog_id, const Message *forwarded_message,
int64 media_album_id) const;
struct ForwardedMessages {
struct CopiedMessage {
unique_ptr<MessageContent> content;
MessageId top_thread_message_id;
MessageId reply_to_message_id;
unique_ptr<ReplyMarkup> reply_markup;
int64 media_album_id;
bool disable_web_page_preview;
size_t index;
};
vector<CopiedMessage> copied_messages;
struct ForwardedMessageContent {
unique_ptr<MessageContent> content;
int64 media_album_id;
size_t index;
};
vector<ForwardedMessageContent> forwarded_message_contents;
Dialog *from_dialog;
Dialog *to_dialog;
MessageSendOptions message_send_options;
};
Result<ForwardedMessages> get_forwarded_messages(DialogId to_dialog_id, DialogId from_dialog_id,
const vector<MessageId> &message_ids,
tl_object_ptr<td_api::messageSendOptions> &&options,
bool in_game_share, vector<MessageCopyOptions> &&copy_options);
void do_send_media(DialogId dialog_id, Message *m, FileId file_id, FileId thumbnail_file_id,
tl_object_ptr<telegram_api::InputFile> input_file,
@ -2090,7 +2145,7 @@ class MessagesManager final : public Actor {
void load_dialog_list(DialogList &list, int32 limit, Promise<Unit> &&promise);
void load_folder_dialog_list(FolderId folder_id, int32 limit, bool only_local, Promise<Unit> &&promise);
void load_folder_dialog_list(FolderId folder_id, int32 limit, bool only_local);
void on_load_folder_dialog_list_fail(FolderId folder_id, Status error);
@ -2098,6 +2153,10 @@ class MessagesManager final : public Actor {
void preload_folder_dialog_list(FolderId folder_id);
void get_dialogs_from_list_impl(int64 task_id);
void on_get_dialogs_from_list(int64 task_id, Result<Unit> &&result);
static void invalidate_message_indexes(Dialog *d);
void update_message_count_by_index(Dialog *d, int diff, const Message *m);
@ -2284,6 +2343,10 @@ class MessagesManager final : public Actor {
void send_update_chat_action_bar(const Dialog *d);
void send_update_secret_chats_with_user_theme(const Dialog *d) const;
void send_update_chat_theme(const Dialog *d);
void send_update_chat_voice_chat(const Dialog *d);
void send_update_chat_message_ttl_setting(const Dialog *d);
@ -2381,6 +2444,8 @@ class MessagesManager final : public Actor {
void drop_dialog_last_pinned_message_id(Dialog *d);
void set_dialog_theme_name(Dialog *d, string theme_name);
void repair_dialog_scheduled_messages(Dialog *d);
void set_dialog_has_scheduled_server_messages(Dialog *d, bool has_scheduled_server_messages);
@ -2470,6 +2535,8 @@ class MessagesManager final : public Actor {
td_api::object_ptr<td_api::ChatActionBar> get_chat_action_bar_object(const Dialog *d,
bool hide_unarchive = false) const;
string get_dialog_theme_name(const Dialog *d) const;
td_api::object_ptr<td_api::voiceChat> get_voice_chat_object(const Dialog *d) const;
td_api::object_ptr<td_api::chat> get_chat_object(const Dialog *d) const;
@ -3346,6 +3413,17 @@ class MessagesManager final : public Actor {
std::unordered_map<string, DialogId> inaccessible_resolved_usernames_;
std::unordered_set<string> reload_voice_chat_on_search_usernames_;
struct GetDialogsTask {
DialogListId dialog_list_id;
int32 limit;
int32 retry_count;
DialogDate last_dialog_date = MIN_DIALOG_DATE;
Promise<td_api::object_ptr<td_api::chats>> promise;
};
std::unordered_map<int64, GetDialogsTask> get_dialogs_tasks_;
int64 current_get_dialogs_task_id_ = 0;
struct PendingOnGetDialogs {
FolderId folder_id;
vector<tl_object_ptr<telegram_api::Dialog>> dialogs;

View File

@ -2878,6 +2878,9 @@ string NotificationManager::convert_loc_key(const string &loc_key) {
if (loc_key == "CHAT_PHOTO_EDITED") {
return "MESSAGE_CHAT_CHANGE_PHOTO";
}
if (loc_key == "MESSAGE_THEME") {
return "MESSAGE_CHAT_CHANGE_THEME";
}
break;
case 'U':
if (loc_key == "PINNED_AUDIO") {

View File

@ -164,7 +164,7 @@ class NotificationTypePushMessage final : public NotificationType {
if (key == "MESSAGE_ANIMATION") {
auto animations_manager = G()->td().get_actor_unsafe()->animations_manager_.get();
return td_api::make_object<td_api::pushMessageContentAnimation>(
animations_manager->get_animation_object(document.file_id, "MESSAGE_ANIMATION"), arg, is_pinned);
animations_manager->get_animation_object(document.file_id), arg, is_pinned);
}
if (key == "MESSAGE_AUDIO") {
auto audios_manager = G()->td().get_actor_unsafe()->audios_manager_.get();
@ -194,6 +194,9 @@ class NotificationTypePushMessage final : public NotificationType {
if (key == "MESSAGE_CHAT_CHANGE_PHOTO") {
return td_api::make_object<td_api::pushMessageContentChatChangePhoto>();
}
if (key == "MESSAGE_CHAT_CHANGE_THEME") {
return td_api::make_object<td_api::pushMessageContentChatChangeTheme>(arg);
}
if (key == "MESSAGE_CHAT_CHANGE_TITLE") {
return td_api::make_object<td_api::pushMessageContentChatChangeTitle>(arg);
}

View File

@ -6,8 +6,6 @@
//
#pragma once
#include "td/actor/PromiseFuture.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/FullMessageId.h"
@ -16,6 +14,8 @@
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/common.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"

View File

@ -405,10 +405,8 @@ ActorId<SecretChatActor> SecretChatsManager::create_chat_actor_impl(int32 id, bo
if (binlog_replay_finish_flag_) {
send_closure(it_flag.first->second, &SecretChatActor::binlog_replay_finish);
}
return it_flag.first->second.get();
} else {
return it_flag.first->second.get();
}
return it_flag.first->second.get();
}
void SecretChatsManager::hangup() {
@ -417,7 +415,7 @@ void SecretChatsManager::hangup() {
return stop();
}
for (auto &it : id_to_actor_) {
LOG(INFO) << "Ask close SecretChatActor " << tag("id", it.first);
LOG(INFO) << "Ask to close SecretChatActor " << tag("id", it.first);
it.second.reset();
}
if (id_to_actor_.empty()) {
@ -429,13 +427,10 @@ void SecretChatsManager::hangup_shared() {
CHECK(!dummy_mode_);
auto token = get_link_token();
auto it = id_to_actor_.find(static_cast<int32>(token));
if (it != id_to_actor_.end()) {
LOG(INFO) << "Close SecretChatActor " << tag("id", it->first);
it->second.release();
id_to_actor_.erase(it);
} else {
LOG(FATAL) << "Unknown SecretChatActor hangup " << tag("id", static_cast<int32>(token));
}
CHECK(it != id_to_actor_.end());
LOG(INFO) << "Close SecretChatActor " << tag("id", it->first);
it->second.release();
id_to_actor_.erase(it);
if (close_flag_ && id_to_actor_.empty()) {
stop();
}

View File

@ -0,0 +1,145 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/telegram/SponsoredMessages.h"
#include "td/telegram/ChannelId.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/MessageContent.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/net/NetQueryCreator.h"
#include "td/telegram/Td.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/buffer.h"
#include "td/utils/logging.h"
#include "td/utils/Status.h"
namespace td {
class GetSponsoredMessagesQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::sponsoredMessages>> promise_;
ChannelId channel_id_;
public:
explicit GetSponsoredMessagesQuery(Promise<td_api::object_ptr<td_api::sponsoredMessages>> &&promise)
: promise_(std::move(promise)) {
}
void send(ChannelId channel_id) {
channel_id_ = channel_id;
auto input_channel = td->contacts_manager_->get_input_channel(channel_id);
if (input_channel == nullptr) {
return promise_.set_error(Status::Error(3, "Chat info not found"));
}
send_query(G()->net_query_creator().create(telegram_api::channels_getSponsoredMessages(std::move(input_channel))));
}
void on_result(uint64 id, BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::channels_getSponsoredMessages>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto sponsored_messages = result_ptr.move_as_ok();
td->contacts_manager_->on_get_users(std::move(sponsored_messages->users_), "GetSponsoredMessagesQuery");
td->contacts_manager_->on_get_chats(std::move(sponsored_messages->chats_), "GetSponsoredMessagesQuery");
vector<td_api::object_ptr<td_api::sponsoredMessage>> messages;
for (auto &sponsored_message : sponsored_messages->messages_) {
DialogId dialog_id(sponsored_message->from_id_);
if (!dialog_id.is_valid() || !td->messages_manager_->have_dialog_info_force(dialog_id)) {
LOG(ERROR) << "Receive unknown sponsor " << dialog_id;
continue;
}
td->messages_manager_->force_create_dialog(dialog_id, "GetSponsoredMessagesQuery");
auto message_text =
get_message_text(td->contacts_manager_.get(), std::move(sponsored_message->message_),
std::move(sponsored_message->entities_), true, true, 0, false, "GetSponsoredMessagesQuery");
int32 ttl = 0;
auto content = get_message_content(td, std::move(message_text), nullptr, dialog_id, true, UserId(), &ttl);
if (ttl != 0) {
LOG(ERROR) << "Receive sponsored message with TTL " << ttl;
continue;
}
messages.push_back(td_api::make_object<td_api::sponsoredMessage>(
sponsored_message->random_id_.as_slice().str(), dialog_id.get(), sponsored_message->start_param_,
get_message_content_object(content.get(), td, DialogId(channel_id_), 0, false, true, -1)));
}
promise_.set_value(td_api::make_object<td_api::sponsoredMessages>(std::move(messages)));
}
void on_error(uint64 id, Status status) final {
td->contacts_manager_->on_get_channel_error(channel_id_, status, "GetSponsoredMessagesQuery");
promise_.set_error(std::move(status));
}
};
class ViewSponsoredMessageQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
ChannelId channel_id_;
public:
explicit ViewSponsoredMessageQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(ChannelId channel_id, const string &message_id) {
channel_id_ = channel_id;
auto input_channel = td->contacts_manager_->get_input_channel(channel_id);
if (input_channel == nullptr) {
return promise_.set_error(Status::Error(3, "Chat info not found"));
}
send_query(G()->net_query_creator().create(
telegram_api::channels_viewSponsoredMessage(std::move(input_channel), BufferSlice(message_id))));
}
void on_result(uint64 id, BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::channels_viewSponsoredMessage>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
promise_.set_value(Unit());
}
void on_error(uint64 id, Status status) final {
td->contacts_manager_->on_get_channel_error(channel_id_, status, "ViewSponsoredMessageQuery");
promise_.set_error(std::move(status));
}
};
void get_dialog_sponsored_messages(Td *td, DialogId dialog_id,
Promise<td_api::object_ptr<td_api::sponsoredMessages>> &&promise) {
if (!td->messages_manager_->have_dialog_force(dialog_id, "get_sponsored_messages")) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (dialog_id.get_type() != DialogType::Channel ||
td->contacts_manager_->get_channel_type(dialog_id.get_channel_id()) != ContactsManager::ChannelType::Broadcast) {
return promise.set_value(td_api::make_object<td_api::sponsoredMessages>());
}
td->create_handler<GetSponsoredMessagesQuery>(std::move(promise))->send(dialog_id.get_channel_id());
}
void view_sponsored_message(Td *td, DialogId dialog_id, const string &message_id, Promise<Unit> &&promise) {
if (!td->messages_manager_->have_dialog_force(dialog_id, "view_sponsored_message")) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (dialog_id.get_type() != DialogType::Channel ||
td->contacts_manager_->get_channel_type(dialog_id.get_channel_id()) != ContactsManager::ChannelType::Broadcast ||
message_id.empty()) {
return promise.set_error(Status::Error(400, "Message not found"));
}
td->create_handler<ViewSponsoredMessageQuery>(std::move(promise))->send(dialog_id.get_channel_id(), message_id);
}
} // namespace td

View File

@ -0,0 +1,25 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/telegram/DialogId.h"
#include "td/telegram/td_api.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/common.h"
namespace td {
class Td;
void get_dialog_sponsored_messages(Td *td, DialogId dialog_id,
Promise<td_api::object_ptr<td_api::sponsoredMessages>> &&promise);
void view_sponsored_message(Td *td, DialogId dialog_id, const string &message_id, Promise<Unit> &&promise);
} // namespace td

View File

@ -1651,8 +1651,6 @@ tl_object_ptr<td_api::sticker> StickersManager::get_sticker_object(FileId file_i
return nullptr;
}
sticker->is_changed = false;
auto mask_position = sticker->point >= 0
? make_tl_object<td_api::maskPosition>(get_mask_point_object(sticker->point),
sticker->x_shift, sticker->y_shift, sticker->scale)
@ -1864,49 +1862,40 @@ FileId StickersManager::on_get_sticker(unique_ptr<Sticker> new_sticker, bool rep
if (s->dimensions != new_sticker->dimensions && new_sticker->dimensions.width != 0) {
LOG(DEBUG) << "Sticker " << file_id << " dimensions has changed";
s->dimensions = new_sticker->dimensions;
s->is_changed = true;
}
if (s->set_id != new_sticker->set_id && new_sticker->set_id.is_valid()) {
LOG_IF(ERROR, s->set_id.is_valid()) << "Sticker " << file_id << " set_id has changed";
s->set_id = new_sticker->set_id;
s->is_changed = true;
}
if (s->alt != new_sticker->alt && !new_sticker->alt.empty()) {
LOG(DEBUG) << "Sticker " << file_id << " emoji has changed";
s->alt = std::move(new_sticker->alt);
s->is_changed = true;
}
if (s->minithumbnail != new_sticker->minithumbnail) {
LOG(DEBUG) << "Sticker " << file_id << " minithumbnail has changed";
s->minithumbnail = std::move(new_sticker->minithumbnail);
s->is_changed = true;
}
if (s->s_thumbnail != new_sticker->s_thumbnail && new_sticker->s_thumbnail.file_id.is_valid()) {
LOG_IF(INFO, s->s_thumbnail.file_id.is_valid()) << "Sticker " << file_id << " s thumbnail has changed from "
<< s->s_thumbnail << " to " << new_sticker->s_thumbnail;
s->s_thumbnail = std::move(new_sticker->s_thumbnail);
s->is_changed = true;
}
if (s->m_thumbnail != new_sticker->m_thumbnail && new_sticker->m_thumbnail.file_id.is_valid()) {
LOG_IF(INFO, s->m_thumbnail.file_id.is_valid()) << "Sticker " << file_id << " m thumbnail has changed from "
<< s->m_thumbnail << " to " << new_sticker->m_thumbnail;
s->m_thumbnail = std::move(new_sticker->m_thumbnail);
s->is_changed = true;
}
if (s->is_animated != new_sticker->is_animated && new_sticker->is_animated) {
s->is_animated = new_sticker->is_animated;
s->is_changed = true;
}
if (s->is_mask != new_sticker->is_mask && new_sticker->is_mask) {
s->is_mask = new_sticker->is_mask;
s->is_changed = true;
}
if (s->point != new_sticker->point && new_sticker->point != -1) {
s->point = new_sticker->point;
s->x_shift = new_sticker->x_shift;
s->y_shift = new_sticker->y_shift;
s->scale = new_sticker->scale;
s->is_changed = true;
}
}
@ -2155,23 +2144,17 @@ FileId StickersManager::dup_sticker(FileId new_id, FileId old_id) {
return new_id;
}
bool StickersManager::merge_stickers(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 StickersManager::merge_stickers(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 stickers " << new_id << " and " << old_id;
const Sticker *old_ = get_sticker(old_id);
CHECK(old_ != nullptr);
if (old_id == new_id) {
return old_->is_changed;
}
auto new_it = stickers_.find(new_id);
if (new_it == stickers_.end() || new_it->second == nullptr) {
auto &old = stickers_[old_id];
old->is_changed = true;
if (!can_delete_old) {
dup_sticker(new_id, old_id);
} else {
@ -2189,8 +2172,6 @@ bool StickersManager::merge_stickers(FileId new_id, FileId old_id, bool can_dele
<< ", " << new_->set_id << "), dimensions = (" << old_->dimensions << ", " << new_->dimensions << ")";
}
new_->is_changed = true;
if (old_->s_thumbnail != new_->s_thumbnail) {
// LOG_STATUS(td_->file_manager_->merge(new_->s_thumbnail.file_id, old_->s_thumbnail.file_id));
}
@ -2202,7 +2183,6 @@ bool StickersManager::merge_stickers(FileId new_id, FileId old_id, bool can_dele
if (can_delete_old) {
stickers_.erase(old_id);
}
return true;
}
tl_object_ptr<telegram_api::InputStickerSet> StickersManager::get_input_sticker_set(const StickerSet *set) {
@ -2299,7 +2279,6 @@ void StickersManager::on_resolve_sticker_set_short_name(FileId sticker_file_id,
CHECK(s->file_id == sticker_file_id);
if (s->set_id != set_id) {
s->set_id = set_id;
s->is_changed = true;
}
}
}
@ -5063,11 +5042,13 @@ void StickersManager::on_uploaded_sticker_file(FileId file_id, tl_object_ptr<tel
return promise.set_error(Status::Error(400, "Wrong file type"));
}
if (is_animated) {
merge_stickers(parsed_document.file_id, file_id, false);
} else {
// must not delete the old document, because the file_id could be used for simultaneous URL uploads
td_->documents_manager_->merge_documents(parsed_document.file_id, file_id, false);
if (parsed_document.file_id != file_id) {
if (is_animated) {
merge_stickers(parsed_document.file_id, file_id, false);
} else {
// must not delete the old document, because the file_id could be used for simultaneous URL uploads
td_->documents_manager_->merge_documents(parsed_document.file_id, file_id, false);
}
}
promise.set_value(Unit());
}

View File

@ -267,7 +267,7 @@ class StickersManager final : public Actor {
FileId dup_sticker(FileId new_id, FileId old_id);
bool merge_stickers(FileId new_id, FileId old_id, bool can_delete_old);
void merge_stickers(FileId new_id, FileId old_id, bool can_delete_old);
template <class StorerT>
void store_sticker(FileId file_id, bool in_sticker_set, StorerT &storer) const;
@ -328,8 +328,6 @@ class StickersManager final : public Actor {
double x_shift = 0;
double y_shift = 0;
double scale = 0;
mutable bool is_changed = true;
};
class StickerSet {

View File

@ -307,7 +307,6 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser
if (sticker->set_id != sticker_set->id) {
LOG_IF(ERROR, sticker->set_id.is_valid()) << "Sticker " << sticker_id << " set_id has changed";
sticker->set_id = sticker_set->id;
sticker->is_changed = true;
}
if (sticker_set->was_loaded) {

View File

@ -90,6 +90,7 @@
#include "td/telegram/SecretChatsManager.h"
#include "td/telegram/SecureManager.h"
#include "td/telegram/SecureValue.h"
#include "td/telegram/SponsoredMessages.h"
#include "td/telegram/StateManager.h"
#include "td/telegram/StickerSetId.h"
#include "td/telegram/StickersManager.h"
@ -97,6 +98,7 @@
#include "td/telegram/MemoryManager.h"
#include "td/telegram/SuggestedAction.h"
#include "td/telegram/TdDb.h"
#include "td/telegram/ThemeManager.h"
#include "td/telegram/TopDialogCategory.h"
#include "td/telegram/TopDialogManager.h"
#include "td/telegram/UpdatesManager.h"
@ -789,31 +791,24 @@ class GetChatFilterRequest final : public RequestActor<> {
}
};
class GetChatsRequest final : public RequestActor<> {
class LoadChatsRequest final : public RequestActor<> {
DialogListId dialog_list_id_;
DialogDate offset_;
int32 limit_;
std::pair<int32, vector<DialogId>> dialog_ids_;
void do_run(Promise<Unit> &&promise) final {
dialog_ids_ =
td->messages_manager_->get_dialogs(dialog_list_id_, offset_, limit_, get_tries() < 2, std::move(promise));
}
void do_send_result() final {
send_result(MessagesManager::get_chats_object(dialog_ids_));
td->messages_manager_->get_dialogs(dialog_list_id_, offset_, limit_, false, get_tries() < 2, std::move(promise));
}
public:
GetChatsRequest(ActorShared<Td> td, uint64 request_id, DialogListId dialog_list_id, int64 offset_order,
int64 offset_dialog_id, int32 limit)
: RequestActor(std::move(td), request_id)
, dialog_list_id_(dialog_list_id)
, offset_(offset_order, DialogId(offset_dialog_id))
, limit_(limit) {
LoadChatsRequest(ActorShared<Td> td, uint64 request_id, DialogListId dialog_list_id, DialogDate offset, int32 limit)
: RequestActor(std::move(td), request_id), dialog_list_id_(dialog_list_id), offset_(offset), limit_(limit) {
// 1 for database + 1 for server request + 1 for server request at the end + 1 for return + 1 just in case
set_tries(5);
if (limit > 100) {
limit = 100;
}
}
};
@ -2739,7 +2734,7 @@ class GetSavedAnimationsRequest final : public RequestActor<> {
void do_send_result() final {
send_result(make_tl_object<td_api::animations>(transform(std::move(animation_ids_), [td = td](FileId animation_id) {
return td->animations_manager_->get_animation_object(animation_id, "GetSavedAnimationsRequest");
return td->animations_manager_->get_animation_object(animation_id);
})));
}
@ -2855,23 +2850,6 @@ class GetSupportUserRequest final : public RequestActor<> {
}
};
class GetBackgroundsRequest final : public RequestOnceActor {
bool for_dark_theme_;
void do_run(Promise<Unit> &&promise) final {
td->background_manager_->get_backgrounds(std::move(promise));
}
void do_send_result() final {
send_result(td->background_manager_->get_backgrounds_object(for_dark_theme_));
}
public:
GetBackgroundsRequest(ActorShared<Td> td, uint64 request_id, bool for_dark_theme)
: RequestOnceActor(std::move(td), request_id), for_dark_theme_(for_dark_theme) {
}
};
class SearchBackgroundRequest final : public RequestActor<> {
string name_;
@ -2905,7 +2883,7 @@ class SetBackgroundRequest final : public RequestActor<> {
}
void do_send_result() final {
send_result(td->background_manager_->get_background_object(background_id_, for_dark_theme_));
send_result(td->background_manager_->get_background_object(background_id_, for_dark_theme_, nullptr));
}
public:
@ -3156,6 +3134,7 @@ bool Td::is_synchronous_request(int32 id) {
case td_api::getFileExtension::ID:
case td_api::cleanFileName::ID:
case td_api::getLanguagePackString::ID:
case td_api::getPhoneNumberInfoSync::ID:
case td_api::getChatFilterDefaultIconName::ID:
case td_api::getJsonValue::ID:
case td_api::getJsonString::ID:
@ -3743,6 +3722,8 @@ void Td::dec_actor_refcnt() {
LOG(DEBUG) << "StickersManager was cleared" << timer;
memory_manager_.reset();
LOG(DEBUG) << "MemoryManager was cleared" << timer;
theme_manager_.reset();
LOG(DEBUG) << "ThemeManager was cleared" << timer;
updates_manager_.reset();
LOG(DEBUG) << "UpdatesManager was cleared" << timer;
video_notes_manager_.reset();
@ -3944,6 +3925,8 @@ void Td::clear() {
LOG(DEBUG) << "StickersManager actor was cleared" << timer;
memory_manager_actor_.reset();
LOG(DEBUG) << "MemoryManager actor was cleared" << timer;
theme_manager_actor_.reset();
LOG(DEBUG) << "ThemeManager actor was cleared" << timer;
updates_manager_actor_.reset();
LOG(DEBUG) << "UpdatesManager actor was cleared" << timer;
web_pages_manager_actor_.reset();
@ -4410,6 +4393,9 @@ void Td::init_managers() {
memory_manager_ = make_unique<MemoryManager>(this, create_reference());
memory_manager_actor_ = register_actor("MemoryManager", memory_manager_.get());
G()->set_memory_manager(memory_manager_actor_.get());
theme_manager_ = make_unique<ThemeManager>(this, create_reference());
theme_manager_actor_ = register_actor("ThemeManager", theme_manager_.get());
G()->set_theme_manager(theme_manager_actor_.get());
updates_manager_ = make_unique<UpdatesManager>(this, create_reference());
updates_manager_actor_ = register_actor("UpdatesManager", updates_manager_.get());
G()->set_updates_manager(updates_manager_actor_.get());
@ -5108,6 +5094,18 @@ void Td::on_request(uint64 id, const td_api::getMessages &request) {
CREATE_REQUEST(GetMessagesRequest, request.chat_id_, request.message_ids_);
}
void Td::on_request(uint64 id, const td_api::getChatSponsoredMessages &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
get_dialog_sponsored_messages(this, DialogId(request.chat_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::viewSponsoredMessage &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
view_sponsored_message(this, DialogId(request.chat_id_), request.message_id_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getMessageThread &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetMessageThreadRequest, request.chat_id_, request.message_id_);
@ -5393,10 +5391,26 @@ void Td::on_request(uint64 id, const td_api::removeTopChat &request) {
send_closure(actor_id(this), &Td::send_result, id, td_api::make_object<td_api::ok>());
}
void Td::on_request(uint64 id, const td_api::loadChats &request) {
CHECK_IS_USER();
DialogListId dialog_list_id(request.chat_list_);
auto r_offset = messages_manager_->get_dialog_list_last_date(dialog_list_id);
if (r_offset.is_error()) {
return send_error_raw(id, 400, r_offset.error().message());
}
auto offset = r_offset.move_as_ok();
if (offset == MAX_DIALOG_DATE) {
return send_closure(actor_id(this), &Td::send_result, id, nullptr);
}
CREATE_REQUEST(LoadChatsRequest, dialog_list_id, offset, request.limit_);
}
void Td::on_request(uint64 id, const td_api::getChats &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetChatsRequest, DialogListId(request.chat_list_), request.offset_order_, request.offset_chat_id_,
request.limit_);
CREATE_REQUEST_PROMISE();
messages_manager_->get_dialogs_from_list(DialogListId(request.chat_list_), request.limit_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::searchPublicChat &request) {
@ -5667,17 +5681,14 @@ void Td::on_request(uint64 id, const td_api::readAllChatMentions &request) {
}
void Td::on_request(uint64 id, td_api::sendMessage &request) {
DialogId dialog_id(request.chat_id_);
auto r_new_message_id = messages_manager_->send_message(
dialog_id, MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_),
auto r_sent_message = messages_manager_->send_message(
DialogId(request.chat_id_), MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_),
std::move(request.options_), std::move(request.reply_markup_), std::move(request.input_message_content_));
if (r_new_message_id.is_error()) {
return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error());
if (r_sent_message.is_error()) {
send_closure(actor_id(this), &Td::send_error, id, r_sent_message.move_as_error());
} else {
send_closure(actor_id(this), &Td::send_result, id, r_sent_message.move_as_ok());
}
CHECK(r_new_message_id.ok().is_valid() || r_new_message_id.ok().is_valid_scheduled());
send_closure(actor_id(this), &Td::send_result, id,
messages_manager_->get_message_object({dialog_id, r_new_message_id.ok()}));
}
void Td::on_request(uint64 id, td_api::sendMessageAlbum &request) {
@ -5862,20 +5873,18 @@ void Td::on_request(uint64 id, td_api::sendChatScreenshotTakenNotification &requ
}
void Td::on_request(uint64 id, td_api::forwardMessages &request) {
DialogId dialog_id(request.chat_id_);
auto input_message_ids = MessagesManager::get_message_ids(request.message_ids_);
auto message_copy_options =
transform(input_message_ids, [send_copy = request.send_copy_, remove_caption = request.remove_caption_](
MessageId) { return MessageCopyOptions(send_copy, remove_caption); });
auto r_message_ids =
messages_manager_->forward_messages(dialog_id, DialogId(request.from_chat_id_), std::move(input_message_ids),
std::move(request.options_), false, std::move(message_copy_options));
if (r_message_ids.is_error()) {
return send_closure(actor_id(this), &Td::send_error, id, r_message_ids.move_as_error());
auto r_messages = messages_manager_->forward_messages(DialogId(request.chat_id_), DialogId(request.from_chat_id_),
std::move(input_message_ids), std::move(request.options_),
false, std::move(message_copy_options), request.only_preview_);
if (r_messages.is_error()) {
send_closure(actor_id(this), &Td::send_error, id, r_messages.move_as_error());
} else {
send_closure(actor_id(this), &Td::send_result, id, r_messages.move_as_ok());
}
send_closure(actor_id(this), &Td::send_result, id,
messages_manager_->get_messages_object(-1, dialog_id, r_message_ids.ok(), false));
}
void Td::on_request(uint64 id, const td_api::resendMessages &request) {
@ -6144,13 +6153,14 @@ void Td::on_request(uint64 id, td_api::startGroupCallRecording &request) {
CLEAN_INPUT_STRING(request.title_);
CREATE_OK_REQUEST_PROMISE();
group_call_manager_->toggle_group_call_recording(GroupCallId(request.group_call_id_), true, std::move(request.title_),
request.record_video_, request.use_portrait_orientation_,
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::endGroupCallRecording &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
group_call_manager_->toggle_group_call_recording(GroupCallId(request.group_call_id_), false, string(),
group_call_manager_->toggle_group_call_recording(GroupCallId(request.group_call_id_), false, string(), false, false,
std::move(promise));
}
@ -6218,7 +6228,7 @@ void Td::on_request(uint64 id, const td_api::discardGroupCall &request) {
group_call_manager_->discard_group_call(GroupCallId(request.group_call_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getGroupCallStreamSegment &request) {
void Td::on_request(uint64 id, td_api::getGroupCallStreamSegment &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<string> result) mutable {
@ -6231,7 +6241,8 @@ void Td::on_request(uint64 id, const td_api::getGroupCallStreamSegment &request)
}
});
group_call_manager_->get_group_call_stream_segment(GroupCallId(request.group_call_id_), request.time_offset_,
request.scale_, std::move(query_promise));
request.scale_, request.channel_id_,
std::move(request.video_quality_), std::move(query_promise));
}
void Td::on_request(uint64 id, const td_api::upgradeBasicGroupChatToSupergroupChat &request) {
@ -6322,6 +6333,13 @@ void Td::on_request(uint64 id, const td_api::setChatPermissions &request) {
messages_manager_->set_dialog_permissions(DialogId(request.chat_id_), request.permissions_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::setChatTheme &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.theme_name_);
CREATE_OK_REQUEST_PROMISE();
messages_manager_->set_dialog_theme(DialogId(request.chat_id_), request.theme_name_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::setChatDraftMessage &request) {
CHECK_IS_USER();
answer_ok_query(
@ -8139,7 +8157,8 @@ void Td::on_request(uint64 id, const td_api::getSupportUser &request) {
void Td::on_request(uint64 id, const td_api::getBackgrounds &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetBackgroundsRequest, request.for_dark_theme_);
CREATE_REQUEST_PROMISE();
background_manager_->get_backgrounds(request.for_dark_theme_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::getBackgroundUrl &request) {
@ -8177,6 +8196,12 @@ void Td::on_request(uint64 id, const td_api::resetBackgrounds &request) {
background_manager_->reset_backgrounds(std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getChatThemes &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
theme_manager_->get_chat_themes(std::move(promise));
}
void Td::on_request(uint64 id, td_api::getRecentlyVisitedTMeUrls &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.referrer_);
@ -8402,6 +8427,10 @@ void Td::on_request(uint64 id, const td_api::getLanguagePackString &request) {
UNREACHABLE();
}
void Td::on_request(uint64 id, const td_api::getPhoneNumberInfoSync &request) {
UNREACHABLE();
}
void Td::on_request(uint64 id, const td_api::getPushReceiverId &request) {
UNREACHABLE();
}
@ -8553,6 +8582,11 @@ td_api::object_ptr<td_api::Object> Td::do_static_request(const td_api::getLangua
request.language_pack_database_path_, request.localization_target_, request.language_pack_id_, request.key_);
}
td_api::object_ptr<td_api::Object> Td::do_static_request(const td_api::getPhoneNumberInfoSync &request) {
// don't check language_code/phone number UTF-8 correctness
return CountryInfoManager::get_phone_number_info_sync(request.language_code_, request.phone_number_prefix_);
}
td_api::object_ptr<td_api::Object> Td::do_static_request(const td_api::getPushReceiverId &request) {
// don't check push payload UTF-8 correctness
auto r_push_receiver_id = NotificationManager::get_push_receiver_id(request.payload_);

View File

@ -74,6 +74,7 @@ class SecretChatsManager;
class StickersManager;
class StorageManager;
class MemoryManager;
class ThemeManager;
class TopDialogManager;
class UpdatesManager;
class VideoNotesManager;
@ -181,6 +182,8 @@ class Td final : public NetQueryCallback {
ActorOwn<PollManager> poll_manager_actor_;
unique_ptr<StickersManager> stickers_manager_;
ActorOwn<StickersManager> stickers_manager_actor_;
unique_ptr<ThemeManager> theme_manager_;
ActorOwn<ThemeManager> theme_manager_actor_;
unique_ptr<UpdatesManager> updates_manager_;
ActorOwn<UpdatesManager> updates_manager_actor_;
unique_ptr<MemoryManager> memory_manager_;
@ -248,7 +251,7 @@ class Td final : public NetQueryCallback {
static td_api::object_ptr<td_api::Object> static_request(td_api::object_ptr<td_api::Function> function);
private:
static constexpr const char *TDLIB_VERSION = "1.7.6";
static constexpr const char *TDLIB_VERSION = "1.7.7";
static constexpr int64 ONLINE_ALARM_ID = 0;
static constexpr int64 PING_SERVER_ALARM_ID = -1;
static constexpr int32 PING_SERVER_TIMEOUT = 300;
@ -524,6 +527,10 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::getMessages &request);
void on_request(uint64 id, const td_api::getChatSponsoredMessages &request);
void on_request(uint64 id, const td_api::viewSponsoredMessage &request);
void on_request(uint64 id, const td_api::getMessageLink &request);
void on_request(uint64 id, const td_api::getMessageEmbeddingCode &request);
@ -564,6 +571,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::removeTopChat &request);
void on_request(uint64 id, const td_api::loadChats &request);
void on_request(uint64 id, const td_api::getChats &request);
void on_request(uint64 id, td_api::searchPublicChat &request);
@ -780,7 +789,7 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::discardGroupCall &request);
void on_request(uint64 id, const td_api::getGroupCallStreamSegment &request);
void on_request(uint64 id, td_api::getGroupCallStreamSegment &request);
void on_request(uint64 id, const td_api::upgradeBasicGroupChatToSupergroupChat &request);
@ -808,6 +817,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::setChatPermissions &request);
void on_request(uint64 id, td_api::setChatTheme &request);
void on_request(uint64 id, td_api::setChatDraftMessage &request);
void on_request(uint64 id, const td_api::toggleChatIsPinned &request);
@ -1180,6 +1191,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::resetBackgrounds &request);
void on_request(uint64 id, const td_api::getChatThemes &request);
void on_request(uint64 id, td_api::getRecentlyVisitedTMeUrls &request);
void on_request(uint64 id, td_api::setBotUpdatesStatus &request);
@ -1242,6 +1255,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::getLanguagePackString &request);
void on_request(uint64 id, const td_api::getPhoneNumberInfoSync &request);
void on_request(uint64 id, const td_api::getPushReceiverId &request);
void on_request(uint64 id, const td_api::getChatFilterDefaultIconName &request);
@ -1293,6 +1308,7 @@ class Td final : public NetQueryCallback {
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getFileExtension &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::cleanFileName &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getLanguagePackString &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getPhoneNumberInfoSync &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getPushReceiverId &request);
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getChatFilterDefaultIconName &request);
static td_api::object_ptr<td_api::Object> do_static_request(td_api::getJsonValue &request);

View File

@ -0,0 +1,177 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/telegram/ThemeManager.h"
#include "td/telegram/BackgroundManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/net/NetQueryCreator.h"
#include "td/telegram/Td.h"
#include "td/utils/algorithm.h"
#include "td/utils/buffer.h"
#include "td/utils/logging.h"
namespace td {
class GetChatThemesQuery final : public Td::ResultHandler {
Promise<telegram_api::object_ptr<telegram_api::account_ChatThemes>> promise_;
public:
explicit GetChatThemesQuery(Promise<telegram_api::object_ptr<telegram_api::account_ChatThemes>> &&promise)
: promise_(std::move(promise)) {
}
void send(int32 hash) {
send_query(G()->net_query_creator().create(telegram_api::account_getChatThemes(hash)));
}
void on_result(uint64 id, BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_getChatThemes>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
promise_.set_value(result_ptr.move_as_ok());
}
void on_error(uint64 id, Status status) final {
promise_.set_error(std::move(status));
}
};
ThemeManager::ThemeManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
}
void ThemeManager::tear_down() {
parent_.reset();
}
void ThemeManager::get_chat_themes(Promise<td_api::object_ptr<td_api::chatThemes>> &&promise) {
pending_get_chat_themes_queries_.push_back(std::move(promise));
if (pending_get_chat_themes_queries_.size() == 1) {
auto request_promise = PromiseCreator::lambda(
[actor_id = actor_id(this)](Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result) {
send_closure(actor_id, &ThemeManager::on_get_chat_themes, std::move(result));
});
td_->create_handler<GetChatThemesQuery>(std::move(request_promise))->send(chat_themes_.hash);
}
}
td_api::object_ptr<td_api::themeSettings> ThemeManager::get_theme_settings_object(const ThemeSettings &settings) const {
auto fill = [colors = settings.message_colors]() mutable -> td_api::object_ptr<td_api::BackgroundFill> {
if (colors.size() >= 3) {
return td_api::make_object<td_api::backgroundFillFreeformGradient>(std::move(colors));
}
CHECK(!colors.empty());
if (colors.size() == 1 || colors[0] == colors[1]) {
return td_api::make_object<td_api::backgroundFillSolid>(colors[0]);
}
return td_api::make_object<td_api::backgroundFillGradient>(colors[1], colors[0], 0);
}();
// ignore settings.base_theme for now
return td_api::make_object<td_api::themeSettings>(
settings.accent_color,
td_->background_manager_->get_background_object(settings.background_id, false, &settings.background_type),
std::move(fill), settings.animate_message_colors);
}
td_api::object_ptr<td_api::chatTheme> ThemeManager::get_chat_theme_object(const ChatTheme &theme) const {
return td_api::make_object<td_api::chatTheme>(theme.emoji, get_theme_settings_object(theme.light_theme),
get_theme_settings_object(theme.dark_theme));
}
td_api::object_ptr<td_api::chatThemes> ThemeManager::get_chat_themes_object() const {
return td_api::make_object<td_api::chatThemes>(
transform(chat_themes_.themes, [this](const ChatTheme &theme) { return get_chat_theme_object(theme); }));
}
void ThemeManager::on_get_chat_themes(Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result) {
auto promises = std::move(pending_get_chat_themes_queries_);
CHECK(!promises.empty());
reset_to_empty(pending_get_chat_themes_queries_);
if (result.is_error()) {
// do not clear chat_themes_
auto error = result.move_as_error();
for (auto &promise : promises) {
promise.set_error(error.clone());
}
return;
}
auto chat_themes_ptr = result.move_as_ok();
LOG(DEBUG) << "Receive " << to_string(chat_themes_ptr);
if (chat_themes_ptr->get_id() == telegram_api::account_chatThemesNotModified::ID) {
for (auto &promise : promises) {
promise.set_value(get_chat_themes_object());
}
return;
}
auto chat_themes = telegram_api::move_object_as<telegram_api::account_chatThemes>(chat_themes_ptr);
LOG(INFO) << "Receive " << to_string(chat_themes);
chat_themes_.hash = chat_themes->hash_;
chat_themes_.themes.clear();
for (auto &chat_theme : chat_themes->themes_) {
if (chat_theme->emoticon_.empty()) {
LOG(ERROR) << "Receive " << to_string(chat_theme);
continue;
}
ChatTheme theme;
theme.emoji = std::move(chat_theme->emoticon_);
theme.light_theme = get_chat_theme_settings(std::move(chat_theme->theme_->settings_));
theme.dark_theme = get_chat_theme_settings(std::move(chat_theme->dark_theme_->settings_));
chat_themes_.themes.push_back(std::move(theme));
}
for (auto &promise : promises) {
promise.set_value(get_chat_themes_object());
}
}
ThemeManager::BaseTheme ThemeManager::get_base_theme(
const telegram_api::object_ptr<telegram_api::BaseTheme> &base_theme) {
CHECK(base_theme != nullptr);
switch (base_theme->get_id()) {
case telegram_api::baseThemeClassic::ID:
return BaseTheme::Classic;
case telegram_api::baseThemeDay::ID:
return BaseTheme::Day;
case telegram_api::baseThemeNight::ID:
return BaseTheme::Night;
case telegram_api::baseThemeTinted::ID:
return BaseTheme::Tinted;
case telegram_api::baseThemeArctic::ID:
return BaseTheme::Arctic;
default:
UNREACHABLE();
return BaseTheme::Classic;
}
}
ThemeManager::ThemeSettings ThemeManager::get_chat_theme_settings(
telegram_api::object_ptr<telegram_api::themeSettings> settings) {
ThemeSettings result;
if (settings != nullptr && !settings->message_colors_.empty() && settings->message_colors_.size() <= 4) {
auto background =
td_->background_manager_->on_get_background(BackgroundId(), string(), std::move(settings->wallpaper_), false);
result.accent_color = settings->accent_color_;
result.background_id = background.first;
result.background_type = std::move(background.second);
result.base_theme = get_base_theme(settings->base_theme_);
result.message_colors = std::move(settings->message_colors_);
result.animate_message_colors = settings->message_colors_animated_;
}
return result;
}
} // namespace td

View File

@ -0,0 +1,75 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/telegram/BackgroundId.h"
#include "td/telegram/BackgroundType.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/common.h"
#include "td/utils/Status.h"
namespace td {
class Td;
class ThemeManager final : public Actor {
public:
ThemeManager(Td *td, ActorShared<> parent);
void get_chat_themes(Promise<td_api::object_ptr<td_api::chatThemes>> &&promise);
private:
enum class BaseTheme : int32 { Classic, Day, Night, Tinted, Arctic };
struct ThemeSettings {
int32 accent_color = 0;
BackgroundId background_id;
BackgroundType background_type;
BaseTheme base_theme;
vector<int32> message_colors;
bool animate_message_colors = false;
};
struct ChatTheme {
string emoji;
ThemeSettings light_theme;
ThemeSettings dark_theme;
};
struct ChatThemes {
int32 hash = 0;
vector<ChatTheme> themes;
};
void tear_down() final;
void on_get_chat_themes(Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result);
td_api::object_ptr<td_api::themeSettings> get_theme_settings_object(const ThemeSettings &settings) const;
td_api::object_ptr<td_api::chatTheme> get_chat_theme_object(const ChatTheme &theme) const;
td_api::object_ptr<td_api::chatThemes> get_chat_themes_object() const;
static BaseTheme get_base_theme(const telegram_api::object_ptr<telegram_api::BaseTheme> &base_theme);
ThemeSettings get_chat_theme_settings(telegram_api::object_ptr<telegram_api::themeSettings> settings);
vector<Promise<td_api::object_ptr<td_api::chatThemes>>> pending_get_chat_themes_queries_;
ChatThemes chat_themes_;
Td *td_;
ActorShared<> parent_;
};
} // namespace td

View File

@ -242,7 +242,7 @@ void UpdatesManager::fill_gap(void *td, const char *source) {
}
auto updates_manager = static_cast<Td *>(td)->updates_manager_.get();
if (source != nullptr) {
if (source != nullptr && !updates_manager->running_get_difference_) {
LOG(WARNING) << "Filling gap in " << source << " by running getDifference";
}
@ -674,6 +674,7 @@ bool UpdatesManager::is_acceptable_message(const telegram_api::Message *message_
case telegram_api::messageActionGroupCall::ID:
case telegram_api::messageActionGroupCallScheduled::ID:
case telegram_api::messageActionSetMessagesTTL::ID:
case telegram_api::messageActionSetChatTheme::ID:
break;
case telegram_api::messageActionChatCreate::ID: {
auto chat_create = static_cast<const telegram_api::messageActionChatCreate *>(action);
@ -1749,7 +1750,7 @@ void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Updat
}
if (seq_begin <= seq_) {
if (seq_ >= 1000000000 && seq_begin < seq_ - 1000000000) {
if (seq_ >= (1 << 30) && seq_begin < seq_ - (1 << 30)) {
set_seq_gap_timeout(0.001);
}
if (seq_end > seq_) {
@ -1975,7 +1976,7 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr<telegram_api::Update>
}
}
if (new_pts <= old_pts || (old_pts >= 1 && new_pts - 500000000 > old_pts)) {
if (new_pts <= old_pts || (old_pts >= 1 && new_pts - (1 << 30) > old_pts)) {
td_->messages_manager_->skip_old_pending_pts_update(std::move(update), new_pts, old_pts, pts_count, source);
return promise.set_value(Unit());
}
@ -2166,7 +2167,7 @@ void UpdatesManager::process_postponed_pts_updates() {
while (update_it != postponed_pts_updates_.end()) {
auto new_pts = update_it->second.pts;
auto pts_count = update_it->second.pts_count;
if (new_pts <= old_pts || (old_pts >= 1 && new_pts - 500000000 > old_pts)) {
if (new_pts <= old_pts || (old_pts >= 1 && new_pts - (1 << 30) > old_pts)) {
skipped_update_count++;
td_->messages_manager_->skip_old_pending_pts_update(std::move(update_it->second.update), new_pts, old_pts,
pts_count, "process_postponed_pts_updates");
@ -2281,7 +2282,7 @@ void UpdatesManager::process_pending_seq_updates() {
auto update_it = pending_seq_updates_.begin();
auto &update = update_it->second;
auto seq_begin = update.seq_begin;
if (seq_begin - 1 > seq_ && seq_begin - 500000000 <= seq_) {
if (seq_begin - 1 > seq_ && seq_begin - (1 << 30) <= seq_) {
// the updates will be applied later
break;
}
@ -2330,7 +2331,7 @@ void UpdatesManager::process_pending_qts_updates() {
auto update_it = pending_qts_updates_.begin();
auto qts = update_it->first;
auto old_qts = get_qts();
if (qts - 1 > old_qts && qts - 500000000 <= old_qts) {
if (qts - 1 > old_qts && qts - (1 << 30) <= old_qts) {
// the update will be applied later
break;
}

View File

@ -8,7 +8,7 @@
namespace td {
constexpr int32 MTPROTO_LAYER = 131;
constexpr int32 MTPROTO_LAYER = 132;
enum class Version : int32 {
Initial, // 0

View File

@ -32,17 +32,19 @@ int32 VideoNotesManager::get_video_note_duration(FileId file_id) const {
return it->second->duration;
}
tl_object_ptr<td_api::videoNote> VideoNotesManager::get_video_note_object(FileId file_id) {
tl_object_ptr<td_api::videoNote> VideoNotesManager::get_video_note_object(FileId file_id) const {
if (!file_id.is_valid()) {
return nullptr;
}
auto &video_note = video_notes_[file_id];
auto it = video_notes_.find(file_id);
if (it == video_notes_.end()) {
return nullptr;
}
auto video_note = it->second.get();
if (video_note == nullptr) {
return nullptr;
}
video_note->is_changed = false;
return make_tl_object<td_api::videoNote>(
video_note->duration, video_note->dimensions.width, get_minithumbnail_object(video_note->minithumbnail),
get_thumbnail_object(td_->file_manager_.get(), video_note->thumbnail, PhotoFormat::Jpeg),
@ -62,12 +64,10 @@ FileId VideoNotesManager::on_get_video_note(unique_ptr<VideoNote> new_video_note
LOG(DEBUG) << "Video note " << file_id << " info has changed";
v->duration = new_video_note->duration;
v->dimensions = new_video_note->dimensions;
v->is_changed = true;
}
if (!G()->shared_config().get_option_boolean("disable_minithumbnails")) {
if (v->minithumbnail != new_video_note->minithumbnail) {
v->minithumbnail = std::move(new_video_note->minithumbnail);
v->is_changed = true;
}
}
if (v->thumbnail != new_video_note->thumbnail) {
@ -78,7 +78,6 @@ FileId VideoNotesManager::on_get_video_note(unique_ptr<VideoNote> new_video_note
<< new_video_note->thumbnail;
}
v->thumbnail = new_video_note->thumbnail;
v->is_changed = true;
}
}
return file_id;
@ -125,23 +124,17 @@ FileId VideoNotesManager::dup_video_note(FileId new_id, FileId old_id) {
return new_id;
}
bool VideoNotesManager::merge_video_notes(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 VideoNotesManager::merge_video_notes(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 video notes " << new_id << " and " << old_id;
const VideoNote *old_ = get_video_note(old_id);
CHECK(old_ != nullptr);
if (old_id == new_id) {
return old_->is_changed;
}
auto new_it = video_notes_.find(new_id);
if (new_it == video_notes_.end() || new_it->second == nullptr) {
auto &old = video_notes_[old_id];
old->is_changed = true;
if (!can_delete_old) {
dup_video_note(new_id, old_id);
} else {
@ -151,7 +144,6 @@ bool VideoNotesManager::merge_video_notes(FileId new_id, FileId old_id, bool can
} else {
VideoNote *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));
}
@ -160,7 +152,6 @@ bool VideoNotesManager::merge_video_notes(FileId new_id, FileId old_id, bool can
if (can_delete_old) {
video_notes_.erase(old_id);
}
return true;
}
void VideoNotesManager::create_video_note(FileId file_id, string minithumbnail, PhotoSize thumbnail, int32 duration,

View File

@ -32,7 +32,7 @@ class VideoNotesManager {
int32 get_video_note_duration(FileId file_id) const;
tl_object_ptr<td_api::videoNote> get_video_note_object(FileId file_id);
tl_object_ptr<td_api::videoNote> get_video_note_object(FileId file_id) const;
void create_video_note(FileId file_id, string minithumbnail, PhotoSize thumbnail, int32 duration,
Dimensions dimensions, bool replace);
@ -51,7 +51,7 @@ class VideoNotesManager {
FileId dup_video_note(FileId new_id, FileId old_id);
bool merge_video_notes(FileId new_id, FileId old_id, bool can_delete_old);
void merge_video_notes(FileId new_id, FileId old_id, bool can_delete_old);
template <class StorerT>
void store_video_note(FileId file_id, StorerT &storer) const;
@ -68,8 +68,6 @@ class VideoNotesManager {
PhotoSize thumbnail;
FileId file_id;
bool is_changed = true;
};
const VideoNote *get_video_note(FileId file_id) const;

View File

@ -31,17 +31,19 @@ int32 VideosManager::get_video_duration(FileId file_id) const {
return it->second->duration;
}
tl_object_ptr<td_api::video> VideosManager::get_video_object(FileId file_id) {
tl_object_ptr<td_api::video> VideosManager::get_video_object(FileId file_id) const {
if (!file_id.is_valid()) {
return nullptr;
}
auto &video = videos_[file_id];
auto it = videos_.find(file_id);
if (it == videos_.end()) {
return nullptr;
}
auto video = it->second.get();
if (video == nullptr) {
return nullptr;
}
video->is_changed = false;
auto thumbnail = video->animated_thumbnail.file_id.is_valid()
? get_thumbnail_object(td_->file_manager_.get(), video->animated_thumbnail, PhotoFormat::Mpeg4)
: get_thumbnail_object(td_->file_manager_.get(), video->thumbnail, PhotoFormat::Jpeg);
@ -63,7 +65,6 @@ FileId VideosManager::on_get_video(unique_ptr<Video> new_video, bool replace) {
if (v->mime_type != new_video->mime_type) {
LOG(DEBUG) << "Video " << file_id << " MIME type has changed";
v->mime_type = new_video->mime_type;
v->is_changed = true;
}
if (v->duration != new_video->duration || v->dimensions != new_video->dimensions ||
v->supports_streaming != new_video->supports_streaming) {
@ -71,17 +72,14 @@ FileId VideosManager::on_get_video(unique_ptr<Video> new_video, bool replace) {
v->duration = new_video->duration;
v->dimensions = new_video->dimensions;
v->supports_streaming = new_video->supports_streaming;
v->is_changed = true;
}
if (v->file_name != new_video->file_name) {
LOG(DEBUG) << "Video " << file_id << " file name has changed";
v->file_name = std::move(new_video->file_name);
v->is_changed = true;
}
if (!G()->shared_config().get_option_boolean("disable_minithumbnails")) {
if (v->minithumbnail != new_video->minithumbnail) {
v->minithumbnail = std::move(new_video->minithumbnail);
v->is_changed = true;
}
}
if (v->thumbnail != new_video->thumbnail) {
@ -92,7 +90,6 @@ FileId VideosManager::on_get_video(unique_ptr<Video> new_video, bool replace) {
<< new_video->thumbnail;
}
v->thumbnail = new_video->thumbnail;
v->is_changed = true;
}
if (v->animated_thumbnail != new_video->animated_thumbnail) {
if (!v->animated_thumbnail.file_id.is_valid()) {
@ -102,15 +99,12 @@ FileId VideosManager::on_get_video(unique_ptr<Video> new_video, bool replace) {
<< new_video->animated_thumbnail;
}
v->animated_thumbnail = new_video->animated_thumbnail;
v->is_changed = true;
}
if (v->has_stickers != new_video->has_stickers && new_video->has_stickers) {
v->has_stickers = new_video->has_stickers;
v->is_changed = true;
}
if (v->sticker_file_ids != new_video->sticker_file_ids && !new_video->sticker_file_ids.empty()) {
v->sticker_file_ids = std::move(new_video->sticker_file_ids);
v->is_changed = true;
}
}
return file_id;
@ -165,23 +159,17 @@ FileId VideosManager::dup_video(FileId new_id, FileId old_id) {
return new_id;
}
bool VideosManager::merge_videos(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 VideosManager::merge_videos(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 videos " << new_id << " and " << old_id;
const Video *old_ = get_video(old_id);
CHECK(old_ != nullptr);
if (old_id == new_id) {
return old_->is_changed;
}
auto new_it = videos_.find(new_id);
if (new_it == videos_.end() || new_it->second == nullptr) {
auto &old = videos_[old_id];
old->is_changed = true;
if (!can_delete_old) {
dup_video(new_id, old_id);
} else {
@ -196,7 +184,6 @@ bool VideosManager::merge_videos(FileId new_id, FileId old_id, bool can_delete_o
LOG(INFO) << "Video has changed: mime_type = (" << old_->mime_type << ", " << new_->mime_type << ")";
}
new_->is_changed = true;
if (old_->thumbnail != new_->thumbnail) {
// LOG_STATUS(td_->file_manager_->merge(new_->thumbnail.file_id, old_->thumbnail.file_id));
}
@ -205,7 +192,6 @@ bool VideosManager::merge_videos(FileId new_id, FileId old_id, bool can_delete_o
if (can_delete_old) {
videos_.erase(old_id);
}
return true;
}
void VideosManager::create_video(FileId file_id, string minithumbnail, PhotoSize thumbnail,

View File

@ -32,7 +32,7 @@ class VideosManager {
int32 get_video_duration(FileId file_id) const;
tl_object_ptr<td_api::video> get_video_object(FileId file_id);
tl_object_ptr<td_api::video> get_video_object(FileId file_id) const;
void create_video(FileId file_id, string minithumbnail, PhotoSize thumbnail, AnimationSize animated_thumbnail,
bool has_stickers, vector<FileId> &&sticker_file_ids, string file_name, string mime_type,
@ -55,7 +55,7 @@ class VideosManager {
FileId dup_video(FileId new_id, FileId old_id);
bool merge_videos(FileId new_id, FileId old_id, bool can_delete_old);
void merge_videos(FileId new_id, FileId old_id, bool can_delete_old);
template <class StorerT>
void store_video(FileId file_id, StorerT &storer) const;
@ -82,8 +82,6 @@ class VideosManager {
vector<FileId> sticker_file_ids;
FileId file_id;
bool is_changed = true;
};
const Video *get_video(FileId file_id) const;

View File

@ -30,14 +30,15 @@ int32 VoiceNotesManager::get_voice_note_duration(FileId file_id) const {
return it->second->duration;
}
tl_object_ptr<td_api::voiceNote> VoiceNotesManager::get_voice_note_object(FileId file_id) {
tl_object_ptr<td_api::voiceNote> VoiceNotesManager::get_voice_note_object(FileId file_id) const {
if (!file_id.is_valid()) {
return nullptr;
}
auto &voice_note = voice_notes_[file_id];
auto it = voice_notes_.find(file_id);
CHECK(it != voice_notes_.end());
auto voice_note = it->second.get();
CHECK(voice_note != nullptr);
voice_note->is_changed = false;
return make_tl_object<td_api::voiceNote>(voice_note->duration, voice_note->waveform, voice_note->mime_type,
td_->file_manager_->get_file_object(file_id));
}
@ -54,13 +55,11 @@ FileId VoiceNotesManager::on_get_voice_note(unique_ptr<VoiceNote> new_voice_note
if (v->mime_type != new_voice_note->mime_type) {
LOG(DEBUG) << "Voice note " << file_id << " info has changed";
v->mime_type = new_voice_note->mime_type;
v->is_changed = true;
}
if (v->duration != new_voice_note->duration || v->waveform != new_voice_note->waveform) {
LOG(DEBUG) << "Voice note " << file_id << " info has changed";
v->duration = new_voice_note->duration;
v->waveform = new_voice_note->waveform;
v->is_changed = true;
}
}
@ -89,23 +88,17 @@ FileId VoiceNotesManager::dup_voice_note(FileId new_id, FileId old_id) {
return new_id;
}
bool VoiceNotesManager::merge_voice_notes(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 VoiceNotesManager::merge_voice_notes(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 voice notes " << new_id << " and " << old_id;
const VoiceNote *old_ = get_voice_note(old_id);
CHECK(old_ != nullptr);
if (old_id == new_id) {
return old_->is_changed;
}
auto new_it = voice_notes_.find(new_id);
if (new_it == voice_notes_.end() || new_it->second == nullptr) {
auto &old = voice_notes_[old_id];
old->is_changed = true;
if (!can_delete_old) {
dup_voice_note(new_id, old_id);
} else {
@ -119,14 +112,11 @@ bool VoiceNotesManager::merge_voice_notes(FileId new_id, FileId old_id, bool can
if (!old_->mime_type.empty() && old_->mime_type != new_->mime_type) {
LOG(INFO) << "Voice note has changed: mime_type = (" << old_->mime_type << ", " << new_->mime_type << ")";
}
new_->is_changed = true;
}
LOG_STATUS(td_->file_manager_->merge(new_id, old_id));
if (can_delete_old) {
voice_notes_.erase(old_id);
}
return true;
}
void VoiceNotesManager::create_voice_note(FileId file_id, string mime_type, int32 duration, string waveform,

View File

@ -26,7 +26,7 @@ class VoiceNotesManager {
int32 get_voice_note_duration(FileId file_id) const;
tl_object_ptr<td_api::voiceNote> get_voice_note_object(FileId file_id);
tl_object_ptr<td_api::voiceNote> get_voice_note_object(FileId file_id) const;
void create_voice_note(FileId file_id, string mime_type, int32 duration, string waveform, bool replace);
@ -39,7 +39,7 @@ class VoiceNotesManager {
FileId dup_voice_note(FileId new_id, FileId old_id);
bool merge_voice_notes(FileId new_id, FileId old_id, bool can_delete_old);
void merge_voice_notes(FileId new_id, FileId old_id, bool can_delete_old);
template <class StorerT>
void store_voice_note(FileId file_id, StorerT &storer) const;
@ -55,8 +55,6 @@ class VoiceNotesManager {
string waveform;
FileId file_id;
bool is_changed = true;
};
const VoiceNote *get_voice_note(FileId file_id) const;

View File

@ -981,7 +981,7 @@ class WebPageBlockAnimation final : public WebPageBlock {
td_api::object_ptr<td_api::PageBlock> get_page_block_object(Context *context) const final {
return make_tl_object<td_api::pageBlockAnimation>(
context->td_->animations_manager_->get_animation_object(animation_file_id, "get_page_block_object"),
context->td_->animations_manager_->get_animation_object(animation_file_id),
caption.get_page_block_caption_object(context), need_autoplay);
}

View File

@ -51,6 +51,8 @@
#include "td/utils/tl_helpers.h"
#include "td/utils/utf8.h"
#include <limits>
namespace td {
class GetWebPagePreviewQuery final : public Td::ResultHandler {
@ -1301,7 +1303,7 @@ tl_object_ptr<td_api::webPage> WebPagesManager::get_web_page_object(WebPageId we
get_photo_object(td_->file_manager_.get(), web_page->photo), web_page->embed_url, web_page->embed_type,
web_page->embed_dimensions.width, web_page->embed_dimensions.height, web_page->duration, web_page->author,
web_page->document.type == Document::Type::Animation
? td_->animations_manager_->get_animation_object(web_page->document.file_id, "get_web_page_object")
? td_->animations_manager_->get_animation_object(web_page->document.file_id)
: nullptr,
web_page->document.type == Document::Type::Audio
? td_->audios_manager_->get_audio_object(web_page->document.file_id)

View File

@ -14,7 +14,6 @@
#include "td/telegram/Client.h"
#include "td/telegram/ClientActor.h"
#include "td/telegram/Td.h" // for VERBOSITY_NAME(td_requests)
#include "td/telegram/td_api_json.h"
#include "td/utils/algorithm.h"
@ -131,22 +130,11 @@ static void reactivate_readline() {
}
static char *command_generator(const char *text, int state) {
static const vector<CSlice> commands{"GetChats",
"GetHistory",
"SetVerbosity",
"SendVideo",
"SearchDocument",
"GetChatMember",
"GetSupergroupAdministrators",
"GetSupergroupBanned",
"GetSupergroupMembers",
"GetFile",
"DownloadFile",
"CancelDownloadFile",
"ImportContacts",
"RemoveContacts",
"CreateSecretChat",
"CreateNewSecretChat"};
static const vector<CSlice> commands{"GetHistory", "SetVerbosity", "SendVideo",
"SearchDocument", "GetChatMember", "GetSupergroupAdministrators",
"GetSupergroupBanned", "GetSupergroupMembers", "GetFile",
"DownloadFile", "CancelDownloadFile", "ImportContacts",
"RemoveContacts", "CreateSecretChat", "CreateNewSecretChat"};
static size_t cmd_i;
if (state == 0) {
cmd_i = 0;
@ -734,7 +722,7 @@ class CliClient final : public Actor {
}
}
if (id > 0 && combined_log.get_first_verbosity_level() < VERBOSITY_NAME(td_requests)) {
if (id > 0 && combined_log.get_first_verbosity_level() < get_log_tag_verbosity_level("td_requests")) {
LOG(ERROR) << "Receive result [" << generation << "][id=" << id << "] " << result_str;
}
@ -853,7 +841,7 @@ class CliClient final : public Actor {
}
void on_error(uint64 generation, uint64 id, td_api::object_ptr<td_api::error> error) {
if (id > 0 && combined_log.get_first_verbosity_level() < VERBOSITY_NAME(td_requests)) {
if (id > 0 && combined_log.get_first_verbosity_level() < get_log_tag_verbosity_level("td_requests")) {
LOG(ERROR) << "Receive error [" << generation << "][id=" << id << "] " << to_string(error);
}
}
@ -945,7 +933,7 @@ class CliClient final : public Actor {
td_client_ = create_actor<ClientActor>(name, make_unique<TdCallbackImpl>(this, ++generation_), std::move(options));
if (get_chat_list_) {
send_request(td_api::make_object<td_api::getChats>(nullptr, std::numeric_limits<int64>::max(), 0, 100));
send_request(td_api::make_object<td_api::getChats>(nullptr, 10000));
}
if (disable_network_) {
send_request(td_api::make_object<td_api::setNetworkType>(td_api::make_object<td_api::networkTypeNone>()));
@ -1331,6 +1319,9 @@ class CliClient final : public Actor {
if (action == "uvn" || action == "upload_video_note") {
return td_api::make_object<td_api::chatActionUploadingVideoNote>(50);
}
if (action == "cs" || action == "choose_sticker") {
return td_api::make_object<td_api::chatActionChoosingSticker>();
}
return td_api::make_object<td_api::chatActionTyping>();
}
@ -1573,11 +1564,11 @@ class CliClient final : public Actor {
}
static td_api::object_ptr<td_api::Object> execute(td_api::object_ptr<td_api::Function> f) {
if (combined_log.get_first_verbosity_level() < VERBOSITY_NAME(td_requests)) {
if (combined_log.get_first_verbosity_level() < get_log_tag_verbosity_level("td_requests")) {
LOG(ERROR) << "Execute request: " << to_string(f);
}
auto res = ClientActor::execute(std::move(f));
if (combined_log.get_first_verbosity_level() < VERBOSITY_NAME(td_requests)) {
if (combined_log.get_first_verbosity_level() < get_log_tag_verbosity_level("td_requests")) {
LOG(ERROR) << "Execute response: " << to_string(res);
}
return res;
@ -1595,6 +1586,15 @@ class CliClient final : public Actor {
}
}
static int32 get_log_tag_verbosity_level(string name) {
auto level = ClientActor::execute(td_api::make_object<td_api::getLogTagVerbosityLevel>(name));
if (level->get_id() == td_api::error::ID) {
return -1;
}
CHECK(level->get_id() == td_api::logVerbosityLevel::ID);
return static_cast<const td_api::logVerbosityLevel *>(level.get())->verbosity_level_;
}
void send_message(const string &chat_id, td_api::object_ptr<td_api::InputMessageContent> &&input_message_content,
bool disable_notification = false, bool from_background = false, int64 reply_to_message_id = 0) {
auto chat = as_chat_id(chat_id);
@ -1966,23 +1966,14 @@ class CliClient final : public Actor {
op_not_found_count++;
}
if (op == "gc" || op == "GetChats" || op == "gca" || begins_with(op, "gc-")) {
string limit;
string offset_order_string;
string offset_chat_id;
get_args(args, limit, offset_order_string, offset_chat_id);
int64 offset_order;
if (offset_order_string.empty()) {
offset_order = std::numeric_limits<int64>::max();
} else {
offset_order = to_integer<int64>(offset_order_string);
}
send_request(td_api::make_object<td_api::getChats>(as_chat_list(op), offset_order, as_chat_id(offset_chat_id),
as_limit(limit, 10000)));
if (op == "gc" || op == "gca" || begins_with(op, "gc-")) {
send_request(td_api::make_object<td_api::getChats>(as_chat_list(op), as_limit(args, 10000)));
} else if (op == "lc" || op == "lca" || begins_with(op, "lc-")) {
send_request(td_api::make_object<td_api::loadChats>(as_chat_list(op), as_limit(args, 10000)));
} else if (op == "gctest") {
send_request(td_api::make_object<td_api::getChats>(nullptr, std::numeric_limits<int64>::max(), 0, 1));
send_request(td_api::make_object<td_api::getChats>(nullptr, std::numeric_limits<int64>::max(), 0, 10));
send_request(td_api::make_object<td_api::getChats>(nullptr, std::numeric_limits<int64>::max(), 0, 5));
send_request(td_api::make_object<td_api::getChats>(nullptr, 1));
send_request(td_api::make_object<td_api::getChats>(nullptr, 10));
send_request(td_api::make_object<td_api::getChats>(nullptr, 5));
} else if (op == "gcc" || op == "GetCommonChats") {
string user_id;
string offset_chat_id;
@ -2305,12 +2296,16 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::removeBackground>(to_integer<int64>(args)));
} else if (op == "rbgs") {
send_request(td_api::make_object<td_api::resetBackgrounds>());
} else if (op == "gcts") {
send_request(td_api::make_object<td_api::getChatThemes>());
} else if (op == "gcos") {
send_request(td_api::make_object<td_api::getCountries>());
} else if (op == "gcoc") {
send_request(td_api::make_object<td_api::getCountryCode>());
} else if (op == "gpni") {
send_request(td_api::make_object<td_api::getPhoneNumberInfo>(args));
} else if (op == "gpnis") {
execute(td_api::make_object<td_api::getPhoneNumberInfoSync>(rand_bool() ? "en" : "", args));
} else if (op == "gadl") {
send_request(td_api::make_object<td_api::getApplicationDownloadLink>());
} else if (op == "atos") {
@ -2604,6 +2599,13 @@ class CliClient final : public Actor {
string message_ids;
get_args(args, chat_id, message_ids);
send_request(td_api::make_object<td_api::getMessages>(as_chat_id(chat_id), as_message_ids(message_ids)));
} else if (op == "gsm") {
send_request(td_api::make_object<td_api::getChatSponsoredMessages>(as_chat_id(args)));
} else if (op == "vsm") {
string chat_id;
string message_id;
get_args(args, chat_id, message_id);
send_request(td_api::make_object<td_api::viewSponsoredMessage>(as_chat_id(chat_id), message_id));
} else if (op == "gmlink") {
string chat_id;
string message_id;
@ -2707,15 +2709,15 @@ class CliClient final : public Actor {
get_args(args, chat_id, message_ids);
send_request(
td_api::make_object<td_api::deleteMessages>(as_chat_id(chat_id), as_message_ids(message_ids), op == "dmr"));
} else if (op == "fm" || op == "cm") {
} else if (op == "fm" || op == "cm" || op == "fmp" || op == "cmp") {
string chat_id;
string from_chat_id;
string message_ids;
get_args(args, chat_id, from_chat_id, message_ids);
auto chat = as_chat_id(chat_id);
send_request(
td_api::make_object<td_api::forwardMessages>(chat, as_chat_id(from_chat_id), as_message_ids(message_ids),
default_message_send_options(), op[0] == 'c', rand_bool()));
send_request(td_api::make_object<td_api::forwardMessages>(
chat, as_chat_id(from_chat_id), as_message_ids(message_ids), default_message_send_options(), op[0] == 'c',
rand_bool(), op.back() == 'p'));
} else if (op == "resend") {
string chat_id;
string message_ids;
@ -2778,8 +2780,11 @@ class CliClient final : public Actor {
} else if (op == "ggc") {
send_request(td_api::make_object<td_api::getGroupCall>(as_group_call_id(args)));
} else if (op == "ggcss") {
send_request(td_api::make_object<td_api::getGroupCallStreamSegment>(as_group_call_id(args),
(std::time(nullptr) - 5) * 1000, 0));
string group_call_id;
int32 channel_id;
get_args(args, group_call_id, channel_id);
send_request(td_api::make_object<td_api::getGroupCallStreamSegment>(
as_group_call_id(group_call_id), (std::time(nullptr) - 5) * 1000, 0, channel_id, nullptr));
} else if (op == "ssgc") {
send_request(td_api::make_object<td_api::startScheduledGroupCall>(as_group_call_id(args)));
} else if (op == "tgcesn" || op == "tgcesne") {
@ -2872,8 +2877,11 @@ class CliClient final : public Actor {
} else if (op == "sgcr") {
string chat_id;
string title;
get_args(args, chat_id, title);
send_request(td_api::make_object<td_api::startGroupCallRecording>(as_group_call_id(chat_id), title));
bool record_video;
bool use_portrait_orientation;
get_args(args, chat_id, title, record_video, use_portrait_orientation);
send_request(td_api::make_object<td_api::startGroupCallRecording>(as_group_call_id(chat_id), title, record_video,
use_portrait_orientation));
} else if (op == "egcr") {
string chat_id = args;
send_request(td_api::make_object<td_api::endGroupCallRecording>(as_group_call_id(chat_id)));
@ -3781,6 +3789,11 @@ class CliClient final : public Actor {
} else {
LOG(ERROR) << "Wrong permissions size, expected 8";
}
} else if (op == "sctn") {
string chat_id;
string theme_name;
get_args(args, chat_id, theme_name);
send_request(td_api::make_object<td_api::setChatTheme>(as_chat_id(chat_id), theme_name));
} else if (op == "sccd") {
string chat_id;
string client_data;

View File

@ -10,7 +10,7 @@
#include "td/telegram/files/FileData.hpp"
#include "td/telegram/files/FileLocation.h"
#include "td/telegram/files/FileLocation.hpp"
#include "td/telegram/logevent/LogEvent.h" // WithVersion
#include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/Version.h"
#include "td/actor/actor.h"

View File

@ -110,18 +110,21 @@ void FileLoader::start_up() {
bool is_upload = file_info.is_upload;
// Two cases when FILE_UPLOAD_RESTART will happen
// 1. File is ready, size is final. But there are more uploaded parts, than size of a file
//pm.init(1, 100000, true, 10, {0, 1, 2}, false, true).ensure_error();
// This error is definitely ok, because we are using actual size of file on disk (mtime is checked by somebody
// else). And actual size could change arbitrarily.
// 1. File is ready, size is final. But there are more uploaded parts than size of the file
// pm.init(1, 100000, true, 10, {0, 1, 2}, false, true).ensure_error();
// This error is definitely ok, because we are using actual size of the file on disk (mtime is checked by
// somebody else). And actual size could change arbitrarily.
//
// 2. size is unknown/zero, size is not final, some parts of file are already uploaded
// pm.init(0, 100000, false, 10, {0, 1, 2}, false, true).ensure_error();
// This case is more complicated
// It means that at some point we got inconsistent state. Like deleted local location, but left partial remote
// locaiton untouched. This is completely possible at this point, but probably should be fixed.
// location untouched. This is completely possible at this point, but probably should be fixed.
auto status =
parts_manager_.init(size, expected_size, is_size_final, part_size, ready_parts, use_part_count_limit, is_upload);
LOG(DEBUG) << "Start " << (is_upload ? "up" : "down") << "load of a file of size " << size << " with expected "
<< (is_size_final ? "exact" : "approximate") << " size " << expected_size << ", part size " << part_size
<< " and " << ready_parts.size() << " ready parts: " << status;
if (status.is_error()) {
on_error(std::move(status));
stop_flag_ = true;

View File

@ -666,6 +666,20 @@ inline bool operator!=(const RemoteFileLocation &lhs, const RemoteFileLocation &
return !(lhs == rhs);
}
inline StringBuilder &operator<<(StringBuilder &sb, const RemoteFileLocation &location) {
switch (location.type()) {
case RemoteFileLocation::Type::Empty:
return sb << "[empty remote location]";
case RemoteFileLocation::Type::Partial:
return sb << location.partial();
case RemoteFileLocation::Type::Full:
return sb << location.full();
default:
UNREACHABLE();
return sb;
}
}
struct EmptyLocalFileLocation {
template <class StorerT>
void store(StorerT &storer) const {

View File

@ -3482,7 +3482,8 @@ void FileManager::on_partial_upload(QueryId query_id, const PartialRemoteFileLoc
auto file_id = query->file_id_;
auto file_node = get_file_node(file_id);
LOG(DEBUG) << "Receive on_partial_upload for file " << file_id << " with " << partial_remote;
LOG(DEBUG) << "Receive on_partial_upload for file " << file_id << " with " << partial_remote << " and ready size "
<< ready_size;
if (!file_node) {
return;
}

View File

@ -40,7 +40,8 @@ FileUploader::FileUploader(const LocalFileLocation &local, const RemoteFileLocat
iv_ = encryption_key_.mutable_iv();
generate_iv_ = encryption_key_.iv_slice().str();
}
if (remote_.type() == RemoteFileLocation::Type::Partial && encryption_key_.is_secure()) {
if (remote_.type() == RemoteFileLocation::Type::Partial && encryption_key_.is_secure() &&
remote_.partial().part_count_ != remote_.partial().ready_part_count_) {
remote_ = RemoteFileLocation{};
}
}
@ -80,6 +81,7 @@ Result<FileLoader::FileInfo> FileUploader::init() {
parts.push_back(i);
}
}
LOG(DEBUG) << "Init file uploader for " << remote_ << " with offset = " << offset << " and part size = " << part_size;
if (!ok.empty() && !ok[0]) {
parts.clear();
}
@ -134,7 +136,7 @@ Result<FileLoader::PrefixInfo> FileUploader::on_update_local_location(const Loca
file_type_ = file_type;
bool is_temp = false;
if (encryption_key_.is_secure() && local_is_ready) {
if (encryption_key_.is_secure() && local_is_ready && remote_.type() == RemoteFileLocation::Type::Empty) {
TRY_RESULT(file_fd_path, open_temp_file(FileType::Temp));
file_fd_path.first.close();
auto new_path = std::move(file_fd_path.second);
@ -243,6 +245,7 @@ Status FileUploader::before_start_parts() {
}
return status;
}
void FileUploader::after_start_parts() {
try_release_fd();
}
@ -318,6 +321,7 @@ void FileUploader::on_progress(Progress progress) {
local_size_);
}
}
FileLoader::Callback *FileUploader::get_callback() {
return static_cast<FileLoader::Callback *>(callback_.get());
}

View File

@ -11,7 +11,7 @@
#include "td/utils/CancellationToken.h"
#include "td/utils/Closure.h"
#include "td/utils/common.h"
#include "td/utils/invoke.h" // for tuple_for_each
#include "td/utils/invoke.h"
#include "td/utils/MovableValue.h"
#include "td/utils/ScopeGuard.h"
#include "td/utils/Status.h"

View File

@ -26,9 +26,9 @@
#include "td/utils/type_traits.h"
#include <functional>
#include <map>
#include <memory>
#include <type_traits>
#include <unordered_map>
#include <utility>
namespace td {
@ -214,7 +214,7 @@ class Scheduler {
ListNode ready_actors_list_;
KHeap<double> timeout_queue_;
std::map<ActorInfo *, std::vector<Event>> pending_events_;
std::unordered_map<ActorInfo *, std::vector<Event>> pending_events_;
ServiceActor service_actor_;
Poll poll_;

View File

@ -24,9 +24,9 @@
#include <openssl/x509v3.h>
#include <cstring>
#include <map>
#include <memory>
#include <mutex>
#include <unordered_map>
#if TD_PORT_WINDOWS
#include <wincrypt.h>
@ -131,7 +131,7 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
static std::mutex warning_mutex;
{
std::lock_guard<std::mutex> lock(warning_mutex);
static std::map<std::string, double> next_warning_time;
static std::unordered_map<std::string, double> next_warning_time;
double &next = next_warning_time[warning];
if (next <= now) {
next = now + 300; // one warning per 5 minutes

View File

@ -860,7 +860,7 @@ static void pbkdf2_impl(Slice password, Slice salt, int iteration_count, Mutable
LOG(FATAL) << "Failed to HMAC";
}
for (int i = 0; i < hash_size; i++) {
dest[i] ^= buf[i];
dest[i] = static_cast<unsigned char>(dest[i] ^ buf[i]);
}
}
}

View File

@ -7,7 +7,7 @@
#pragma once
#include "td/utils/common.h"
#include "td/utils/invoke.h" // for tuple_for_each
#include "td/utils/invoke.h"
#include "td/utils/Slice.h"
#include "td/utils/StringBuilder.h"

View File

@ -47,7 +47,8 @@ using Platform::String;
using Platform::NullReferenceException;
template <class Key, class Value> class ConcurrentDictionary {
template <class Key, class Value>
class ConcurrentDictionary {
public:
bool TryGetValue(Key key, Value &value) {
std::lock_guard<std::mutex> guard(mutex_);

View File

@ -38,10 +38,8 @@ class MemoryMapping::Impl {
int64 offset_;
};
#if !TD_WINDOWS
static Result<int64> get_page_size() {
#if TD_WINDOWS
return Status::Error("Unimplemented");
#else
static Result<int64> page_size = []() -> Result<int64> {
auto page_size = sysconf(_SC_PAGESIZE);
if (page_size < 0) {
@ -50,8 +48,8 @@ static Result<int64> get_page_size() {
return page_size;
}();
return page_size.clone();
#endif
}
#endif
Result<MemoryMapping> MemoryMapping::create_anonymous(const MemoryMapping::Options &options) {
return Status::Error("Unsupported yet");

View File

@ -6,6 +6,8 @@
//
#include "td/utils/port/platform.h"
char disable_linker_warning_about_empty_file_platform_cpp TD_UNUSED;
#if !TD_MSVC
#if TD_DARWIN_UNKNOWN

View File

@ -230,7 +230,7 @@ Slice get_operating_system_version() {
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
auto handle = GetModuleHandle(L"ntdll.dll");
if (handle != nullptr) {
using RtlGetVersionPtr = LONG(WINAPI *)(PRTL_OSVERSIONINFOEXW);
using RtlGetVersionPtr = LONG(WINAPI *)(_Out_ PRTL_OSVERSIONINFOEXW);
RtlGetVersionPtr RtlGetVersion = reinterpret_cast<RtlGetVersionPtr>(GetProcAddress(handle, "RtlGetVersion"));
if (RtlGetVersion != nullptr) {
RTL_OSVERSIONINFOEXW os_version_info = {};
@ -240,7 +240,7 @@ Slice get_operating_system_version() {
auto minor = os_version_info.dwMinorVersion;
bool is_server = os_version_info.wProductType != VER_NT_WORKSTATION;
if (major == 10 && minor >= 0) {
if (major == 10) {
if (is_server) {
return os_version_info.dwBuildNumber >= 17623 ? "Windows Server 2019" : "Windows Server 2016";
}

View File

@ -6,7 +6,7 @@
//
#include "td/utils/utf8.h"
#include "td/utils/logging.h" // for UNREACHABLE
#include "td/utils/logging.h"
#include "td/utils/unicode.h"
namespace td {

View File

@ -33,7 +33,7 @@ TEST(Heap, sort_random_perm) {
ASSERT_EQ(i, kheap.top_key());
kheap.pop();
}
};
}
class CheckedHeap {
public:

View File

@ -92,7 +92,7 @@ static void bench_log(std::string name, F &&f) {
bench(LogBenchmark<typename decltype(f())::element_type>(name, threads_n, test_full_logging, f));
}
}
};
}
TEST(Log, Bench) {
bench_log("NullLog", [] { return td::make_unique<td::NullLog>(); });

Some files were not shown because too many files have changed in this diff Show More