Merge commit '3282a873cb24b0c975b6929aeb71a00fc6a18b7c'

Conflicts:
	sqlite/sqlite/sqlite3.c
	sqlite/sqlite/sqlite3.h
	sqlite/sqlite/sqlite3ext.h
	sqlite/sqlite/sqlite3session.h
	tddb/td/db/SqliteDb.cpp
This commit is contained in:
Andrea Cavalli 2020-08-18 13:55:47 +02:00
commit 1ccc7c6c65
90 changed files with 227854 additions and 476 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
project(TDLib VERSION 1.6.7 LANGUAGES CXX C)
project(TDLib VERSION 1.6.8 LANGUAGES CXX C)
if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR "lib")
@ -610,6 +610,7 @@ set(TDLIB_SOURCE
td/telegram/Logging.h
td/telegram/MessageContent.h
td/telegram/MessageContentType.h
td/telegram/MessageCopyOptions.h
td/telegram/MessageEntity.h
td/telegram/MessageId.h
td/telegram/MessagesDb.h

View File

@ -199,7 +199,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.6.7 REQUIRED)
find_package(Td 1.6.8 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

@ -274,6 +274,7 @@ function split_file($file, $chunks, $undo) {
'inline_queries_manager[_(-][^.]|InlineQueriesManager' => 'InlineQueriesManager',
'language_pack_manager[_(-][^.]|LanguagePackManager' => 'LanguagePackManager',
'get_erase_logevent_promise|parse_time|store_time' => 'logevent/LogEventHelper',
'MessageCopyOptions' => 'MessageCopyOptions',
'messages_manager[_(-][^.]|MessagesManager' => 'MessagesManager',
'notification_manager[_(-][^.]|NotificationManager|notifications[)]' => 'NotificationManager',
'PublicDialogType|get_public_dialog_type' => 'PublicDialogType',

View File

@ -10,6 +10,7 @@
#include "td/actor/PromiseFuture.h"
#include "td/utils/common.h"
#include "td/utils/crypto.h"
#include "td/utils/logging.h"
#if TD_MSVC
@ -266,6 +267,8 @@ class QueryBench : public td::Benchmark {
};
int main() {
td::init_openssl_threads();
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG));
bench(RingBench<4>(504, 0));
bench(RingBench<3>(504, 0));
@ -285,5 +288,4 @@ int main() {
bench(RingBench<0>(504, 2));
bench(RingBench<1>(504, 2));
bench(RingBench<2>(504, 2));
return 0;
}

View File

@ -366,5 +366,4 @@ int main() {
td::bench(SHA1Bench());
td::bench(Crc32Bench());
td::bench(Crc64Bench());
return 0;
}

View File

@ -238,5 +238,4 @@ int main() {
bench(TdKvBench<td::BinlogKeyValue<td::Binlog>>("BinlogKeyValue<Binlog>"));
bench(TdKvBench<td::BinlogKeyValue<td::ConcurrentBinlog>>("BinlogKeyValue<ConcurrentBinlog>"));
bench(SeqKvBench());
return 0;
}

View File

@ -74,5 +74,4 @@ class HandshakeBench : public Benchmark {
int main() {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG));
td::bench(td::HandshakeBench());
return 0;
}

View File

@ -160,5 +160,4 @@ int main() {
#endif
td::bench(IostreamWriteBench());
td::bench(FILEWriteBench());
return 0;
}

View File

@ -391,5 +391,4 @@ int main() {
#if TD_LINUX || TD_ANDROID || TD_TIZEN
td::bench(td::SemBench());
#endif
return 0;
}

View File

@ -974,6 +974,4 @@ int main() {
// BENCH_Q(BufferQueue, 100);
// BENCH_Q(BufferQueue, 10);
// BENCH_Q(BufferQueue, 1);
return 0;
}

View File

@ -112,5 +112,4 @@ class MessagesDbBench : public Benchmark {
int main() {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(WARNING));
bench(td::MessagesDbBench());
return 0;
}

View File

@ -26,5 +26,4 @@ int main(int argc, char *argv[]) {
//}
});
LOG(INFO) << status << ": " << cnt;
return 0;
}

View File

@ -40,5 +40,4 @@ int main(int argc, char *argv[]) {
// empty
}
scheduler->finish();
return 0;
}

View File

@ -561,6 +561,19 @@ function onOptionsChanged() {
install_dir = '../example/java/td';
}
function getClangVersionSuffix() {
switch (linux_distro) {
case 'Ubuntu 14':
return '-3.9';
case 'Ubuntu 18':
return '-6.0';
case 'Ubuntu 20':
return '-10';
default:
return ''; // use default version
}
}
var commands = [];
var php = "php";
@ -612,18 +625,9 @@ function onOptionsChanged() {
packages += ' default-jdk';
}
if (use_clang) {
if (linux_distro === 'Ubuntu 18' || linux_distro === 'Ubuntu 20') {
packages += ' clang-6.0 libc++-dev libc++abi-dev';
} else {
if (linux_distro === 'Ubuntu 14') {
packages += ' clang-3.9';
} else {
packages += ' clang';
}
packages += ' libc++-dev';
if (linux_distro === 'Debian 10') {
packages += ' libc++abi-dev';
}
packages += ' clang' + getClangVersionSuffix() + ' libc++-dev';
if (linux_distro === 'Debian 10' || linux_distro === 'Ubuntu 18' || linux_distro === 'Ubuntu 20') {
packages += ' libc++abi-dev';
}
} else {
packages += ' g++';
@ -672,7 +676,7 @@ function onOptionsChanged() {
commands.push('git clone https://github.com/tdlib/td.git');
commands.push('cd td');
commands.push('git checkout v1.6.0');
// commands.push('git checkout v1.6.0');
if (use_vcpkg) {
commands.push('git clone https://github.com/Microsoft/vcpkg.git');
@ -786,14 +790,13 @@ function onOptionsChanged() {
var prefix = '';
if (os_linux) {
if (use_clang) {
if (linux_distro === 'Ubuntu 18' || linux_distro === 'Ubuntu 20') {
prefix = 'CC=/usr/bin/clang-6.0 CXX=/usr/bin/clang++-6.0 ';
options.push('-DCMAKE_AR=/usr/bin/llvm-ar-6.0');
options.push('-DCMAKE_NM=/usr/bin/llvm-nm-6.0');
options.push('-DCMAKE_OBJDUMP=/usr/bin/llvm-objdump-6.0');
options.push('-DCMAKE_RANLIB=/usr/bin/llvm-ranlib-6.0');
} else {
prefix = 'CC=/usr/bin/clang CXX=/usr/bin/clang++ ';
var clang_version_suffix = getClangVersionSuffix();
prefix = 'CC=/usr/bin/clang' + clang_version_suffix + ' CXX=/usr/bin/clang++' + clang_version_suffix + ' ';
if (use_lto) {
options.push('-DCMAKE_AR=/usr/bin/llvm-ar' + clang_version_suffix);
options.push('-DCMAKE_NM=/usr/bin/llvm-nm' + clang_version_suffix);
options.push('-DCMAKE_OBJDUMP=/usr/bin/llvm-objdump' + clang_version_suffix);
options.push('-DCMAKE_RANLIB=/usr/bin/llvm-ranlib' + clang_version_suffix);
}
} else if (linux_distro === 'Ubuntu 14') {
prefix = 'CC=/usr/bin/gcc-4.9 CXX=/usr/bin/g++-4.9 ';

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.6.7 REQUIRED)
find_package(Td 1.6.8 REQUIRED)
add_executable(tdjson_example tdjson_example.cpp)
target_link_libraries(tdjson_example PRIVATE Td::TdJson)

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.6.7" Language="en-US" Publisher="Telegram LLC" />
<Identity Id="Telegram.Td.UWP" Version="1.6.8" 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

@ -11,7 +11,6 @@
#if (TD_DARWIN || TD_LINUX) && defined(USE_MEMPROF)
#include <algorithm>
#include <atomic>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
@ -34,6 +33,11 @@ double get_fast_backtrace_success_rate() {
}
#else
#define my_assert(f) \
if (!(f)) { \
std::abort(); \
}
#if TD_LINUX
extern void *__libc_stack_end;
#endif
@ -156,7 +160,7 @@ std::int32_t get_ht_pos(const Backtrace &bt, bool force = false) {
if (pos_hash == 0) {
if (ht_size > HT_MAX_SIZE / 2) {
if (force) {
assert(ht_size * 10 < HT_MAX_SIZE * 7);
my_assert(ht_size * 10 < HT_MAX_SIZE * 7);
} else {
Backtrace unknown_bt{{nullptr}};
unknown_bt[0] = reinterpret_cast<void *>(1);
@ -188,18 +192,21 @@ std::int32_t get_ht_pos(const Backtrace &bt, bool force = false) {
void dump_alloc(const std::function<void(const AllocInfo &)> &func) {
for (auto &node : ht) {
if (node.size == 0) {
auto size = node.size.load(std::memory_order_relaxed);
if (size == 0) {
continue;
}
func(AllocInfo{node.backtrace, node.size.load()});
func(AllocInfo{node.backtrace, size});
}
}
void register_xalloc(malloc_info *info, std::int32_t diff) {
my_assert(info->size >= 0);
if (diff > 0) {
ht[info->ht_pos].size += info->size;
ht[info->ht_pos].size.fetch_add(info->size, std::memory_order_relaxed);
} else {
ht[info->ht_pos].size -= info->size;
auto old_value = ht[info->ht_pos].size.fetch_sub(info->size, std::memory_order_relaxed);
my_assert(old_value >= static_cast<std::size_t>(info->size));
}
}
@ -234,7 +241,7 @@ static malloc_info *get_info(void *data_void) {
auto *buf = data - RESERVED_SIZE;
auto *info = reinterpret_cast<malloc_info *>(buf);
assert(info->magic == MALLOC_INFO_MAGIC);
my_assert(info->magic == MALLOC_INFO_MAGIC);
return info;
}
@ -276,7 +283,7 @@ void *realloc(void *ptr, std::size_t size) {
return new_ptr;
}
void *memalign(std::size_t aligment, std::size_t size) {
assert(false && "Memalign is unsupported");
my_assert(false && "Memalign is unsupported");
return nullptr;
}
}

226627
sqlite/sqlite3.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -405,12 +405,13 @@ user id:int32 first_name:string last_name:string username:string phone_number:st
//@photo User profile photo; may be null
//@is_blocked True, if the user is blocked by the current user
//@can_be_called True, if the user can be called
//@supports_video_calls True, if a video call can be created with the user
//@has_private_calls True, if the user can't be called due to their privacy settings
//@need_phone_number_privacy_exception True, if the current user needs to explicitly allow to share their phone number with the user when the method addContact is used
//@bio A short user bio @share_text For bots, the text that is included with the link when users share the bot
//@group_in_common_count Number of group chats where both the other user and the current user are a member; 0 for the current user
//@bot_info If the user is a bot, information about the bot; may be null
userFullInfo photo:chatPhoto is_blocked:Bool can_be_called:Bool has_private_calls:Bool need_phone_number_privacy_exception:Bool bio:string share_text:string group_in_common_count:int32 bot_info:botInfo = UserFullInfo;
userFullInfo photo:chatPhoto is_blocked:Bool can_be_called:Bool supports_video_calls:Bool has_private_calls:Bool need_phone_number_privacy_exception:Bool bio:string share_text:string group_in_common_count:int32 bot_info:botInfo = UserFullInfo;
//@description Represents a list of users @total_count Approximate total count of users found @user_ids A list of user identifiers
users total_count:int32 user_ids:vector<int32> = Users;
@ -1542,8 +1543,8 @@ messagePoll poll:poll = MessageContent;
//@need_shipping_address True, if the shipping address should be specified @receipt_message_id The identifier of the message with the receipt, after the product has been purchased
messageInvoice title:string description:string photo:photo currency:string total_amount:int53 start_parameter:string is_test:Bool need_shipping_address:Bool receipt_message_id:int53 = MessageContent;
//@description A message with information about an ended call @discard_reason Reason why the call was discarded @duration Call duration, in seconds
messageCall discard_reason:CallDiscardReason duration:int32 = MessageContent;
//@description A message with information about an ended call @is_video True, if the call was a video call @discard_reason Reason why the call was discarded @duration Call duration, in seconds
messageCall is_video:Bool discard_reason:CallDiscardReason duration:int32 = MessageContent;
//@description A newly created basic group @title Title of the basic group @member_user_ids User identifiers of members in the basic group
messageBasicGroupChatCreate title:string member_user_ids:vector<int32> = MessageContent;
@ -1682,11 +1683,17 @@ messageSchedulingStateSendAtDate send_date:int32 = MessageSchedulingState;
messageSchedulingStateSendWhenOnline = MessageSchedulingState;
//@description Options to be used when a message is send
//@description Options to be used when a message is sent
//@disable_notification Pass true to disable notification for the message. Must be false if the message is sent to a secret chat
//@from_background Pass true if the message is sent from the background
//@scheduling_state Message scheduling state. Messages sent to a secret chat, live location messages and self-destructing messages can't be scheduled
sendMessageOptions disable_notification:Bool from_background:Bool scheduling_state:MessageSchedulingState = SendMessageOptions;
messageSendOptions disable_notification:Bool from_background:Bool scheduling_state:MessageSchedulingState = MessageSendOptions;
//@description Options to be used when a message content is copied without a link to the original message
//@send_copy True, if content of the message needs to be copied without a link to the original message. Always true if the message is forwarded to a secret chat
//@replace_caption True, if media caption of the message copy needs to be replaced. Ignored if send_copy is false
//@new_caption New message caption. Ignored if replace_caption is false
messageCopyOptions send_copy:Bool replace_caption:Bool new_caption:formattedText = MessageCopyOptions;
//@class InputMessageContent @description The content of a message to send
@ -1752,9 +1759,8 @@ inputMessagePoll question:string options:vector<string> is_anonymous:Bool type:P
//@description A forwarded message @from_chat_id Identifier for the chat this forwarded message came from @message_id Identifier of the message to forward
//@in_game_share True, if a game message should be shared within a launched game; applies only to game messages
//@send_copy True, if content of the message needs to be copied without a link to the original message. Always true if the message is forwarded to a secret chat
//@remove_caption True, if media caption of the message copy needs to be removed. Ignored if send_copy is false
inputMessageForwarded from_chat_id:int53 message_id:int53 in_game_share:Bool send_copy:Bool remove_caption:Bool = InputMessageContent;
//@copy_options Options to be used to copy content of the message without a link to the original message
inputMessageForwarded from_chat_id:int53 message_id:int53 in_game_share:Bool copy_options:messageCopyOptions = InputMessageContent;
//@class SearchMessagesFilter @description Represents a filter for message search results
@ -1912,8 +1918,18 @@ callDiscardReasonHungUp = CallDiscardReason;
//@library_versions List of supported libtgvoip versions
callProtocol udp_p2p:Bool udp_reflector:Bool min_layer:int32 max_layer:int32 library_versions:vector<string> = CallProtocol;
//@description Describes the address of UDP reflectors @id Reflector identifier @ip IPv4 reflector address @ipv6 IPv6 reflector address @port Reflector port number @peer_tag Connection peer tag
callConnection id:int64 ip:string ipv6:string port:int32 peer_tag:bytes = CallConnection;
//@class CallServerType @description Describes the type of a call server
//@description A Telegram call reflector @peer_tag A peer tag to be used with the reflector
callServerTypeTelegramReflector peer_tag:bytes = CallServerType;
//@description A WebRTC server @username Username to be used for authentification @password Authentication password @supports_turn True, if the server supports TURN @supports_stun True, if the server supports STUN
callServerTypeWebrtc username:string password:string supports_turn:Bool supports_stun:Bool = CallServerType;
//@description Describes a server for relaying call data @id Server identifier @ip_address Server IPv4 address @ipv6_address Server IPv6 address @port Server port number @type Server type
callServer id:int64 ip_address:string ipv6_address:string port:int32 type:CallServerType = CallServer;
//@description Contains the call identifier @id Call identifier
@ -1928,8 +1944,8 @@ callStatePending is_created:Bool is_received:Bool = CallState;
//@description The call has been answered and encryption keys are being exchanged
callStateExchangingKeys = CallState;
//@description The call is ready to use @protocol Call protocols supported by the peer @connections Available UDP reflectors @config A JSON-encoded call config @encryption_key Call encryption key @emojis Encryption key emojis fingerprint @allow_p2p True, if peer-to-peer connection is allowed by users privacy settings
callStateReady protocol:callProtocol connections:vector<callConnection> config:string encryption_key:bytes emojis:vector<string> allow_p2p:Bool = CallState;
//@description The call is ready to use @protocol Call protocols supported by the peer @servers List of available call servers @config A JSON-encoded call config @encryption_key Call encryption key @emojis Encryption key emojis fingerprint @allow_p2p True, if peer-to-peer connection is allowed by users privacy settings
callStateReady protocol:callProtocol servers:vector<callServer> config:string encryption_key:bytes emojis:vector<string> allow_p2p:Bool = CallState;
//@description The call is hanging up after discardCall has been called
callStateHangingUp = CallState;
@ -1965,8 +1981,8 @@ callProblemSilentRemote = CallProblem;
callProblemDropped = CallProblem;
//@description Describes a call @id Call identifier, not persistent @user_id Peer user identifier @is_outgoing True, if the call is outgoing @state Call state
call id:int32 user_id:int32 is_outgoing:Bool state:CallState = Call;
//@description Describes a call @id Call identifier, not persistent @user_id Peer user identifier @is_outgoing True, if the call is outgoing @is_video True, if the call is a video call @state Call state
call id:int32 user_id:int32 is_outgoing:Bool is_video:Bool state:CallState = Call;
//@description Contains settings for the authentication of the user's phone number
@ -3184,6 +3200,9 @@ updateFileGenerationStop generation_id:int64 = Update;
//@description New call was created or information about a call was updated @call New data about a call
updateCall call:call = Update;
//@description New call signaling data arrived @call_id The call identifier @data The data
updateNewCallSignalingData call_id:int32 data:bytes = Update;
//@description Some privacy setting rules have been changed @setting The privacy setting @rules New privacy rules
updateUserPrivacySettingRules setting:UserPrivacySetting rules:userPrivacySettingRules = Update;
@ -3612,13 +3631,13 @@ getMessageLinkInfo url:string = MessageLinkInfo;
//@chat_id Target chat @reply_to_message_id Identifier of the message to reply to or 0
//@options Options to be used to send the message
//@reply_markup Markup for replying to the message; for bots only @input_message_content The content of the message to be sent
sendMessage chat_id:int53 reply_to_message_id:int53 options:sendMessageOptions reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message;
sendMessage chat_id:int53 reply_to_message_id:int53 options:messageSendOptions reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message;
//@description Sends messages grouped together into an album. Currently only photo and video messages can be grouped into an album. Returns sent messages
//@chat_id Target chat @reply_to_message_id Identifier of a message to reply to or 0
//@options Options to be used to send the messages
//@input_message_contents Contents of messages to be sent
sendMessageAlbum chat_id:int53 reply_to_message_id:int53 options:sendMessageOptions input_message_contents:vector<InputMessageContent> = Messages;
sendMessageAlbum chat_id:int53 reply_to_message_id:int53 options:messageSendOptions input_message_contents:vector<InputMessageContent> = Messages;
//@description Invites a bot to a chat (if it is not yet a member) and sends it the /start command. Bots can't be invited to a private chat other than the chat with the bot. Bots can't be invited to channels (although they can be added as admins) and secret chats. Returns the sent message
//@bot_user_id Identifier of the bot @chat_id Identifier of the target chat @parameter A hidden parameter sent to the bot for deep linking purposes (https://core.telegram.org/bots#deep-linking)
@ -3629,7 +3648,7 @@ sendBotStartMessage bot_user_id:int32 chat_id:int53 parameter:string = Message;
//@options Options to be used to send the message
//@query_id Identifier of the inline query @result_id Identifier of the inline result
//@hide_via_bot If true, there will be no mention of a bot, via which the message is sent. Can be used only for bots GetOption("animation_search_bot_username"), GetOption("photo_search_bot_username") and GetOption("venue_search_bot_username")
sendInlineQueryResultMessage chat_id:int53 reply_to_message_id:int53 options:sendMessageOptions query_id:int64 result_id:string hide_via_bot:Bool = Message;
sendInlineQueryResultMessage chat_id:int53 reply_to_message_id:int53 options:messageSendOptions query_id:int64 result_id:string hide_via_bot:Bool = Message;
//@description Forwards previously sent messages. Returns the forwarded messages in the same order as the message identifiers passed in message_ids. If a message can't be forwarded, null will be returned instead of the message
//@chat_id Identifier of the chat to which to forward messages @from_chat_id Identifier of the chat from which to forward messages @message_ids Identifiers of the messages to forward
@ -3637,7 +3656,7 @@ sendInlineQueryResultMessage chat_id:int53 reply_to_message_id:int53 options:sen
//@as_album True, if the messages should be grouped into an album after forwarding. For this to work, no more than 10 messages may be forwarded, and all of them must be photo or video 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 captions 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:sendMessageOptions as_album:Bool send_copy:Bool remove_caption:Bool = Messages;
forwardMessages chat_id:int53 from_chat_id:int53 message_ids:vector<int53> options:messageSendOptions as_album:Bool send_copy:Bool remove_caption: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
@ -4052,14 +4071,17 @@ checkChatInviteLink invite_link:string = ChatInviteLinkInfo;
joinChatByInviteLink invite_link:string = Chat;
//@description Creates a new call @user_id Identifier of the user to be called @protocol Description of the call protocols supported by the application
createCall user_id:int32 protocol:callProtocol = CallId;
//@description Creates a new call @user_id Identifier of the user to be called @protocol Description of the call protocols supported by the application @is_video True, if a video call needs to be created
createCall user_id:int32 protocol:callProtocol is_video:Bool = CallId;
//@description Accepts an incoming call @call_id Call identifier @protocol Description of the call protocols supported by the application
acceptCall call_id:int32 protocol:callProtocol = Ok;
//@description Discards a call @call_id Call identifier @is_disconnected True, if the user was disconnected @duration The call duration, in seconds @connection_id Identifier of the connection used during the call
discardCall call_id:int32 is_disconnected:Bool duration:int32 connection_id:int64 = Ok;
//@description Sends call signaling data @call_id Call identifier @data The data
sendCallSignalingData call_id:int32 data:bytes = Ok;
//@description Discards a call @call_id Call identifier @is_disconnected True, if the user was disconnected @duration The call duration, in seconds @is_video True, if the call was a video call @connection_id Identifier of the connection used during the call
discardCall call_id:int32 is_disconnected:Bool duration:int32 is_video:Bool connection_id:int64 = Ok;
//@description Sends a call rating @call_id Call identifier @rating Call rating; 1-5 @comment An optional user comment if the rating is less than 5 @problems List of the exact types of problems with the call, specified by the user
sendCallRating call_id:int32 rating:int32 comment:string problems:vector<CallProblem> = Ok;

Binary file not shown.

View File

@ -212,7 +212,7 @@ inputReportReasonOther#e1746d0a text:string = ReportReason;
inputReportReasonCopyright#9b89f93a = ReportReason;
inputReportReasonGeoIrrelevant#dbd4feed = ReportReason;
userFull#edf17c12 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 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 = UserFull;
userFull#edf17c12 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 = UserFull;
contact#f911c994 user_id:int mutual:Bool = Contact;
@ -805,13 +805,14 @@ inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_co
inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall;
phoneCallEmpty#5366c915 id:long = PhoneCall;
phoneCallWaiting#1b8f4ad1 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall;
phoneCallRequested#87eabb53 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCallAccepted#997c454a flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector<PhoneConnection> start_date:int = PhoneCall;
phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.5?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
phoneCallWaiting#1b8f4ad1 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall;
phoneCallRequested#87eabb53 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCallAccepted#997c454a flags:# video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector<PhoneConnection> start_date:int = PhoneCall;
phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection;
phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection;
phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector<string> = PhoneCallProtocol;

Binary file not shown.

View File

@ -673,7 +673,7 @@ Status SessionConnection::on_raw_packet(const PacketInfo &info, BufferSlice pack
}
if (status.is_error()) {
if (status.code() == 1) {
LOG(WARNING) << "Packet ignored " << status;
LOG(INFO) << "Packet ignored: " << status;
send_ack(info.message_id);
return Status::OK();
} else if (status.code() == 2) {

View File

@ -21,6 +21,7 @@
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/NotificationManager.h"
#include "td/telegram/PasswordManager.h"
#include "td/telegram/StateManager.h"
#include "td/telegram/StickersManager.h"
#include "td/telegram/Td.h"
#include "td/telegram/TdDb.h"
@ -55,8 +56,7 @@ AuthManager::AuthManager(int32 api_id, const string &api_hash, ActorShared<> par
} else {
LOG(ERROR) << "Restore unknown my_id";
ContactsManager::send_get_me_query(
G()->td().get_actor_unsafe(),
PromiseCreator::lambda([this](Result<Unit> result) { update_state(State::Ok); }));
td, PromiseCreator::lambda([this](Result<Unit> result) { update_state(State::Ok); }));
}
} else if (auth_str == "logout") {
update_state(State::LoggingOut);
@ -220,7 +220,7 @@ void AuthManager::set_login_token_expires_at(double login_token_expires_at) {
login_token_expires_at_ = login_token_expires_at;
poll_export_login_code_timeout_.cancel_timeout();
poll_export_login_code_timeout_.set_callback(std::move(on_update_login_token_static));
poll_export_login_code_timeout_.set_callback_data(static_cast<void *>(G()->td().get_actor_unsafe()));
poll_export_login_code_timeout_.set_callback_data(static_cast<void *>(td));
poll_export_login_code_timeout_.set_timeout_at(login_token_expires_at_);
}
@ -837,6 +837,9 @@ void AuthManager::update_state(State new_state, bool force, bool should_save_sta
if (should_save_state) {
save_state();
}
if (new_state == State::LoggingOut || new_state == State::DestroyingKeys) {
send_closure(G()->state_manager(), &StateManager::on_logging_out, true);
}
send_closure(G()->td(), &Td::send_update,
make_tl_object<td_api::updateAuthorizationState>(get_authorization_state_object(state_)));

View File

@ -64,12 +64,34 @@ CallProtocol::CallProtocol(const td_api::callProtocol &protocol)
, library_versions(protocol.library_versions_) {
}
CallConnection::CallConnection(const telegram_api::phoneConnection &connection)
: id(connection.id_)
, ip(connection.ip_)
, ipv6(connection.ipv6_)
, port(connection.port_)
, peer_tag(connection.peer_tag_.as_slice().str()) {
CallConnection::CallConnection(const telegram_api::PhoneConnection &connection) {
switch (connection.get_id()) {
case telegram_api::phoneConnection::ID: {
auto &conn = static_cast<const telegram_api::phoneConnection &>(connection);
type = Type::Telegram;
id = conn.id_;
ip = conn.ip_;
ipv6 = conn.ipv6_;
port = conn.port_;
peer_tag = conn.peer_tag_.as_slice().str();
break;
}
case telegram_api::phoneConnectionWebrtc::ID: {
auto &conn = static_cast<const telegram_api::phoneConnectionWebrtc &>(connection);
type = Type::Webrtc;
id = conn.id_;
ip = conn.ip_;
ipv6 = conn.ipv6_;
port = conn.port_;
username = conn.username_;
password = conn.password_;
supports_turn = conn.turn_;
supports_stun = conn.stun_;
break;
}
default:
UNREACHABLE();
}
}
tl_object_ptr<td_api::callProtocol> CallProtocol::get_call_protocol_object() const {
@ -77,12 +99,19 @@ tl_object_ptr<td_api::callProtocol> CallProtocol::get_call_protocol_object() con
vector<string>(library_versions));
}
tl_object_ptr<telegram_api::phoneConnection> CallConnection::get_input_phone_connection() const {
return make_tl_object<telegram_api::phoneConnection>(id, ip, ipv6, port, BufferSlice(peer_tag));
}
tl_object_ptr<td_api::callConnection> CallConnection::get_call_connection_object() const {
return make_tl_object<td_api::callConnection>(id, ip, ipv6, port, peer_tag);
tl_object_ptr<td_api::callServer> CallConnection::get_call_server_object() const {
auto server_type = [&]() -> tl_object_ptr<td_api::CallServerType> {
switch (type) {
case Type::Telegram:
return make_tl_object<td_api::callServerTypeTelegramReflector>(peer_tag);
case Type::Webrtc:
return make_tl_object<td_api::callServerTypeWebrtc>(username, password, supports_turn, supports_stun);
default:
UNREACHABLE();
return nullptr;
}
}();
return make_tl_object<td_api::callServer>(id, ip, ipv6, port, std::move(server_type));
}
tl_object_ptr<td_api::CallState> CallState::get_call_state_object() const {
@ -92,7 +121,7 @@ tl_object_ptr<td_api::CallState> CallState::get_call_state_object() const {
case Type::ExchangingKey:
return make_tl_object<td_api::callStateExchangingKeys>();
case Type::Ready: {
auto call_connections = transform(connections, [](auto &c) { return c.get_call_connection_object(); });
auto call_connections = transform(connections, [](auto &c) { return c.get_call_server_object(); });
return make_tl_object<td_api::callStateReady>(protocol.get_call_protocol_object(), std::move(call_connections),
config, key, vector<string>(emojis_fingerprint), allow_p2p);
}
@ -131,8 +160,43 @@ void CallActor::create_call(UserId user_id, tl_object_ptr<telegram_api::InputUse
promise.set_value(CallId(local_call_id_));
}
void CallActor::accept_call(CallProtocol &&protocol, Promise<> promise) {
if (state_ != State::SendAcceptQuery) {
return promise.set_error(Status::Error(400, "Unexpected acceptCall"));
}
is_accepted_ = true;
call_state_.protocol = std::move(protocol);
promise.set_value(Unit());
loop();
}
void CallActor::update_call_signaling_data(string data) {
// nothing to do
if (call_state_.type != CallState::Type::Ready) {
return;
}
auto update = td_api::make_object<td_api::updateNewCallSignalingData>();
update->call_id_ = local_call_id_.get();
update->data_ = std::move(data);
send_closure(G()->td(), &Td::send_update, std::move(update));
}
void CallActor::send_call_signaling_data(string &&data, Promise<> promise) {
if (call_state_.type != CallState::Type::Ready) {
return promise.set_error(Status::Error(400, "Call is not active"));
}
auto query = G()->net_query_creator().create(
telegram_api::phone_sendSignalingData(get_input_phone_call("send_call_signaling_data"), BufferSlice(data)));
send_with_promise(std::move(query),
PromiseCreator::lambda([promise = std::move(promise)](NetQueryPtr net_query) mutable {
auto res = fetch_result<telegram_api::phone_sendSignalingData>(std::move(net_query));
if (res.is_error()) {
promise.set_error(res.move_as_error());
} else {
promise.set_value(Unit());
}
}));
}
void CallActor::discard_call(bool is_disconnected, int32 duration, bool is_video, int64 connection_id,
@ -180,16 +244,6 @@ void CallActor::discard_call(bool is_disconnected, int32 duration, bool is_video
loop();
}
void CallActor::accept_call(CallProtocol &&protocol, Promise<> promise) {
if (state_ != State::SendAcceptQuery) {
return promise.set_error(Status::Error(400, "Unexpected acceptCall"));
}
is_accepted_ = true;
call_state_.protocol = std::move(protocol);
promise.set_value(Unit());
loop();
}
void CallActor::rate_call(int32 rating, string comment, vector<td_api::object_ptr<td_api::CallProblem>> &&problems,
Promise<> promise) {
if (!call_state_.need_rating) {
@ -407,6 +461,8 @@ Status CallActor::do_update_call(telegram_api::phoneCall &call) {
}
cancel_timeout();
is_video_ |= (call.flags_ & telegram_api::phoneCall::VIDEO_MASK) != 0;
LOG(DEBUG) << "Do update call to Ready from state " << static_cast<int32>(state_);
if (state_ == State::WaitAcceptResult) {
dh_handshake_.set_g_a(call.g_a_or_b_.as_slice());
@ -701,7 +757,7 @@ void CallActor::flush_call_state() {
send_closure(G()->td(), &Td::send_update,
make_tl_object<td_api::updateCall>(
make_tl_object<td_api::call>(local_call_id_.get(), is_outgoing_ ? user_id_.get() : call_admin_id_,
is_outgoing_, call_state_.get_call_state_object())));
is_outgoing_, is_video_, call_state_.get_call_state_object())));
}
}

View File

@ -46,17 +46,25 @@ struct CallProtocol {
};
struct CallConnection {
enum class Type : int32 { Telegram, Webrtc };
Type type;
int64 id;
string ip;
string ipv6;
int32 port;
// Telegram
string peer_tag;
explicit CallConnection(const telegram_api::phoneConnection &connection);
// WebRTC
string username;
string password;
bool supports_turn = false;
bool supports_stun = false;
tl_object_ptr<telegram_api::phoneConnection> get_input_phone_connection() const;
explicit CallConnection(const telegram_api::PhoneConnection &connection);
tl_object_ptr<td_api::callConnection> get_call_connection_object() const;
tl_object_ptr<td_api::callServer> get_call_server_object() const;
};
struct CallState {
@ -87,9 +95,10 @@ class CallActor : public NetQueryCallback {
void create_call(UserId user_id, tl_object_ptr<telegram_api::InputUser> &&input_user, CallProtocol &&protocol,
bool is_video, Promise<CallId> &&promise);
void update_call_signaling_data(string data);
void discard_call(bool is_disconnected, int32 duration, bool is_video, int64 connection_id, Promise<> promise);
void accept_call(CallProtocol &&protocol, Promise<> promise);
void update_call_signaling_data(string data);
void send_call_signaling_data(string &&data, Promise<> promise);
void discard_call(bool is_disconnected, int32 duration, bool is_video, int64 connection_id, Promise<> promise);
void rate_call(int32 rating, string comment, vector<td_api::object_ptr<td_api::CallProblem>> &&problems,
Promise<> promise);
void send_call_debug_information(string data, Promise<> promise);

View File

@ -68,6 +68,22 @@ void CallManager::create_call(UserId user_id, tl_object_ptr<telegram_api::InputU
std::move(promise));
}
void CallManager::accept_call(CallId call_id, CallProtocol &&protocol, Promise<> promise) {
auto actor = get_call_actor(call_id);
if (actor.empty()) {
return promise.set_error(Status::Error(400, "Call not found"));
}
send_closure(actor, &CallActor::accept_call, std::move(protocol), std::move(promise));
}
void CallManager::send_call_signaling_data(CallId call_id, string &&data, Promise<> promise) {
auto actor = get_call_actor(call_id);
if (actor.empty()) {
return promise.set_error(Status::Error(400, "Call not found"));
}
send_closure(actor, &CallActor::send_call_signaling_data, std::move(data), std::move(promise));
}
void CallManager::discard_call(CallId call_id, bool is_disconnected, int32 duration, bool is_video, int64 connection_id,
Promise<> promise) {
auto actor = get_call_actor(call_id);
@ -77,14 +93,6 @@ void CallManager::discard_call(CallId call_id, bool is_disconnected, int32 durat
send_closure(actor, &CallActor::discard_call, is_disconnected, duration, is_video, connection_id, std::move(promise));
}
void CallManager::accept_call(CallId call_id, CallProtocol &&protocol, Promise<> promise) {
auto actor = get_call_actor(call_id);
if (actor.empty()) {
return promise.set_error(Status::Error(400, "Call not found"));
}
send_closure(actor, &CallActor::accept_call, std::move(protocol), std::move(promise));
}
void CallManager::rate_call(CallId call_id, int32 rating, string comment,
vector<td_api::object_ptr<td_api::CallProblem>> &&problems, Promise<> promise) {
auto actor = get_call_actor(call_id);

View File

@ -31,9 +31,10 @@ class CallManager : public Actor {
void create_call(UserId user_id, tl_object_ptr<telegram_api::InputUser> &&input_user, CallProtocol &&protocol,
bool is_video, Promise<CallId> promise);
void accept_call(CallId call_id, CallProtocol &&protocol, Promise<> promise);
void send_call_signaling_data(CallId call_id, string &&data, Promise<> promise);
void discard_call(CallId call_id, bool is_disconnected, int32 duration, bool is_video, int64 connection_id,
Promise<> promise);
void accept_call(CallId call_id, CallProtocol &&protocol, Promise<> promise);
void rate_call(CallId call_id, int32 rating, string comment,
vector<td_api::object_ptr<td_api::CallProblem>> &&problems, Promise<> promise);
void send_call_debug_information(CallId call_id, string data, Promise<> promise);

View File

@ -60,7 +60,7 @@ class MultiTd : public Actor {
send_closure(td, &Td::request, request_id, std::move(function));
}
void destroy(int32 td_id) {
void close(int32 td_id) {
auto size = tds_.erase(td_id);
CHECK(size == 1);
}
@ -321,9 +321,9 @@ class MultiImpl {
send_closure(multi_td_, &MultiTd::send, client_id, request_id, std::move(function));
}
void destroy(int32 td_id) {
void close(int32 td_id) {
auto guard = concurrent_scheduler_->get_send_guard();
send_closure(multi_td_, &MultiTd::destroy, td_id);
send_closure(multi_td_, &MultiTd::close, td_id);
}
~MultiImpl() {
@ -412,7 +412,7 @@ class MultiClient::Impl final {
Impl &operator=(Impl &&) = delete;
~Impl() {
for (auto &it : impls_) {
it.second->destroy(it.first);
it.second->close(it.first);
}
while (!impls_.empty()) {
receive(10);
@ -462,7 +462,7 @@ class Client::Impl final {
Impl(Impl &&) = delete;
Impl &operator=(Impl &&) = delete;
~Impl() {
multi_impl_->destroy(td_id_);
multi_impl_->close(td_id_);
while (!is_closed_) {
receive(10);
}

View File

@ -515,7 +515,6 @@ ActorOwn<> get_full_config(DcOption option, Promise<FullConfig> promise, ActorSh
}
void on_result(NetQueryPtr query) override {
promise_.set_result(fetch_result<telegram_api::help_getConfig>(std::move(query)));
stop();
}
void hangup_shared() override {
if (get_link_token() == 1) {
@ -880,8 +879,7 @@ ConfigManager::ConfigManager(ActorShared<> parent) : parent_(std::move(parent))
}
void ConfigManager::start_up() {
ref_cnt_++;
config_recoverer_ = create_actor<ConfigRecoverer>("Recoverer", actor_shared());
config_recoverer_ = create_actor<ConfigRecoverer>("Recoverer", create_reference());
send_closure(config_recoverer_, &ConfigRecoverer::on_dc_options_update, load_dc_options_update());
auto expire_time = load_config_expire_time();
@ -893,7 +891,13 @@ void ConfigManager::start_up() {
}
}
ActorShared<> ConfigManager::create_reference() {
ref_cnt_++;
return actor_shared(this, REFCNT_TOKEN);
}
void ConfigManager::hangup_shared() {
LOG_CHECK(get_link_token() == REFCNT_TOKEN) << "Expected REFCNT_TOKEN, got " << get_link_token();
ref_cnt_--;
try_stop();
}

View File

@ -25,6 +25,7 @@
#include "td/utils/Status.h"
#include "td/utils/Time.h"
#include <limits>
#include <map>
namespace td {
@ -131,6 +132,8 @@ class ConfigManager : public NetQueryCallback {
size_t dismiss_suggested_action_request_count_ = 0;
std::map<SuggestedAction, vector<Promise<Unit>>> dismiss_suggested_action_queries_;
static constexpr uint64 REFCNT_TOKEN = std::numeric_limits<uint64>::max() - 2;
void start_up() override;
void hangup_shared() override;
void hangup() override;
@ -157,6 +160,8 @@ class ConfigManager : public NetQueryCallback {
static void save_config_expire(Timestamp timestamp);
static void save_dc_options_update(DcOptions dc_options);
static DcOptions load_dc_options_update();
ActorShared<> create_reference();
};
} // namespace td

View File

@ -3365,6 +3365,7 @@ void ContactsManager::UserFull::store(StorerT &storer) const {
STORE_FLAG(can_pin_messages);
STORE_FLAG(need_phone_number_privacy_exception);
STORE_FLAG(has_photo);
STORE_FLAG(supports_video_calls);
END_STORE_FLAGS();
if (has_about) {
store(about, storer);
@ -3389,6 +3390,7 @@ void ContactsManager::UserFull::parse(ParserT &parser) {
PARSE_FLAG(can_pin_messages);
PARSE_FLAG(need_phone_number_privacy_exception);
PARSE_FLAG(has_photo);
PARSE_FLAG(supports_video_calls);
END_PARSE_FLAGS();
if (has_about) {
parse(about, parser);
@ -9190,10 +9192,12 @@ void ContactsManager::on_get_user_full(tl_object_ptr<telegram_api::userFull> &&u
}
bool can_be_called = user_full->phone_calls_available_ && !user_full->phone_calls_private_;
bool supports_video_calls = user_full->video_calls_available_ && !user_full->phone_calls_private_;
bool has_private_calls = user_full->phone_calls_private_;
if (user->can_be_called != can_be_called || user->has_private_calls != has_private_calls ||
user->about != user_full->about_) {
if (user->can_be_called != can_be_called || user->supports_video_calls != supports_video_calls ||
user->has_private_calls != has_private_calls || user->about != user_full->about_) {
user->can_be_called = can_be_called;
user->supports_video_calls = supports_video_calls;
user->has_private_calls = has_private_calls;
user->about = std::move(user_full->about_);
@ -10252,6 +10256,7 @@ void ContactsManager::drop_user_full(UserId user_id) {
user_full->photo = Photo();
user_full->is_blocked = false;
user_full->can_be_called = false;
user_full->supports_video_calls = false;
user_full->has_private_calls = false;
user_full->need_phone_number_privacy_exception = false;
user_full->about = string();
@ -10594,7 +10599,7 @@ void ContactsManager::on_get_channel_participants_success(
<< channel_id;
total_count = static_cast<int32>(result.size());
} else if (is_full && total_count > static_cast<int32>(result.size())) {
LOG(ERROR) << "Fix total member count from " << total_count << " to " << result.size();
LOG(ERROR) << "Fix total number of members from " << total_count << " to " << result.size() << " in " << channel_id;
total_count = static_cast<int32>(result.size());
}
@ -11474,7 +11479,7 @@ void ContactsManager::on_update_chat_add_user(ChatId chat_id, UserId inviter_use
// Chat is already updated
if (chat_full->version == c->version &&
narrow_cast<int32>(chat_full->participants.size()) != c->participant_count) {
LOG(ERROR) << "Number of members of " << chat_id << " with version " << c->version << " is "
LOG(ERROR) << "Number of members in " << chat_id << " with version " << c->version << " is "
<< c->participant_count << " but there are " << chat_full->participants.size()
<< " members in the ChatFull";
repair_chat_participants(chat_id);
@ -11748,7 +11753,7 @@ void ContactsManager::on_update_chat_participant_count(Chat *c, ChatId chat_id,
if (version < c->version) {
// some outdated data
LOG(INFO) << "Receive member count of " << chat_id << " with version " << version << debug_str
LOG(INFO) << "Receive number of members in " << chat_id << " with version " << version << debug_str
<< ", but current version is " << c->version;
return;
}
@ -11757,7 +11762,7 @@ void ContactsManager::on_update_chat_participant_count(Chat *c, ChatId chat_id,
if (version == c->version && participant_count != 0) {
// version is not changed when deleted user is removed from the chat
LOG_IF(ERROR, c->participant_count != participant_count + 1)
<< "Member count of " << chat_id << " has changed from " << c->participant_count << " to "
<< "Number of members in " << chat_id << " has changed from " << c->participant_count << " to "
<< participant_count << ", but version " << c->version << " remains unchanged" << debug_str;
repair_chat_participants(chat_id);
}
@ -11844,7 +11849,7 @@ bool ContactsManager::on_update_chat_full_participants_short(ChatFull *chat_full
return true;
}
LOG(INFO) << "Member count of " << chat_id << " with version " << chat_full->version
LOG(INFO) << "Number of members in " << chat_id << " with version " << chat_full->version
<< " has changed, but new version is " << version;
repair_chat_participants(chat_id);
return false;
@ -14118,8 +14123,9 @@ tl_object_ptr<td_api::userFullInfo> ContactsManager::get_user_full_info_object(U
bool is_bot = is_user_bot(user_id);
return make_tl_object<td_api::userFullInfo>(
get_chat_photo_object(td_->file_manager_.get(), user_full->photo), user_full->is_blocked,
user_full->can_be_called, user_full->has_private_calls, user_full->need_phone_number_privacy_exception,
is_bot ? string() : user_full->about, is_bot ? user_full->about : string(), user_full->common_chat_count,
user_full->can_be_called, user_full->supports_video_calls, user_full->has_private_calls,
user_full->need_phone_number_privacy_exception, is_bot ? string() : user_full->about,
is_bot ? user_full->about : string(), user_full->common_chat_count,
is_bot ? get_bot_info_object(user_id) : nullptr);
}

View File

@ -688,6 +688,7 @@ class ContactsManager : public Actor {
bool is_blocked = false;
bool can_be_called = false;
bool supports_video_calls = false;
bool has_private_calls = false;
bool can_pin_messages = false;
bool need_phone_number_privacy_exception = false;

View File

@ -3937,8 +3937,11 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message,
}
unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const MessageContent *content,
MessageContentDupType type) {
MessageContentDupType type, MessageCopyOptions &&copy_options) {
CHECK(content != nullptr);
if (copy_options.send_copy) {
CHECK(type == MessageContentDupType::Copy);
}
if (type != MessageContentDupType::Forward && type != MessageContentDupType::SendViaBot &&
!can_have_input_media(td, content)) {
return nullptr;
@ -3961,12 +3964,12 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
if (to_secret) {
thumbnail_file_id = get_message_content_thumbnail_file_id(content, td);
}
auto remove_caption = type == MessageContentDupType::CopyWithoutCaption;
auto replace_caption = type == MessageContentDupType::Copy && copy_options.replace_caption;
switch (content->get_type()) {
case MessageContentType::Animation: {
auto result = make_unique<MessageAnimation>(*static_cast<const MessageAnimation *>(content));
if (remove_caption) {
result->caption = FormattedText();
if (replace_caption) {
result->caption = std::move(copy_options.new_caption);
}
if (td->documents_manager_->has_input_media(result->file_id, thumbnail_file_id, to_secret)) {
return std::move(result);
@ -3977,8 +3980,8 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
}
case MessageContentType::Audio: {
auto result = make_unique<MessageAudio>(*static_cast<const MessageAudio *>(content));
if (remove_caption) {
result->caption = FormattedText();
if (replace_caption) {
result->caption = std::move(copy_options.new_caption);
}
if (td->documents_manager_->has_input_media(result->file_id, thumbnail_file_id, to_secret)) {
return std::move(result);
@ -3998,8 +4001,8 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
}
case MessageContentType::Document: {
auto result = make_unique<MessageDocument>(*static_cast<const MessageDocument *>(content));
if (remove_caption) {
result->caption = FormattedText();
if (replace_caption) {
result->caption = std::move(copy_options.new_caption);
}
if (td->documents_manager_->has_input_media(result->file_id, thumbnail_file_id, to_secret)) {
return std::move(result);
@ -4022,8 +4025,8 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
return make_unique<MessageLocation>(*static_cast<const MessageLocation *>(content));
case MessageContentType::Photo: {
auto result = make_unique<MessagePhoto>(*static_cast<const MessagePhoto *>(content));
if (remove_caption) {
result->caption = FormattedText();
if (replace_caption) {
result->caption = std::move(copy_options.new_caption);
}
CHECK(!result->photo.photos.empty());
@ -4103,8 +4106,8 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
return make_unique<MessageVenue>(*static_cast<const MessageVenue *>(content));
case MessageContentType::Video: {
auto result = make_unique<MessageVideo>(*static_cast<const MessageVideo *>(content));
if (remove_caption) {
result->caption = FormattedText();
if (replace_caption) {
result->caption = std::move(copy_options.new_caption);
}
if (td->documents_manager_->has_input_media(result->file_id, thumbnail_file_id, to_secret)) {
return std::move(result);
@ -4125,8 +4128,8 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
}
case MessageContentType::VoiceNote: {
auto result = make_unique<MessageVoiceNote>(*static_cast<const MessageVoiceNote *>(content));
if (remove_caption) {
result->caption = FormattedText();
if (replace_caption) {
result->caption = std::move(copy_options.new_caption);
}
result->is_listened = false;
if (td->documents_manager_->has_input_media(result->file_id, thumbnail_file_id, to_secret)) {
@ -4491,7 +4494,8 @@ tl_object_ptr<td_api::MessageContent> get_message_content_object(const MessageCo
}
case MessageContentType::Call: {
const MessageCall *m = static_cast<const MessageCall *>(content);
return make_tl_object<td_api::messageCall>(get_call_discard_reason_object(m->discard_reason), m->duration);
return make_tl_object<td_api::messageCall>(m->is_video, get_call_discard_reason_object(m->discard_reason),
m->duration);
}
case MessageContentType::PaymentSuccessful: {
const MessagePaymentSuccessful *m = static_cast<const MessagePaymentSuccessful *>(content);

View File

@ -12,6 +12,7 @@
#include "td/telegram/FullMessageId.h"
#include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/MessageContentType.h"
#include "td/telegram/MessageCopyOptions.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/Photo.h"
@ -174,10 +175,10 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message_tex
DialogId owner_dialog_id, bool is_content_read, UserId via_bot_user_id,
int32 *ttl);
enum class MessageContentDupType : int32 { Send, SendViaBot, Forward, Copy, CopyWithoutCaption };
enum class MessageContentDupType : int32 { Send, SendViaBot, Forward, Copy };
unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const MessageContent *content,
MessageContentDupType type);
MessageContentDupType type, MessageCopyOptions &&copy_options);
unique_ptr<MessageContent> get_action_message_content(Td *td, tl_object_ptr<telegram_api::MessageAction> &&action,
DialogId owner_dialog_id, MessageId reply_to_message_id);

View File

@ -0,0 +1,41 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// 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/MessageEntity.h"
#include "td/telegram/ReplyMarkup.h"
#include "td/utils/common.h"
#include "td/utils/StringBuilder.h"
namespace td {
struct MessageCopyOptions {
bool send_copy = false;
bool replace_caption = false;
FormattedText new_caption;
unique_ptr<ReplyMarkup> reply_markup;
MessageCopyOptions() = default;
MessageCopyOptions(bool send_copy, bool remove_caption) : send_copy(send_copy), replace_caption(remove_caption) {
}
};
inline StringBuilder &operator<<(StringBuilder &string_builder, MessageCopyOptions copy_options) {
if (copy_options.send_copy) {
string_builder << "CopyOptions[replace_caption = " << copy_options.replace_caption;
}
if (copy_options.replace_caption) {
string_builder << ", new_caption = " << copy_options.new_caption;
}
if (copy_options.send_copy) {
string_builder << "]";
}
return string_builder;
}
} // namespace td

View File

@ -4491,6 +4491,7 @@ void MessagesManager::Dialog::store(StorerT &storer) const {
bool has_folder_id = folder_id != FolderId();
bool has_pending_read_channel_inbox = pending_read_channel_inbox_pts != 0;
bool has_distance = distance >= 0;
bool has_last_yet_unsent_message = last_message_id.is_valid() && last_message_id.is_yet_unsent();
BEGIN_STORE_FLAGS();
STORE_FLAG(has_draft_message);
STORE_FLAG(has_last_database_message);
@ -4543,6 +4544,7 @@ void MessagesManager::Dialog::store(StorerT &storer) const {
STORE_FLAG(can_unarchive);
STORE_FLAG(has_distance);
STORE_FLAG(hide_distance);
STORE_FLAG(has_last_yet_unsent_message);
END_STORE_FLAGS();
}
@ -4708,6 +4710,7 @@ void MessagesManager::Dialog::parse(ParserT &parser) {
PARSE_FLAG(can_unarchive);
PARSE_FLAG(has_distance);
PARSE_FLAG(hide_distance);
PARSE_FLAG(had_last_yet_unsent_message);
END_PARSE_FLAGS();
} else {
is_folder_id_inited = false;
@ -4721,6 +4724,7 @@ void MessagesManager::Dialog::parse(ParserT &parser) {
need_repair_channel_server_unread_count = false;
can_unarchive = false;
hide_distance = false;
had_last_yet_unsent_message = false;
}
parse(last_new_message_id, parser);
@ -5234,15 +5238,15 @@ int32 MessagesManager::get_message_index_mask(DialogId dialog_id, const Message
if (m->is_content_secret || (m->ttl > 0 && !is_secret)) {
return 0;
}
int32 mentions_mask = get_message_content_index_mask(m->content.get(), td_, is_secret, m->is_outgoing);
int32 index_mask = get_message_content_index_mask(m->content.get(), td_, is_secret, m->is_outgoing);
if (m->contains_mention) {
mentions_mask |= search_messages_filter_index_mask(SearchMessagesFilter::Mention);
index_mask |= search_messages_filter_index_mask(SearchMessagesFilter::Mention);
if (m->contains_unread_mention) {
mentions_mask |= search_messages_filter_index_mask(SearchMessagesFilter::UnreadMention);
index_mask |= search_messages_filter_index_mask(SearchMessagesFilter::UnreadMention);
}
}
LOG(INFO) << "Have index mask " << mentions_mask << " for " << m->message_id << " in " << dialog_id;
return mentions_mask;
LOG(INFO) << "Have index mask " << index_mask << " for " << m->message_id << " in " << dialog_id;
return index_mask;
}
vector<MessageId> MessagesManager::get_message_ids(const vector<int64> &input_message_ids) {
@ -6061,13 +6065,11 @@ bool MessagesManager::update_message_contains_unread_mention(Dialog *d, Message
m->contains_unread_mention = false;
if (d->unread_mention_count == 0) {
if (d->message_count_by_index[search_messages_filter_index(SearchMessagesFilter::UnreadMention)] != -1) {
if (is_dialog_inited(d)) {
LOG(ERROR) << "Unread mention count of " << d->dialog_id << " became negative from " << source;
}
} else {
d->unread_mention_count--;
d->message_count_by_index[search_messages_filter_index(SearchMessagesFilter::UnreadMention)] =
d->unread_mention_count;
set_dialog_unread_mention_count(d, d->unread_mention_count - 1);
on_dialog_updated(d->dialog_id, "update_message_contains_unread_mention");
}
LOG(INFO) << "Update unread mention message count in " << d->dialog_id << " to " << d->unread_mention_count
@ -6157,18 +6159,18 @@ void MessagesManager::on_update_dialog_online_member_count(DialogId dialog_id, i
}
if (!dialog_id.is_valid()) {
LOG(ERROR) << "Receive online member count in invalid " << dialog_id;
LOG(ERROR) << "Receive number of online members in invalid " << dialog_id;
return;
}
if (is_broadcast_channel(dialog_id)) {
LOG_IF(ERROR, online_member_count != 0)
<< "Receive online member count " << online_member_count << " in a broadcast " << dialog_id;
<< "Receive " << online_member_count << " as a number of online members in a channel " << dialog_id;
return;
}
if (online_member_count < 0) {
LOG(ERROR) << "Receive online member count " << online_member_count << " in a " << dialog_id;
LOG(ERROR) << "Receive " << online_member_count << " as a number of online members in a " << dialog_id;
return;
}
@ -6409,7 +6411,7 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p
auto channel_id = dialog_id.get_channel_id();
if (!td_->contacts_manager_->have_channel(channel_id)) {
// do not create dialog if there is no info about the channel
LOG(WARNING) << "There is no info about " << channel_id << ", so ignore " << to_string(update);
LOG(WARNING) << "There is no info about " << channel_id << ", so ignore " << oneline(to_string(update));
return;
}
@ -9617,8 +9619,7 @@ void MessagesManager::delete_all_dialog_messages(Dialog *d, bool remove_from_dia
}
if (d->unread_mention_count > 0) {
d->unread_mention_count = 0;
d->message_count_by_index[search_messages_filter_index(SearchMessagesFilter::UnreadMention)] = 0;
set_dialog_unread_mention_count(d, 0);
send_update_chat_unread_mention_count(d);
}
@ -9742,8 +9743,7 @@ void MessagesManager::read_all_dialog_mentions(DialogId dialog_id, Promise<Unit>
}
if (d->unread_mention_count != 0) {
d->unread_mention_count = 0;
d->message_count_by_index[search_messages_filter_index(SearchMessagesFilter::UnreadMention)] = 0;
set_dialog_unread_mention_count(d, 0);
if (!is_update_sent) {
send_update_chat_unread_mention_count(d);
} else {
@ -10515,8 +10515,8 @@ void MessagesManager::set_dialog_online_member_count(DialogId dialog_id, int32 o
}
auto &info = dialog_online_member_counts_[dialog_id];
LOG(INFO) << "Change online member count from " << info.online_member_count << " to " << online_member_count << " in "
<< dialog_id << " from " << source;
LOG(INFO) << "Change number of online members from " << info.online_member_count << " to " << online_member_count
<< " in " << dialog_id << " from " << source;
bool need_update = d->is_opened && (!info.is_update_sent || info.online_member_count != online_member_count);
info.online_member_count = online_member_count;
info.updated_time = Time::now();
@ -10539,7 +10539,7 @@ void MessagesManager::on_update_dialog_online_member_count_timeout(DialogId dial
return;
}
LOG(INFO) << "Expired timeout for online member count for " << dialog_id;
LOG(INFO) << "Expired timeout for number of online members in " << dialog_id;
Dialog *d = get_dialog(dialog_id);
CHECK(d != nullptr);
if (!d->is_opened) {
@ -12386,6 +12386,14 @@ void MessagesManager::set_dialog_last_clear_history_date(Dialog *d, int32 date,
}
}
void MessagesManager::set_dialog_unread_mention_count(Dialog *d, int32 unread_mention_count) {
CHECK(d->unread_mention_count != unread_mention_count);
CHECK(unread_mention_count >= 0);
d->unread_mention_count = unread_mention_count;
d->message_count_by_index[search_messages_filter_index(SearchMessagesFilter::UnreadMention)] = unread_mention_count;
}
void MessagesManager::set_dialog_is_empty(Dialog *d, const char *source) {
LOG(INFO) << "Set " << d->dialog_id << " is_empty to true from " << source;
d->is_empty = true;
@ -12401,8 +12409,7 @@ void MessagesManager::set_dialog_is_empty(Dialog *d, const char *source) {
}
}
if (d->unread_mention_count > 0) {
d->unread_mention_count = 0;
d->message_count_by_index[search_messages_filter_index(SearchMessagesFilter::UnreadMention)] = 0;
set_dialog_unread_mention_count(d, 0);
send_update_chat_unread_mention_count(d);
}
if (d->reply_markup_message_id != MessageId()) {
@ -13025,10 +13032,8 @@ void MessagesManager::on_get_dialogs(FolderId folder_id, vector<tl_object_ptr<te
if (!G()->parameters().use_message_db || is_new) {
if (d->unread_mention_count != dialog->unread_mentions_count_) {
d->unread_mention_count = dialog->unread_mentions_count_;
set_dialog_unread_mention_count(d, dialog->unread_mentions_count_);
update_dialog_mention_notification_count(d);
d->message_count_by_index[search_messages_filter_index(SearchMessagesFilter::UnreadMention)] =
d->unread_mention_count;
send_update_chat_unread_mention_count(d);
}
}
@ -13637,13 +13642,12 @@ unique_ptr<MessagesManager::Message> MessagesManager::do_delete_message(Dialog *
}
if (result->contains_unread_mention) {
if (d->unread_mention_count == 0) {
LOG_IF(ERROR,
d->message_count_by_index[search_messages_filter_index(SearchMessagesFilter::UnreadMention)] != -1)
<< "Unread mention count became negative in " << d->dialog_id << " after deletion of " << message_id;
if (is_dialog_inited(d)) {
LOG(ERROR) << "Unread mention count became negative in " << d->dialog_id << " after deletion of "
<< message_id;
}
} else {
d->unread_mention_count--;
d->message_count_by_index[search_messages_filter_index(SearchMessagesFilter::UnreadMention)] =
d->unread_mention_count;
set_dialog_unread_mention_count(d, d->unread_mention_count - 1);
send_update_chat_unread_mention_count(d);
}
}
@ -20013,7 +20017,7 @@ tl_object_ptr<td_api::messages> MessagesManager::get_messages_object(
}
MessagesManager::Message *MessagesManager::get_message_to_send(
Dialog *d, MessageId reply_to_message_id, const SendMessageOptions &options, unique_ptr<MessageContent> &&content,
Dialog *d, MessageId reply_to_message_id, const MessageSendOptions &options, unique_ptr<MessageContent> &&content,
bool *need_update_dialog_pos, unique_ptr<MessageForwardInfo> forward_info, bool is_copy) {
CHECK(d != nullptr);
CHECK(!reply_to_message_id.is_scheduled());
@ -20542,7 +20546,7 @@ class MessagesManager::SendMessageLogEvent {
};
Result<MessageId> MessagesManager::send_message(DialogId dialog_id, MessageId reply_to_message_id,
tl_object_ptr<td_api::sendMessageOptions> &&options,
tl_object_ptr<td_api::messageSendOptions> &&options,
tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
tl_object_ptr<td_api::InputMessageContent> &&input_message_content) {
if (input_message_content == nullptr) {
@ -20551,10 +20555,11 @@ Result<MessageId> MessagesManager::send_message(DialogId dialog_id, MessageId re
LOG(INFO) << "Begin to send message to " << dialog_id << " in reply to " << reply_to_message_id;
if (input_message_content->get_id() == td_api::inputMessageForwarded::ID) {
auto input_message = static_cast<const td_api::inputMessageForwarded *>(input_message_content.get());
auto input_message = td_api::move_object_as<td_api::inputMessageForwarded>(input_message_content);
TRY_RESULT(copy_options, process_message_copy_options(dialog_id, std::move(input_message->copy_options_)));
TRY_RESULT_ASSIGN(copy_options.reply_markup, get_dialog_reply_markup(dialog_id, std::move(reply_markup)));
return forward_message(dialog_id, DialogId(input_message->from_chat_id_), MessageId(input_message->message_id_),
std::move(options), input_message->in_game_share_, input_message->send_copy_,
input_message->remove_caption_);
std::move(options), input_message->in_game_share_, std::move(copy_options));
}
Dialog *d = get_dialog_force(dialog_id);
@ -20565,16 +20570,16 @@ Result<MessageId> MessagesManager::send_message(DialogId dialog_id, MessageId re
TRY_STATUS(can_send_message(dialog_id));
TRY_RESULT(message_reply_markup, get_dialog_reply_markup(dialog_id, std::move(reply_markup)));
TRY_RESULT(message_content, process_input_message_content(dialog_id, std::move(input_message_content)));
TRY_RESULT(send_message_options, process_send_message_options(dialog_id, std::move(options)));
TRY_STATUS(can_use_send_message_options(send_message_options, message_content));
TRY_RESULT(message_send_options, process_message_send_options(dialog_id, std::move(options)));
TRY_STATUS(can_use_message_send_options(message_send_options, message_content));
// there must be no errors after get_message_to_send call
bool need_update_dialog_pos = false;
Message *m = get_message_to_send(
d, get_reply_to_message_id(d, reply_to_message_id), send_message_options,
dup_message_content(td_, dialog_id, message_content.content.get(), MessageContentDupType::Send),
&need_update_dialog_pos, nullptr, message_content.via_bot_user_id.is_valid());
Message *m = get_message_to_send(d, get_reply_to_message_id(d, reply_to_message_id), message_send_options,
dup_message_content(td_, dialog_id, message_content.content.get(),
MessageContentDupType::Send, MessageCopyOptions()),
&need_update_dialog_pos, nullptr, message_content.via_bot_user_id.is_valid());
m->reply_markup = std::move(message_reply_markup);
m->via_bot_user_id = message_content.via_bot_user_id;
m->disable_web_page_preview = message_content.disable_web_page_preview;
@ -20606,8 +20611,9 @@ Result<InputMessageContent> MessagesManager::process_input_message_content(
}
if (input_message_content->get_id() == td_api::inputMessageForwarded::ID) {
auto input_message = static_cast<const td_api::inputMessageForwarded *>(input_message_content.get());
if (!input_message->send_copy_) {
auto input_message = td_api::move_object_as<td_api::inputMessageForwarded>(input_message_content);
TRY_RESULT(copy_options, process_message_copy_options(dialog_id, std::move(input_message->copy_options_)));
if (!copy_options.send_copy) {
return Status::Error(400, "Can't use forwarded message");
}
@ -20632,9 +20638,8 @@ Result<InputMessageContent> MessagesManager::process_input_message_content(
return Status::Error(400, "Can't copy message");
}
unique_ptr<MessageContent> content = dup_message_content(
td_, dialog_id, copied_message->content.get(),
input_message->remove_caption_ ? MessageContentDupType::CopyWithoutCaption : MessageContentDupType::Copy);
unique_ptr<MessageContent> content = dup_message_content(td_, dialog_id, copied_message->content.get(),
MessageContentDupType::Copy, std::move(copy_options));
if (content == nullptr) {
return Status::Error(400, "Can't copy message content");
}
@ -20659,9 +20664,25 @@ Result<InputMessageContent> MessagesManager::process_input_message_content(
return std::move(content);
}
Result<MessagesManager::SendMessageOptions> MessagesManager::process_send_message_options(
DialogId dialog_id, tl_object_ptr<td_api::sendMessageOptions> &&options) const {
SendMessageOptions result;
Result<MessageCopyOptions> MessagesManager::process_message_copy_options(
DialogId dialog_id, tl_object_ptr<td_api::messageCopyOptions> &&options) const {
if (options == nullptr || !options->send_copy_) {
return MessageCopyOptions();
}
MessageCopyOptions result;
result.send_copy = true;
result.replace_caption = options->replace_caption_;
if (result.replace_caption) {
TRY_RESULT_ASSIGN(result.new_caption,
process_input_caption(td_->contacts_manager_.get(), dialog_id, std::move(options->new_caption_),
td_->auth_manager_->is_bot()));
}
return std::move(result);
}
Result<MessagesManager::MessageSendOptions> MessagesManager::process_message_send_options(
DialogId dialog_id, tl_object_ptr<td_api::messageSendOptions> &&options) const {
MessageSendOptions result;
if (options != nullptr) {
result.disable_notification = options->disable_notification_;
result.from_background = options->from_background_;
@ -20693,7 +20714,7 @@ Result<MessagesManager::SendMessageOptions> MessagesManager::process_send_messag
return result;
}
Status MessagesManager::can_use_send_message_options(const SendMessageOptions &options,
Status MessagesManager::can_use_message_send_options(const MessageSendOptions &options,
const unique_ptr<MessageContent> &content, int32 ttl) {
if (options.schedule_date != 0) {
if (ttl > 0) {
@ -20707,9 +20728,9 @@ Status MessagesManager::can_use_send_message_options(const SendMessageOptions &o
return Status::OK();
}
Status MessagesManager::can_use_send_message_options(const SendMessageOptions &options,
Status MessagesManager::can_use_message_send_options(const MessageSendOptions &options,
const InputMessageContent &content) {
return can_use_send_message_options(options, content.content, content.ttl);
return can_use_message_send_options(options, content.content, content.ttl);
}
int64 MessagesManager::generate_new_media_album_id() {
@ -20721,7 +20742,7 @@ int64 MessagesManager::generate_new_media_album_id() {
}
Result<vector<MessageId>> MessagesManager::send_message_group(
DialogId dialog_id, MessageId reply_to_message_id, tl_object_ptr<td_api::sendMessageOptions> &&options,
DialogId dialog_id, MessageId reply_to_message_id, tl_object_ptr<td_api::messageSendOptions> &&options,
vector<tl_object_ptr<td_api::InputMessageContent>> &&input_message_contents) {
if (input_message_contents.size() > MAX_GROUPED_MESSAGES) {
return Status::Error(4, "Too much messages to send as an album");
@ -20736,12 +20757,12 @@ Result<vector<MessageId>> MessagesManager::send_message_group(
}
TRY_STATUS(can_send_message(dialog_id));
TRY_RESULT(send_message_options, process_send_message_options(dialog_id, std::move(options)));
TRY_RESULT(message_send_options, process_message_send_options(dialog_id, std::move(options)));
vector<std::pair<unique_ptr<MessageContent>, int32>> message_contents;
for (auto &input_message_content : input_message_contents) {
TRY_RESULT(message_content, process_input_message_content(dialog_id, std::move(input_message_content)));
TRY_STATUS(can_use_send_message_options(send_message_options, message_content));
TRY_STATUS(can_use_message_send_options(message_send_options, message_content));
if (!is_allowed_media_group_content(message_content.content->get_type())) {
return Status::Error(5, "Wrong message content type");
}
@ -20761,10 +20782,10 @@ Result<vector<MessageId>> MessagesManager::send_message_group(
vector<MessageId> result;
bool need_update_dialog_pos = false;
for (auto &message_content : message_contents) {
Message *m = get_message_to_send(
d, reply_to_message_id, send_message_options,
dup_message_content(td_, dialog_id, message_content.first.get(), MessageContentDupType::Send),
&need_update_dialog_pos);
Message *m = get_message_to_send(d, reply_to_message_id, message_send_options,
dup_message_content(td_, dialog_id, message_content.first.get(),
MessageContentDupType::Send, MessageCopyOptions()),
&need_update_dialog_pos);
result.push_back(m->message_id);
auto ttl = message_content.second;
if (ttl > 0) {
@ -21391,7 +21412,7 @@ Result<MessageId> MessagesManager::send_bot_start_message(UserId bot_user_id, Di
vector<MessageEntity> text_entities;
text_entities.emplace_back(MessageEntity::Type::BotCommand, 0, narrow_cast<int32>(text.size()));
bool need_update_dialog_pos = false;
Message *m = get_message_to_send(d, MessageId(), SendMessageOptions(),
Message *m = get_message_to_send(d, MessageId(), MessageSendOptions(),
create_text_message_content(text, std::move(text_entities), WebPageId()),
&need_update_dialog_pos);
m->is_bot_start_message = true;
@ -21476,7 +21497,7 @@ void MessagesManager::do_send_bot_start_message(UserId bot_user_id, DialogId dia
}
Result<MessageId> MessagesManager::send_inline_query_result_message(DialogId dialog_id, MessageId reply_to_message_id,
tl_object_ptr<td_api::sendMessageOptions> &&options,
tl_object_ptr<td_api::messageSendOptions> &&options,
int64 query_id, const string &result_id,
bool hide_via_bot) {
LOG(INFO) << "Begin to send inline query result message to " << dialog_id << " in reply to " << reply_to_message_id;
@ -21487,7 +21508,7 @@ Result<MessageId> MessagesManager::send_inline_query_result_message(DialogId dia
}
TRY_STATUS(can_send_message(dialog_id));
TRY_RESULT(send_message_options, process_send_message_options(dialog_id, std::move(options)));
TRY_RESULT(message_send_options, process_message_send_options(dialog_id, std::move(options)));
bool to_secret = false;
switch (dialog_id.get_type()) {
case DialogType::User:
@ -21515,14 +21536,14 @@ Result<MessageId> MessagesManager::send_inline_query_result_message(DialogId dia
return Status::Error(5, "Inline query result not found");
}
TRY_STATUS(can_use_send_message_options(send_message_options, content->message_content, 0));
TRY_STATUS(can_use_message_send_options(message_send_options, content->message_content, 0));
TRY_STATUS(can_send_message_content(dialog_id, content->message_content.get(), false));
bool need_update_dialog_pos = false;
Message *m = get_message_to_send(
d, get_reply_to_message_id(d, reply_to_message_id), send_message_options,
dup_message_content(td_, dialog_id, content->message_content.get(), MessageContentDupType::SendViaBot),
&need_update_dialog_pos, nullptr, true);
Message *m = get_message_to_send(d, get_reply_to_message_id(d, reply_to_message_id), message_send_options,
dup_message_content(td_, dialog_id, content->message_content.get(),
MessageContentDupType::SendViaBot, MessageCopyOptions()),
&need_update_dialog_pos, nullptr, true);
m->hide_via_bot = hide_via_bot;
if (!hide_via_bot) {
m->via_bot_user_id = td_->inline_queries_manager_->get_inline_bot_user_id(query_id);
@ -22091,7 +22112,8 @@ void MessagesManager::edit_message_media(FullMessageId full_message_id,
cancel_edit_message_media(dialog_id, m, "Cancelled by new editMessageMedia request");
m->edited_content = dup_message_content(td_, dialog_id, content.content.get(), MessageContentDupType::Send);
m->edited_content =
dup_message_content(td_, dialog_id, content.content.get(), MessageContentDupType::Send, MessageCopyOptions());
CHECK(m->edited_content != nullptr);
m->edited_reply_markup = r_new_reply_markup.move_as_ok();
m->edit_generation = ++current_message_edit_generation_;
@ -22928,10 +22950,12 @@ void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_d
}
Result<MessageId> MessagesManager::forward_message(DialogId to_dialog_id, DialogId from_dialog_id, MessageId message_id,
tl_object_ptr<td_api::sendMessageOptions> &&options,
bool in_game_share, bool send_copy, bool remove_caption) {
tl_object_ptr<td_api::messageSendOptions> &&options,
bool in_game_share, MessageCopyOptions &&copy_options) {
vector<MessageCopyOptions> all_copy_options;
all_copy_options.push_back(std::move(copy_options));
TRY_RESULT(result, forward_messages(to_dialog_id, from_dialog_id, {message_id}, std::move(options), in_game_share,
false, send_copy, remove_caption));
false, std::move(all_copy_options)));
CHECK(result.size() == 1);
auto sent_message_id = result[0];
if (sent_message_id == MessageId()) {
@ -22942,9 +22966,10 @@ Result<MessageId> MessagesManager::forward_message(DialogId to_dialog_id, Dialog
Result<vector<MessageId>> MessagesManager::forward_messages(DialogId to_dialog_id, DialogId from_dialog_id,
vector<MessageId> message_ids,
tl_object_ptr<td_api::sendMessageOptions> &&options,
bool in_game_share, bool as_album, bool send_copy,
bool remove_caption) {
tl_object_ptr<td_api::messageSendOptions> &&options,
bool in_game_share, bool as_album,
vector<MessageCopyOptions> &&copy_options) {
CHECK(copy_options.size() == message_ids.size());
if (message_ids.size() > 100) { // TODO replace with const from config or implement mass-forward
return Status::Error(4, "Too much messages to forward");
}
@ -22969,7 +22994,7 @@ Result<vector<MessageId>> MessagesManager::forward_messages(DialogId to_dialog_i
}
TRY_STATUS(can_send_message(to_dialog_id));
TRY_RESULT(send_message_options, process_send_message_options(to_dialog_id, std::move(options)));
TRY_RESULT(message_send_options, process_message_send_options(to_dialog_id, std::move(options)));
for (auto message_id : message_ids) {
if (message_id.is_valid_scheduled()) {
@ -22989,6 +23014,7 @@ Result<vector<MessageId>> MessagesManager::forward_messages(DialogId to_dialog_i
struct CopiedMessage {
unique_ptr<MessageContent> content;
unique_ptr<ReplyMarkup> reply_markup;
bool disable_web_page_preview;
size_t index;
};
@ -23012,10 +23038,11 @@ Result<vector<MessageId>> MessagesManager::forward_messages(DialogId to_dialog_i
continue;
}
bool need_copy = !message_id.is_server() || to_secret || send_copy;
auto type = need_copy ? (remove_caption ? MessageContentDupType::CopyWithoutCaption : MessageContentDupType::Copy)
: MessageContentDupType::Forward;
unique_ptr<MessageContent> content = dup_message_content(td_, to_dialog_id, forwarded_message->content.get(), type);
bool need_copy = !message_id.is_server() || to_secret || copy_options[i].send_copy;
auto type = need_copy ? MessageContentDupType::Copy : MessageContentDupType::Forward;
auto reply_markup = std::move(copy_options[i].reply_markup);
unique_ptr<MessageContent> content =
dup_message_content(td_, to_dialog_id, forwarded_message->content.get(), type, std::move(copy_options[i]));
if (content == nullptr) {
LOG(INFO) << "Can't forward " << message_id;
continue;
@ -23027,14 +23054,15 @@ Result<vector<MessageId>> MessagesManager::forward_messages(DialogId to_dialog_i
continue;
}
auto can_use_options_status = can_use_send_message_options(send_message_options, content, 0);
auto can_use_options_status = can_use_message_send_options(message_send_options, content, 0);
if (can_use_options_status.is_error()) {
LOG(INFO) << "Can't forward " << message_id << ": " << can_send_status.message();
continue;
}
if (need_copy) {
copied_messages.push_back({std::move(content), get_message_disable_web_page_preview(forwarded_message), i});
copied_messages.push_back(
{std::move(content), std::move(reply_markup), get_message_disable_web_page_preview(forwarded_message), i});
continue;
}
@ -23077,14 +23105,14 @@ Result<vector<MessageId>> MessagesManager::forward_messages(DialogId to_dialog_i
}
}
Message *m = get_message_to_send(to_dialog, MessageId(), send_message_options, std::move(content),
Message *m = get_message_to_send(to_dialog, MessageId(), message_send_options, std::move(content),
&need_update_dialog_pos, std::move(forward_info));
m->real_forward_from_dialog_id = from_dialog_id;
m->real_forward_from_message_id = message_id;
m->via_bot_user_id = forwarded_message->via_bot_user_id;
m->in_game_share = in_game_share;
if (forwarded_message->views > 0 && m->forward_info != nullptr) {
m->views = forwarded_message->views;
m->views = 1;
}
if (is_game) {
@ -23175,10 +23203,11 @@ Result<vector<MessageId>> MessagesManager::forward_messages(DialogId to_dialog_i
}
for (auto &copied_message : copied_messages) {
Message *m = get_message_to_send(to_dialog, MessageId(), send_message_options, std::move(copied_message.content),
Message *m = get_message_to_send(to_dialog, MessageId(), message_send_options, std::move(copied_message.content),
&need_update_dialog_pos, nullptr, true);
m->disable_web_page_preview = copied_message.disable_web_page_preview;
m->media_album_id = media_album_id;
m->reply_markup = std::move(copied_message.reply_markup);
save_send_message_logevent(to_dialog_id, m);
do_send_message(to_dialog_id, m);
@ -23242,7 +23271,7 @@ Result<vector<MessageId>> MessagesManager::resend_messages(DialogId dialog_id, v
CHECK(m != nullptr);
unique_ptr<MessageContent> content =
dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::Send);
dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::Send, MessageCopyOptions());
if (content == nullptr) {
LOG(INFO) << "Can't resend " << m->message_id;
continue;
@ -23282,7 +23311,7 @@ Result<vector<MessageId>> MessagesManager::resend_messages(DialogId dialog_id, v
CHECK(message != nullptr);
send_update_delete_messages(dialog_id, {message->message_id.get()}, true, false);
SendMessageOptions options(message->disable_notification, message->from_background,
MessageSendOptions options(message->disable_notification, message->from_background,
get_message_schedule_date(message.get()));
Message *m = get_message_to_send(d, get_reply_to_message_id(d, message->reply_to_message_id), options,
std::move(new_contents[i]), &need_update_dialog_pos, nullptr, message->is_copy);
@ -23328,7 +23357,7 @@ Result<MessageId> MessagesManager::send_dialog_set_ttl_message(DialogId dialog_i
TRY_STATUS(can_send_message(dialog_id));
bool need_update_dialog_pos = false;
Message *m = get_message_to_send(d, MessageId(), SendMessageOptions(), create_chat_set_ttl_message_content(ttl),
Message *m = get_message_to_send(d, MessageId(), MessageSendOptions(), create_chat_set_ttl_message_content(ttl),
&need_update_dialog_pos);
send_update_new_message(d, m);
@ -23361,7 +23390,7 @@ Status MessagesManager::send_screenshot_taken_notification_message(DialogId dial
if (dialog_type == DialogType::User) {
bool need_update_dialog_pos = false;
const Message *m = get_message_to_send(d, MessageId(), SendMessageOptions(),
const Message *m = get_message_to_send(d, MessageId(), MessageSendOptions(),
create_screenshot_taken_message_content(), &need_update_dialog_pos);
do_send_screenshot_taken_notification_message(dialog_id, m, 0);
@ -28728,6 +28757,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq
}
if (message->contains_unread_mention && message_id <= d->last_read_all_mentions_message_id) {
LOG(INFO) << "Ignore unread mention in " << message_id;
message->contains_unread_mention = false;
if (message->from_database) {
on_message_changed(d, message.get(), false, "add already read mention message to dialog");
@ -28973,9 +29003,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq
}
}
if (*need_update && message->contains_unread_mention) {
d->unread_mention_count++;
d->message_count_by_index[search_messages_filter_index(SearchMessagesFilter::UnreadMention)] =
d->unread_mention_count;
set_dialog_unread_mention_count(d, d->unread_mention_count + 1);
send_update_chat_unread_mention_count(d);
}
if (*need_update) {
@ -30531,7 +30559,7 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr<Message> &&last_datab
update_dialog_pos(d, "fix_new_dialog 7", true, is_loaded_from_database);
}
if (is_loaded_from_database && d->order != order && order < MAX_ORDINARY_DIALOG_ORDER &&
!td_->contacts_manager_->is_dialog_info_received_from_server(dialog_id)) {
!td_->contacts_manager_->is_dialog_info_received_from_server(dialog_id) && !d->had_last_yet_unsent_message) {
LOG(ERROR) << dialog_id << " has order " << d->order << " instead of saved to database order " << order;
}
@ -31913,9 +31941,7 @@ void MessagesManager::on_get_channel_dialog(DialogId dialog_id, MessageId last_m
false, "on_get_channel_dialog 50");
}
if (d->unread_mention_count != unread_mention_count) {
d->unread_mention_count = unread_mention_count;
d->message_count_by_index[search_messages_filter_index(SearchMessagesFilter::UnreadMention)] =
d->unread_mention_count;
set_dialog_unread_mention_count(d, unread_mention_count);
update_dialog_mention_notification_count(d);
send_update_chat_unread_mention_count(d);
}
@ -32434,12 +32460,14 @@ void MessagesManager::on_binlog_events(vector<BinlogEvent> &&events) {
add_message_dependencies(dependencies, dialog_id, m.get());
resolve_dependencies_force(td_, dependencies);
m->content = dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::Send);
m->content =
dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::Send, MessageCopyOptions());
auto result_message = continue_send_message(dialog_id, std::move(m), event.id_);
if (result_message != nullptr) {
do_send_message(dialog_id, result_message);
}
break;
}
case LogEvent::HandlerType::SendBotStartMessage: {
@ -32499,7 +32527,8 @@ void MessagesManager::on_binlog_events(vector<BinlogEvent> &&events) {
add_message_dependencies(dependencies, dialog_id, m.get());
resolve_dependencies_force(td_, dependencies);
m->content = dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::SendViaBot);
m->content = dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::SendViaBot,
MessageCopyOptions());
auto result_message = continue_send_message(dialog_id, std::move(m), event.id_);
if (result_message != nullptr) {
@ -32588,7 +32617,8 @@ void MessagesManager::on_binlog_events(vector<BinlogEvent> &&events) {
set_message_id(m, get_next_yet_unsent_message_id(to_dialog));
m->date = now;
}
m->content = dup_message_content(td_, to_dialog_id, m->content.get(), MessageContentDupType::Forward);
m->content = dup_message_content(td_, to_dialog_id, m->content.get(), MessageContentDupType::Forward,
MessageCopyOptions());
CHECK(m->content != nullptr);
m->have_previous = true;
m->have_next = true;

View File

@ -29,6 +29,7 @@
#include "td/telegram/Global.h"
#include "td/telegram/InputDialogId.h"
#include "td/telegram/MessageContentType.h"
#include "td/telegram/MessageCopyOptions.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessagesDb.h"
#include "td/telegram/net/NetQuery.h"
@ -367,26 +368,27 @@ class MessagesManager : public Actor {
DialogId search_public_dialog(const string &username_to_search, bool force, Promise<Unit> &&promise);
Result<MessageId> send_message(
DialogId dialog_id, MessageId reply_to_message_id, tl_object_ptr<td_api::sendMessageOptions> &&options,
DialogId dialog_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;
Result<vector<MessageId>> send_message_group(
DialogId dialog_id, MessageId reply_to_message_id, tl_object_ptr<td_api::sendMessageOptions> &&options,
DialogId dialog_id, MessageId reply_to_message_id, tl_object_ptr<td_api::messageSendOptions> &&options,
vector<tl_object_ptr<td_api::InputMessageContent>> &&input_message_contents) TD_WARN_UNUSED_RESULT;
Result<MessageId> send_bot_start_message(UserId bot_user_id, DialogId dialog_id,
const string &parameter) TD_WARN_UNUSED_RESULT;
Result<MessageId> send_inline_query_result_message(DialogId dialog_id, MessageId reply_to_message_id,
tl_object_ptr<td_api::sendMessageOptions> &&options,
tl_object_ptr<td_api::messageSendOptions> &&options,
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::sendMessageOptions> &&options, bool in_game_share,
bool as_album, bool send_copy, bool remove_caption) TD_WARN_UNUSED_RESULT;
tl_object_ptr<td_api::messageSendOptions> &&options, bool in_game_share,
bool as_album,
vector<MessageCopyOptions> &&copy_options) TD_WARN_UNUSED_RESULT;
Result<vector<MessageId>> resend_messages(DialogId dialog_id, vector<MessageId> message_ids) TD_WARN_UNUSED_RESULT;
@ -1153,6 +1155,7 @@ class MessagesManager : public Actor {
bool is_has_scheduled_database_messages_checked = false;
bool has_loaded_scheduled_messages_from_database = false;
bool sent_scheduled_messages = false;
bool had_last_yet_unsent_message = false; // whether the dialog was stored to database without last message
bool increment_view_counter = false;
@ -1504,13 +1507,13 @@ class MessagesManager : public Actor {
Promise<> success_promise;
};
struct SendMessageOptions {
struct MessageSendOptions {
bool disable_notification = false;
bool from_background = false;
int32 schedule_date = 0;
SendMessageOptions() = default;
SendMessageOptions(bool disable_notification, bool from_background, int32 schedule_date)
MessageSendOptions() = default;
MessageSendOptions(bool disable_notification, bool from_background, int32 schedule_date)
: disable_notification(disable_notification), from_background(from_background), schedule_date(schedule_date) {
}
};
@ -1648,14 +1651,17 @@ class MessagesManager : public Actor {
Result<InputMessageContent> process_input_message_content(
DialogId dialog_id, tl_object_ptr<td_api::InputMessageContent> &&input_message_content);
Result<SendMessageOptions> process_send_message_options(DialogId dialog_id,
tl_object_ptr<td_api::sendMessageOptions> &&options) const;
Result<MessageCopyOptions> process_message_copy_options(DialogId dialog_id,
tl_object_ptr<td_api::messageCopyOptions> &&options) const;
static Status can_use_send_message_options(const SendMessageOptions &options,
Result<MessageSendOptions> process_message_send_options(DialogId dialog_id,
tl_object_ptr<td_api::messageSendOptions> &&options) const;
static Status can_use_message_send_options(const MessageSendOptions &options,
const unique_ptr<MessageContent> &content, int32 ttl);
static Status can_use_send_message_options(const SendMessageOptions &options, const InputMessageContent &content);
static Status can_use_message_send_options(const MessageSendOptions &options, const InputMessageContent &content);
Message *get_message_to_send(Dialog *d, MessageId reply_to_message_id, const SendMessageOptions &options,
Message *get_message_to_send(Dialog *d, MessageId reply_to_message_id, const MessageSendOptions &options,
unique_ptr<MessageContent> &&content, bool *need_update_dialog_pos,
unique_ptr<MessageForwardInfo> forward_info = nullptr, bool is_copy = false);
@ -1702,8 +1708,8 @@ class MessagesManager : public Actor {
const vector<MessageId> &message_ids, uint64 logevent_id);
Result<MessageId> forward_message(DialogId to_dialog_id, DialogId from_dialog_id, MessageId message_id,
tl_object_ptr<td_api::sendMessageOptions> &&options, bool in_game_share,
bool send_copy, bool remove_caption) TD_WARN_UNUSED_RESULT;
tl_object_ptr<td_api::messageSendOptions> &&options, bool in_game_share,
MessageCopyOptions &&copy_options) TD_WARN_UNUSED_RESULT;
void do_send_media(DialogId dialog_id, Message *m, FileId file_id, FileId thumbnail_file_id,
tl_object_ptr<telegram_api::InputFile> input_file,
@ -2131,6 +2137,8 @@ class MessagesManager : public Actor {
void set_dialog_last_clear_history_date(Dialog *d, int32 date, MessageId last_clear_history_message_id,
const char *source, bool is_loaded_from_database = false);
static void set_dialog_unread_mention_count(Dialog *d, int32 unread_mention_count);
void set_dialog_is_empty(Dialog *d, const char *source);
static int32 get_pinned_dialogs_limit(DialogListId dialog_list_id);

View File

@ -3184,8 +3184,8 @@ Status NotificationManager::process_push_notification_payload(string payload, bo
return Status::Error(406, "New secret chat notification is not supported");
}
if (begins_with(loc_key, "PHONE_CALL_")) {
// TODO PHONE_CALL_REQUEST/PHONE_CALL_DECLINE/PHONE_CALL_MISSED notification
if (begins_with(loc_key, "PHONE_CALL_") || begins_with(loc_key, "VIDEO_CALL_")) {
// TODO PHONE_CALL_REQUEST/PHONE_CALL_DECLINE/PHONE_CALL_MISSED/VIDEO_CALL_REQUEST/VIDEO_CALL_MISSED notifications
return Status::Error(406, "Phone call notification is not supported");
}

View File

@ -327,7 +327,7 @@ void SecretChatActor::send_message_impl(tl_object_ptr<secret_api::DecryptedMessa
LOG(INFO) << "Send message: " << to_string(*message) << to_string(file);
auto it = random_id_to_outbound_message_state_token_.find(random_id);
if (it != end(random_id_to_outbound_message_state_token_)) {
if (it != random_id_to_outbound_message_state_token_.end()) {
return on_outbound_outer_send_message_promise(it->second, std::move(promise));
}
@ -1126,8 +1126,8 @@ void SecretChatActor::do_outbound_message_impl(unique_ptr<logevent::OutboundSecr
}
void SecretChatActor::on_his_in_seq_no_updated() {
auto it = begin(out_seq_no_to_outbound_message_state_token_);
while (it != end(out_seq_no_to_outbound_message_state_token_) && it->first < seq_no_state_.his_in_seq_no) {
auto it = out_seq_no_to_outbound_message_state_token_.begin();
while (it != out_seq_no_to_outbound_message_state_token_.end() && it->first < seq_no_state_.his_in_seq_no) {
auto token = it->second;
it = out_seq_no_to_outbound_message_state_token_.erase(it);
on_outbound_ack(token);
@ -1141,6 +1141,7 @@ void SecretChatActor::on_pfs_state_changed() {
LOG(INFO) << "In on_pfs_state_changed: " << pfs_state_;
pfs_state_changed_ = true;
}
Promise<> SecretChatActor::add_changes(Promise<> save_changes_finish) {
StateChange change;
if (seq_no_state_changed_) {

View File

@ -17,7 +17,6 @@
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/SequenceDispatcher.h"
#include "td/telegram/StateManager.h"
#include "td/telegram/Td.h"
#include "td/telegram/TdDb.h"
#include "td/telegram/secret_api.h"
@ -34,7 +33,6 @@
#include "td/utils/common.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/Random.h"
#include "td/utils/Status.h"
#include "td/utils/Time.h"

View File

@ -7,7 +7,6 @@
#pragma once
#include "td/telegram/logevent/SecretChatEvent.h"
#include "td/telegram/PtsManager.h"
#include "td/telegram/SecretChatActor.h"
#include "td/telegram/SecretChatId.h"
@ -17,6 +16,7 @@
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/common.h"
#include "td/utils/Time.h"
#include <map>

View File

@ -78,9 +78,14 @@ void StateManager::on_proxy(bool use_proxy) {
loop();
}
void StateManager::on_logging_out(bool is_logging_out) {
is_logging_out_ = is_logging_out;
notify_flag(Flag::LoggingOut);
}
void StateManager::add_callback(unique_ptr<Callback> callback) {
if (callback->on_network(network_type_, network_generation_) && callback->on_online(online_flag_) &&
callback->on_state(get_real_state())) {
callback->on_state(get_real_state()) && callback->on_logging_out(is_logging_out_)) {
callbacks_.push_back(std::move(callback));
}
}
@ -121,6 +126,8 @@ void StateManager::notify_flag(Flag flag) {
return (*it)->on_state(flush_state_);
case Flag::Network:
return (*it)->on_network(network_type_, network_generation_);
case Flag::LoggingOut:
return (*it)->on_logging_out(is_logging_out_);
default:
UNREACHABLE();
return true;

View File

@ -34,6 +34,9 @@ class StateManager final : public Actor {
virtual bool on_online(bool is_online) {
return true;
}
virtual bool on_logging_out(bool is_logging_out) {
return true;
}
};
explicit StateManager(ActorShared<> parent) : parent_(std::move(parent)) {
@ -49,6 +52,8 @@ class StateManager final : public Actor {
void on_proxy(bool use_proxy);
void on_logging_out(bool is_logging_out);
void add_callback(unique_ptr<Callback> net_callback);
void wait_first_sync(Promise<> promise);
@ -104,6 +109,7 @@ class StateManager final : public Actor {
uint32 network_generation_ = 1;
bool online_flag_ = false;
bool use_proxy_ = false;
bool is_logging_out_ = false;
static constexpr double UP_DELAY = 0.05;
static constexpr double DOWN_DELAY = 0.3;
@ -121,7 +127,7 @@ class StateManager final : public Actor {
void inc_connect();
void dec_connect();
enum class Flag : int32 { Online, State, Network };
enum class Flag : int32 { Online, State, Network, LoggingOut };
void notify_flag(Flag flag);
void start_up() override;

View File

@ -47,6 +47,7 @@
#include "td/telegram/LanguagePackManager.h"
#include "td/telegram/Location.h"
#include "td/telegram/Logging.h"
#include "td/telegram/MessageCopyOptions.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessagesManager.h"
@ -3189,7 +3190,7 @@ void Td::schedule_get_promo_data(int32 expires_in) {
if (expires_in > 86400) {
expires_in = 86400;
}
if (!close_flag_ && !auth_manager_->is_bot()) {
if (!close_flag_ && auth_manager_->is_authorized() && !auth_manager_->is_bot()) {
LOG(INFO) << "Schedule getPromoData in " << expires_in;
alarm_timeout_.set_timeout_in(PROMO_DATA_ALARM_ID, expires_in);
}
@ -5761,9 +5762,13 @@ 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 r_message_ids = messages_manager_->forward_messages(
dialog_id, DialogId(request.from_chat_id_), MessagesManager::get_message_ids(request.message_ids_),
std::move(request.options_), false, request.as_album_, request.send_copy_, request.remove_caption_);
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, request.as_album_, 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());
}
@ -5828,7 +5833,7 @@ void Td::on_request(uint64 id, td_api::createNewSecretChat &request) {
CREATE_REQUEST(CreateNewSecretChatRequest, request.user_id_);
}
void Td::on_request(uint64 id, td_api::createCall &request) {
void Td::on_request(uint64 id, const td_api::createCall &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<CallId> result) mutable {
@ -5854,17 +5859,10 @@ void Td::on_request(uint64 id, td_api::createCall &request) {
}
send_closure(G()->call_manager(), &CallManager::create_call, user_id, std::move(input_user),
CallProtocol(*request.protocol_), false, std::move(query_promise));
CallProtocol(*request.protocol_), request.is_video_, std::move(query_promise));
}
void Td::on_request(uint64 id, td_api::discardCall &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
send_closure(G()->call_manager(), &CallManager::discard_call, CallId(request.call_id_), request.is_disconnected_,
request.duration_, false, request.connection_id_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::acceptCall &request) {
void Td::on_request(uint64 id, const td_api::acceptCall &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
if (!request.protocol_) {
@ -5874,6 +5872,20 @@ void Td::on_request(uint64 id, td_api::acceptCall &request) {
CallProtocol(*request.protocol_), std::move(promise));
}
void Td::on_request(uint64 id, td_api::sendCallSignalingData &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
send_closure(G()->call_manager(), &CallManager::send_call_signaling_data, CallId(request.call_id_),
std::move(request.data_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::discardCall &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
send_closure(G()->call_manager(), &CallManager::discard_call, CallId(request.call_id_), request.is_disconnected_,
request.duration_, request.is_video_, request.connection_id_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::sendCallRating &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.comment_);

View File

@ -229,7 +229,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.6.7";
static constexpr const char *TDLIB_VERSION = "1.6.8";
static constexpr int64 ONLINE_ALARM_ID = 0;
static constexpr int64 PING_SERVER_ALARM_ID = -1;
static constexpr int32 PING_SERVER_TIMEOUT = 300;
@ -664,11 +664,13 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, td_api::createNewSecretChat &request);
void on_request(uint64 id, td_api::createCall &request);
void on_request(uint64 id, const td_api::createCall &request);
void on_request(uint64 id, td_api::discardCall &request);
void on_request(uint64 id, const td_api::acceptCall &request);
void on_request(uint64 id, td_api::acceptCall &request);
void on_request(uint64 id, td_api::sendCallSignalingData &request);
void on_request(uint64 id, const td_api::discardCall &request);
void on_request(uint64 id, td_api::sendCallRating &request);

View File

@ -304,8 +304,9 @@ Status TdDb::init_sqlite(int32 scheduler_id, const TdParameters &parameters, DbK
}
sqlite_path_ = sql_database_path;
TRY_STATUS(SqliteDb::change_key(sqlite_path_, key, old_key));
sql_connection_ = std::make_shared<SqliteConnectionSafe>(sql_database_path, key);
TRY_RESULT(db_instance, SqliteDb::change_key(sqlite_path_, key, old_key));
sql_connection_ = std::make_shared<SqliteConnectionSafe>(sql_database_path, key, db_instance.get_cipher_version());
sql_connection_->set(std::move(db_instance));
auto &db = sql_connection_->get();
TRY_STATUS(init_db(db));

View File

@ -8,7 +8,7 @@
namespace td {
constexpr int32 MTPROTO_LAYER = 116;
constexpr int32 MTPROTO_LAYER = 117;
enum class Version : int32 {
Initial, // 0
@ -31,7 +31,7 @@ enum class Version : int32 {
AddMessageUnsupportedVersion,
SupportInstantView2_0,
AddNotificationGroupInfoMaxRemovedMessageId,
SupportMinithumbnails, // 20
SupportMinithumbnails, // 20
AddVideoCallsSupport,
AddPhotoSizeSource,
AddFolders,

View File

@ -18,6 +18,7 @@
#include "td/utils/base64.h"
#include "td/utils/buffer.h"
#include "td/utils/common.h"
#include "td/utils/crypto.h"
#include "td/utils/FileLog.h"
#include "td/utils/format.h"
#include "td/utils/JsonBuilder.h"
@ -1391,14 +1392,14 @@ class CliClient final : public Actor {
auto chat = as_chat_id(chat_id);
auto id = send_request(td_api::make_object<td_api::sendMessage>(
chat, reply_to_message_id,
td_api::make_object<td_api::sendMessageOptions>(disable_notification, from_background,
td_api::make_object<td_api::messageSendOptions>(disable_notification, from_background,
as_message_scheduling_state(schedule_date_)),
nullptr, std::move(input_message_content)));
query_id_to_send_message_info_[id].start_time = Time::now();
}
td_api::object_ptr<td_api::sendMessageOptions> default_send_message_options() const {
return td_api::make_object<td_api::sendMessageOptions>(false, false, as_message_scheduling_state(schedule_date_));
td_api::object_ptr<td_api::messageSendOptions> default_message_send_options() const {
return td_api::make_object<td_api::messageSendOptions>(false, false, as_message_scheduling_state(schedule_date_));
}
void send_get_background_url(td_api::object_ptr<td_api::BackgroundType> &&background_type) {
@ -2706,7 +2707,7 @@ class CliClient final : public Actor {
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_send_message_options(), op[2] == 'g',
chat, as_chat_id(from_chat_id), as_message_ids(message_ids), default_message_send_options(), op[2] == 'g',
op[0] == 'c', Random::fast(0, 1) == 1));
} else if (op == "resend") {
string chat_id;
@ -2730,16 +2731,21 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::closeSecretChat>(as_secret_chat_id(args)));
} else if (op == "cc" || op == "CreateCall") {
send_request(td_api::make_object<td_api::createCall>(
as_user_id(args), td_api::make_object<td_api::callProtocol>(true, true, 65, 65, vector<string>{"2.6"})));
as_user_id(args), td_api::make_object<td_api::callProtocol>(true, true, 65, 65, vector<string>{"2.6", "3.0"}),
Random::fast(0, 1) == 1));
} else if (op == "ac" || op == "AcceptCall") {
send_request(td_api::make_object<td_api::acceptCall>(
as_call_id(args),
td_api::make_object<td_api::callProtocol>(true, true, 65, 65, vector<string>{"2.6", "3.0"})));
} else if (op == "scsd") {
send_request(td_api::make_object<td_api::sendCallSignalingData>(as_call_id(args), "abacaba"));
} else if (op == "dc" || op == "DiscardCall") {
string call_id;
string is_disconnected;
std::tie(call_id, is_disconnected) = split(args);
send_request(td_api::make_object<td_api::discardCall>(as_call_id(call_id), as_bool(is_disconnected), 0, 0));
} else if (op == "ac" || op == "AcceptCall") {
send_request(td_api::make_object<td_api::acceptCall>(
as_call_id(args), td_api::make_object<td_api::callProtocol>(true, true, 65, 65, vector<string>{"2.6"})));
send_request(td_api::make_object<td_api::discardCall>(as_call_id(call_id), as_bool(is_disconnected), 0,
Random::fast(0, 1) == 1, 0));
} else if (op == "scr" || op == "SendCallRating") {
string call_id;
string rating;
@ -2965,7 +2971,7 @@ class CliClient final : public Actor {
photos = full_split(args);
send_request(td_api::make_object<td_api::sendMessageAlbum>(
as_chat_id(chat_id), as_message_id(reply_to_message_id), default_send_message_options(),
as_chat_id(chat_id), as_message_id(reply_to_message_id), default_message_send_options(),
transform(photos, [](const string &photo_path) {
td_api::object_ptr<td_api::InputMessageContent> content = td_api::make_object<td_api::inputMessagePhoto>(
as_input_file(photo_path), nullptr, Auto(), 0, 0, as_caption(""), 0);
@ -3094,7 +3100,7 @@ class CliClient final : public Actor {
auto chat = as_chat_id(chat_id);
send_request(td_api::make_object<td_api::sendInlineQueryResultMessage>(
chat, 0, default_send_message_options(), to_integer<int64>(query_id), result_id, op == "siqrh"));
chat, 0, default_message_send_options(), to_integer<int64>(query_id), result_id, op == "siqrh"));
} else if (op == "gcqr") {
string chat_id;
string message_id;
@ -3194,9 +3200,15 @@ class CliClient final : public Actor {
std::tie(chat_id, args) = split(args);
std::tie(from_chat_id, from_message_id) = split(args);
send_message(chat_id, td_api::make_object<td_api::inputMessageForwarded>(as_chat_id(from_chat_id),
as_message_id(from_message_id), true,
op == "scopy", Random::fast(0, 1) == 0));
td_api::object_ptr<td_api::messageCopyOptions> copy_options;
if (op == "scopy") {
copy_options =
td_api::make_object<td_api::messageCopyOptions>(true, Random::fast(0, 1) == 0, as_caption("_as_d"));
}
send_message(chat_id,
td_api::make_object<td_api::inputMessageForwarded>(
as_chat_id(from_chat_id), as_message_id(from_message_id), true, std::move(copy_options)));
} else if (op == "sdice" || op == "sdicecd") {
string chat_id;
string emoji;
@ -4332,8 +4344,9 @@ void main(int argc, char **argv) {
set_signal_handler(SignalType::Error, fail_signal).ensure();
set_signal_handler(SignalType::Abort, fail_signal).ensure();
Log::set_fatal_error_callback(on_fatal_error);
init_openssl_threads();
const char *locale_name = (std::setlocale(LC_ALL, "fr-FR") == nullptr ? "" : "fr-FR");
const char *locale_name = (std::setlocale(LC_ALL, "fr-FR") == nullptr ? "C" : "fr-FR");
std::locale new_locale(locale_name);
std::locale::global(new_locale);
SCOPE_EXIT {

View File

@ -2388,19 +2388,25 @@ class FileManager::ForceUploadActor : public Actor {
explicit UploadCallback(ActorId<ForceUploadActor> callback) : callback_(std::move(callback)) {
}
void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) override {
send_closure(callback_, &ForceUploadActor::on_upload_ok, std::move(input_file));
send_closure(std::move(callback_), &ForceUploadActor::on_upload_ok, std::move(input_file));
}
void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) override {
send_closure(callback_, &ForceUploadActor::on_upload_encrypted_ok, std::move(input_file));
send_closure(std::move(callback_), &ForceUploadActor::on_upload_encrypted_ok, std::move(input_file));
}
void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) override {
send_closure(callback_, &ForceUploadActor::on_upload_secure_ok, std::move(input_file));
send_closure(std::move(callback_), &ForceUploadActor::on_upload_secure_ok, std::move(input_file));
}
void on_upload_error(FileId file_id, Status error) override {
send_closure(callback_, &ForceUploadActor::on_upload_error, std::move(error));
send_closure(std::move(callback_), &ForceUploadActor::on_upload_error, std::move(error));
}
~UploadCallback() {
if (callback_.empty()) {
return;
}
send_closure(std::move(callback_), &ForceUploadActor::on_upload_error, td::Status::Error("Cancelled"));
}
private:
@ -2466,6 +2472,9 @@ class FileManager::ForceUploadActor : public Actor {
if (is_active_) {
return;
}
if (G()->close_flag()) {
return stop();
}
is_active_ = true;
attempt_++;

View File

@ -90,6 +90,8 @@ class StatsCallback final : public mtproto::RawConnection::StatsCallback {
} // namespace detail
ConnectionCreator::ClientInfo::ClientInfo() {
sanity_flood_control.add_limit(5, 10);
flood_control.add_limit(1, 1);
flood_control.add_limit(4, 2);
flood_control.add_limit(8, 3);
@ -549,6 +551,7 @@ void ConnectionCreator::on_network(bool network_flag, uint32 network_generation)
for (auto &client : clients_) {
client.second.backoff.clear();
client.second.sanity_flood_control.clear_events();
client.second.flood_control.clear_events();
client.second.flood_control_online.clear_events();
client_loop(client.second);
@ -567,11 +570,26 @@ void ConnectionCreator::on_online(bool online_flag) {
if (need_drop_flood_control) {
for (auto &client : clients_) {
client.second.backoff.clear();
client.second.sanity_flood_control.clear_events();
client.second.flood_control_online.clear_events();
client_loop(client.second);
}
}
}
void ConnectionCreator::on_logging_out(bool is_logging_out) {
if (is_logging_out_ == is_logging_out) {
return;
}
VLOG(connections) << "Receive logging out flag " << is_logging_out;
is_logging_out_ = is_logging_out;
for (auto &client : clients_) {
client.second.backoff.clear();
client.second.sanity_flood_control.clear_events();
client.second.flood_control_online.clear_events();
client_loop(client.second);
}
}
void ConnectionCreator::on_pong(size_t hash) {
G()->save_server_time();
@ -852,17 +870,20 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
}
}
bool act_as_if_online = online_flag_ || is_logging_out_;
// Check flood
auto &flood_control = online_flag_ ? client.flood_control_online : client.flood_control;
auto &flood_control = act_as_if_online ? client.flood_control_online : client.flood_control;
auto wakeup_at = max(flood_control.get_wakeup_at(), client.mtproto_error_flood_control.get_wakeup_at());
if (!online_flag_) {
wakeup_at = max(client.sanity_flood_control.get_wakeup_at(), wakeup_at);
if (!act_as_if_online) {
wakeup_at = max(wakeup_at, client.backoff.get_wakeup_at());
}
if (wakeup_at > Time::now()) {
return client_set_timeout_at(client, wakeup_at);
}
flood_control.add_event(static_cast<int32>(Time::now()));
if (!online_flag_) {
client.sanity_flood_control.add_event(static_cast<int32>(Time::now()));
if (!act_as_if_online) {
client.backoff.add_event(static_cast<int32>(Time::now()));
}
@ -879,6 +900,9 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
return client_set_timeout_at(client, Time::now() + 0.1);
}
// Events with failed socket creation are ignored
flood_control.add_event(static_cast<int32>(Time::now()));
auto socket_fd = r_socket_fd.move_as_ok();
IPAddress debug_ip;
auto debug_ip_status = debug_ip.init_socket_address(socket_fd);
@ -1057,6 +1081,10 @@ void ConnectionCreator::start_up() {
send_closure(connection_creator_, &ConnectionCreator::on_online, online_flag);
return connection_creator_.is_alive();
}
bool on_logging_out(bool is_logging_out) override {
send_closure(connection_creator_, &ConnectionCreator::on_logging_out, is_logging_out);
return connection_creator_.is_alive();
}
private:
ActorId<ConnectionCreator> connection_creator_;

View File

@ -103,6 +103,7 @@ class ConnectionCreator : public NetQueryCallback {
bool network_flag_ = false;
uint32 network_generation_ = 0;
bool online_flag_ = false;
bool is_logging_out_ = false;
bool is_inited_ = false;
static constexpr int32 MAX_PROXY_LAST_USED_SAVE_DELAY = 60;
@ -146,6 +147,7 @@ class ConnectionCreator : public NetQueryCallback {
void add_session_id(int64 session_id);
Backoff backoff;
FloodControlStrict sanity_flood_control;
FloodControlStrict flood_control;
FloodControlStrict flood_control_online;
FloodControlStrict mtproto_error_flood_control;
@ -211,6 +213,7 @@ class ConnectionCreator : public NetQueryCallback {
void on_network(bool network_flag, uint32 network_generation);
void on_online(bool online_flag);
void on_logging_out(bool is_logging_out);
static void update_mtproto_header(const Proxy &proxy);

View File

@ -227,7 +227,7 @@ void NetQueryDispatcher::update_session_count() {
}
void NetQueryDispatcher::destroy_auth_keys(Promise<> promise) {
std::lock_guard<std::mutex> guard(main_dc_id_mutex_);
LOG(INFO) << "Destory auth keys";
LOG(INFO) << "Destroy auth keys";
need_destroy_auth_key_ = true;
for (size_t i = 1; i < MAX_DC_COUNT; i++) {
if (is_dc_inited(narrow_cast<int32>(i)) && dcs_[i - 1].id_.is_internal()) {

View File

@ -596,6 +596,7 @@ void Session::on_container_sent(uint64 container_id, vector<uint64> msg_ids) {
void Session::on_message_ack(uint64 id) {
on_message_ack_impl(id, 1);
}
void Session::on_message_ack_impl(uint64 id, int32 type) {
auto cit = sent_containers_.find(id);
if (cit != sent_containers_.end()) {
@ -643,6 +644,7 @@ void Session::dec_container(uint64 message_id, Query *query) {
sent_containers_.erase(it);
}
}
void Session::cleanup_container(uint64 message_id, Query *query) {
if (query->container_id == message_id) {
// message was sent without any container
@ -684,8 +686,6 @@ void Session::mark_as_unknown(uint64 id, Query *query) {
}
Status Session::on_message_result_ok(uint64 id, BufferSlice packet, size_t original_size) {
// Steal authorization information.
// It is a dirty hack, yep.
if (id == 0) {
if (is_cdn_) {
return Status::Error("Got update from CDN connection");
@ -718,6 +718,8 @@ Status Session::on_message_result_ok(uint64 id, BufferSlice packet, size_t origi
VLOG(net_query) << "Return query result " << query_ptr->query;
if (!parser.get_error()) {
// Steal authorization information.
// It is a dirty hack, yep.
if (ID == telegram_api::auth_authorization::ID || ID == telegram_api::auth_loginTokenSuccess::ID) {
if (query_ptr->query->tl_constructor() != telegram_api::auth_importAuthorization::ID) {
G()->net_query_dispatcher().set_main_dc_id(raw_dc_id_);
@ -766,8 +768,13 @@ void Session::on_message_result_error(uint64 id, int error_code, BufferSlice mes
return;
}
LOG(DEBUG) << "Session::on_message_result_error " << tag("id", id) << tag("error_code", error_code)
<< tag("msg", message.as_slice());
if (error_code < 0) {
LOG(WARNING) << "Session::on_message_result_error from mtproto " << tag("id", id) << tag("error_code", error_code)
<< tag("msg", message.as_slice());
} else {
LOG(DEBUG) << "Session::on_message_result_error " << tag("id", id) << tag("error_code", error_code)
<< tag("msg", message.as_slice());
}
auto it = sent_queries_.find(id);
if (it == sent_queries_.end()) {
return;
@ -874,6 +881,7 @@ void Session::on_message_info(uint64 id, int32 state, uint64 answer_id, int32 an
current_info_->connection->resend_answer(answer_id);
}
}
Status Session::on_destroy_auth_key() {
auth_data_.drop_main_auth_key();
on_auth_key_updated();
@ -1101,6 +1109,7 @@ void Session::connection_close(ConnectionInfo *info) {
info->connection->force_close(static_cast<mtproto::SessionConnection::Callback *>(this));
CHECK(info->state == ConnectionInfo::State::Empty);
}
bool Session::need_send_check_main_key() const {
return need_check_main_key_ && auth_data_.get_main_auth_key().id() != being_checked_main_auth_key_id_;
}
@ -1130,6 +1139,7 @@ bool Session::need_send_bind_key() const {
return auth_data_.use_pfs() && !auth_data_.get_bind_flag() &&
auth_data_.get_tmp_auth_key().id() != being_binded_tmp_auth_key_id_;
}
bool Session::need_send_query() const {
return !close_flag_ && !need_check_main_key_ && (!auth_data_.use_pfs() || auth_data_.get_bind_flag()) &&
!pending_queries_.empty() && !can_destroy_auth_key();

View File

@ -138,6 +138,10 @@ void SessionProxy::update_main_flag(bool is_main) {
}
void SessionProxy::update_destroy(bool need_destroy) {
if (need_destroy_ == need_destroy) {
LOG(INFO) << "Ignore reduntant update_destroy(" << need_destroy << ")";
return;
}
need_destroy_ = need_destroy;
close_session();
open_session();

View File

@ -51,6 +51,12 @@ class LazySchedulerLocalStorage {
create_func_ = create_func;
}
void set(T &&t) {
auto &optional_value_ = sls_optional_value_.get();
CHECK(!optional_value_);
optional_value_ = std::move(t);
}
T &get() {
auto &optional_value_ = sls_optional_value_.get();
if (!optional_value_) {

View File

@ -22,6 +22,7 @@
#include "td/utils/Time.h"
#include <functional>
#include <iterator>
#include <utility>
namespace td {
@ -285,7 +286,7 @@ void Scheduler::do_event(ActorInfo *actor_info, Event &&event) {
UNREACHABLE();
break;
}
// can't clear event here. It may be already destroyed during destory_actor
// can't clear event here. It may be already destroyed during destroy_actor
}
void Scheduler::register_migrated_actor(ActorInfo *actor_info) {
@ -302,8 +303,8 @@ void Scheduler::register_migrated_actor(ActorInfo *actor_info) {
}
auto it = pending_events_.find(actor_info);
if (it != pending_events_.end()) {
actor_info->mailbox_.insert(actor_info->mailbox_.end(), make_move_iterator(begin(it->second)),
make_move_iterator(end(it->second)));
actor_info->mailbox_.insert(actor_info->mailbox_.end(), std::make_move_iterator(it->second.begin()),
std::make_move_iterator(it->second.end()));
pending_events_.erase(it);
}
if (actor_info->mailbox_.empty()) {

View File

@ -165,10 +165,10 @@ void Scheduler::flush_mailbox(ActorInfo *actor_info, const RunFuncT &run_func, c
if (guard.can_run()) {
(*run_func)(actor_info);
} else {
mailbox.insert(begin(mailbox) + i, (*event_func)());
mailbox.insert(mailbox.begin() + i, (*event_func)());
}
}
mailbox.erase(begin(mailbox), begin(mailbox) + i);
mailbox.erase(mailbox.begin(), mailbox.begin() + i);
}
inline void Scheduler::send_to_scheduler(int32 sched_id, const ActorId<> &actor_id, Event &&event) {

View File

@ -13,9 +13,10 @@
namespace td {
SqliteConnectionSafe::SqliteConnectionSafe(string path, DbKey key)
: path_(std::move(path)), lsls_connection_([path = path_, key = std::move(key)] {
auto r_db = SqliteDb::open_with_key(path, key);
SqliteConnectionSafe::SqliteConnectionSafe(string path, DbKey key, optional<int32> cipher_version)
: path_(std::move(path))
, lsls_connection_([path = path_, key = std::move(key), cipher_version = std::move(cipher_version)] {
auto r_db = SqliteDb::open_with_key(path, key, cipher_version.copy());
if (r_db.is_error()) {
auto r_stat = stat(path);
if (r_stat.is_error()) {
@ -33,6 +34,10 @@ SqliteConnectionSafe::SqliteConnectionSafe(string path, DbKey key)
}) {
}
void SqliteConnectionSafe::set(SqliteDb &&db) {
lsls_connection_.set(std::move(db));
}
SqliteDb &SqliteConnectionSafe::get() {
return lsls_connection_.get();
}

View File

@ -12,15 +12,17 @@
#include "td/db/SqliteDb.h"
#include "td/utils/common.h"
#include "td/utils/optional.h"
namespace td {
class SqliteConnectionSafe {
public:
SqliteConnectionSafe() = default;
explicit SqliteConnectionSafe(string path, DbKey key = DbKey::empty());
explicit SqliteConnectionSafe(string path, DbKey key = DbKey::empty(), optional<int32> cipher_version = {});
SqliteDb &get();
void set(SqliteDb &&db);
void close();

View File

@ -19,30 +19,7 @@
namespace td {
namespace {
string db_key_to_sqlcipher_key(const DbKey &db_key) {
if (db_key.is_empty()) {
return "''";
}
if (db_key.is_password()) {
return PSTRING() << "'" << db_key.data().str() << "'";
}
CHECK(db_key.is_raw_key());
Slice raw_key = db_key.data();
CHECK(raw_key.size() == 32);
size_t expected_size = 64 + 5;
string res(expected_size + 50, ' ');
StringBuilder sb(res);
sb << '"';
sb << 'x';
sb << '\'';
sb << format::as_hex_dump<0>(raw_key);
sb << '\'';
sb << '"';
CHECK(!sb.is_error());
CHECK(sb.as_cslice().size() == expected_size);
res.resize(expected_size);
return res;
}
} // namespace
SqliteDb::~SqliteDb() = default;
@ -134,6 +111,15 @@ Result<string> SqliteDb::get_pragma(Slice name) {
CHECK(!stmt.can_step());
return std::move(res);
}
Result<string> SqliteDb::get_pragma_string(Slice name) {
TRY_RESULT(stmt, get_statement(PSLICE() << "PRAGMA " << name));
TRY_STATUS(stmt.step());
CHECK(stmt.has_row());
auto res = stmt.view_string(0).str();
TRY_STATUS(stmt.step());
CHECK(!stmt.can_step());
return std::move(res);
}
Result<int32> SqliteDb::user_version() {
TRY_RESULT(get_version_stmt, get_statement("PRAGMA user_version"));
@ -167,14 +153,30 @@ Status SqliteDb::check_encryption() {
return Status::OK();
}
Result<SqliteDb> SqliteDb::open_with_key(CSlice path, const DbKey &db_key) {
Result<SqliteDb> SqliteDb::open_with_key(CSlice path, const DbKey &db_key, optional<int32> cipher_version) {
auto res = do_open_with_key(path, db_key, cipher_version ? cipher_version.value() : 0);
if (res.is_error() && !cipher_version) {
return do_open_with_key(path, db_key, 3);
}
return res;
}
Result<SqliteDb> SqliteDb::do_open_with_key(CSlice path, const DbKey &db_key, int32 cipher_version) {
SqliteDb db;
TRY_STATUS(db.init(path));
return std::move(db);
}
Status SqliteDb::change_key(CSlice path, const DbKey &new_db_key, const DbKey &old_db_key) {
return Status::OK();
void SqliteDb::set_cipher_version(int32 cipher_version) {
}
optional<int32> SqliteDb::get_cipher_version() const {
return optional<int32>{3};
}
Result<SqliteDb> SqliteDb::change_key(CSlice path, const DbKey &new_db_key, const DbKey &old_db_key) {
SqliteDb db;
TRY_STATUS(db.init(path));
return std::move(db);
}
Status SqliteDb::destroy(Slice path) {

View File

@ -12,6 +12,7 @@
#include "td/db/detail/RawSqliteDb.h"
#include "td/utils/logging.h"
#include "td/utils/optional.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
@ -50,6 +51,7 @@ class SqliteDb {
Status exec(CSlice cmd) TD_WARN_UNUSED_RESULT;
Result<bool> has_table(Slice table);
Result<string> get_pragma(Slice name);
Result<string> get_pragma_string(Slice name);
Status begin_transaction() TD_WARN_UNUSED_RESULT;
Status commit_transaction() TD_WARN_UNUSED_RESULT;
@ -60,8 +62,8 @@ class SqliteDb {
static Status destroy(Slice path) TD_WARN_UNUSED_RESULT;
// Anyway we can't change the key on the fly, so having static functions is more than enough
static Result<SqliteDb> open_with_key(CSlice path, const DbKey &db_key);
static Status change_key(CSlice path, const DbKey &new_db_key, const DbKey &old_db_key);
static Result<SqliteDb> open_with_key(CSlice path, const DbKey &db_key, optional<int32> cipher_version = {});
static Result<SqliteDb> change_key(CSlice path, const DbKey &new_db_key, const DbKey &old_db_key);
Status last_error();
@ -76,6 +78,8 @@ class SqliteDb {
detail::RawSqliteDb::with_db_path(main_path, f);
}
optional<int32> get_cipher_version() const;
private:
explicit SqliteDb(std::shared_ptr<detail::RawSqliteDb> raw) : raw_(std::move(raw)) {
}
@ -83,6 +87,8 @@ class SqliteDb {
bool enable_logging_ = false;
Status check_encryption();
static Result<SqliteDb> do_open_with_key(CSlice path, const DbKey &db_key, int32 cipher_version);
void set_cipher_version(int32 cipher_version);
};
} // namespace td

View File

@ -12,15 +12,13 @@
#include "td/db/binlog/BinlogInterface.h"
#include "td/utils/misc.h"
#include "td/utils/port/Clocks.h"
#include "td/utils/Random.h"
#include "td/utils/StorerBase.h"
#include "td/utils/Time.h"
#include "td/utils/tl_helpers.h"
#include "td/utils/tl_parsers.h"
#include "td/utils/tl_storers.h"
#include <map>
#include <set>
#include <unordered_map>
namespace td {
@ -102,7 +100,8 @@ class TQueueImpl : public TQueue {
return false;
}
auto &q = queues_[queue_id];
if (q.events.size() >= MAX_QUEUE_EVENTS || q.total_event_length > MAX_TOTAL_EVENT_LENGTH - raw_event.data.size()) {
if (q.events.size() >= MAX_QUEUE_EVENTS || q.total_event_length > MAX_TOTAL_EVENT_LENGTH - raw_event.data.size() ||
raw_event.expires_at <= 0) {
return false;
}
auto event_id = raw_event.event_id;
@ -120,6 +119,9 @@ class TQueueImpl : public TQueue {
q.events.erase(it);
}
}
if (q.events.empty() && !raw_event.data.empty()) {
schedule_queue_gc(queue_id, q, raw_event.expires_at);
}
if (raw_event.logevent_id == 0 && callback_ != nullptr) {
raw_event.logevent_id = callback_->push(queue_id, raw_event);
@ -130,7 +132,7 @@ class TQueueImpl : public TQueue {
return true;
}
Result<EventId> push(QueueId queue_id, string data, double expires_at, int64 extra, EventId hint_new_id) override {
Result<EventId> push(QueueId queue_id, string data, int32 expires_at, int64 extra, EventId hint_new_id) override {
if (data.empty()) {
return Status::Error("Data is empty");
}
@ -145,6 +147,9 @@ class TQueueImpl : public TQueue {
if (q.total_event_length > MAX_TOTAL_EVENT_LENGTH - data.size()) {
return Status::Error("Queue size is too big");
}
if (expires_at <= 0) {
return Status::Error("Failed to add already expired event");
}
EventId event_id;
while (true) {
if (q.tail_id.empty()) {
@ -210,7 +215,7 @@ class TQueueImpl : public TQueue {
pop(q, queue_id, it, q.tail_id);
}
Result<size_t> get(QueueId queue_id, EventId from_id, bool forget_previous, double now,
Result<size_t> get(QueueId queue_id, EventId from_id, bool forget_previous, int32 unix_time_now,
MutableSpan<Event> &result_events) override {
auto it = queues_.find(queue_id);
if (it == queues_.end()) {
@ -226,35 +231,40 @@ class TQueueImpl : public TQueue {
return Status::Error("Specified from_id is in the past");
}
return do_get(queue_id, q, from_id, forget_previous, now, result_events);
do_get(queue_id, q, from_id, forget_previous, unix_time_now, result_events);
return get_size(q);
}
std::pair<uint64, uint64> run_gc(double now) override {
uint64 total_deleted_events = 0;
uint64 deleted_queues = 0;
for (auto queue_it = queues_.begin(); queue_it != queues_.end();) {
size_t deleted_events = 0;
for (auto it = queue_it->second.events.begin(); it != queue_it->second.events.end();) {
auto &e = it->second;
if (e.expires_at < now) {
if (!it->second.data.empty()) {
deleted_events++;
}
pop(queue_it->second, queue_it->first, it,
e.expires_at < now - 7 * 86400 ? EventId() : queue_it->second.tail_id);
} else {
++it;
int64 run_gc(int32 unix_time_now) override {
int64 deleted_events = 0;
while (!queue_gc_at_.empty()) {
auto it = queue_gc_at_.begin();
if (it->first >= unix_time_now) {
break;
}
auto queue_id = it->second;
auto &q = queues_[queue_id];
CHECK(q.gc_at == it->first);
int32 new_gc_at = 0;
if (!q.events.empty()) {
auto head_id = q.events.begin()->first;
Event event;
MutableSpan<Event> span{&event, 1};
size_t size_before = get_size(q);
do_get(queue_id, q, head_id, false, unix_time_now, span);
size_t size_after = get_size(q);
CHECK(size_after <= size_before);
deleted_events += size_before - size_after;
if (!span.empty()) {
CHECK(!event.data.empty());
new_gc_at = event.expires_at;
CHECK(new_gc_at >= unix_time_now);
}
}
if (callback_ != nullptr && queue_it->second.events.empty()) {
deleted_queues++;
queue_it = queues_.erase(queue_it);
} else {
++queue_it;
}
total_deleted_events += deleted_events;
schedule_queue_gc(queue_id, q, new_gc_at);
}
return {deleted_queues, total_deleted_events};
return deleted_events;
}
size_t get_size(QueueId queue_id) override {
@ -262,12 +272,7 @@ class TQueueImpl : public TQueue {
if (it == queues_.end()) {
return 0;
}
auto &q = it->second;
if (q.events.empty()) {
return 0;
}
return q.events.size() - (q.events.rbegin()->second.data.empty() ? 1 : 0);
return get_size(it->second);
}
void close(Promise<> promise) override {
@ -282,11 +287,21 @@ class TQueueImpl : public TQueue {
EventId tail_id;
std::map<EventId, RawEvent> events;
size_t total_event_length = 0;
int32 gc_at = 0;
};
std::unordered_map<QueueId, Queue> queues_;
std::set<std::pair<int32, QueueId>> queue_gc_at_;
unique_ptr<StorageCallback> callback_;
static size_t get_size(Queue &q) {
if (q.events.empty()) {
return 0;
}
return q.events.size() - (q.events.rbegin()->second.data.empty() ? 1 : 0);
}
void pop(Queue &q, QueueId queue_id, std::map<EventId, RawEvent>::iterator &it, EventId tail_id) {
auto &event = it->second;
if (callback_ == nullptr || event.logevent_id == 0) {
@ -316,8 +331,8 @@ class TQueueImpl : public TQueue {
event.data = {};
}
size_t do_get(QueueId queue_id, Queue &q, EventId from_id, bool forget_previous, double now,
MutableSpan<Event> &result_events) {
void do_get(QueueId queue_id, Queue &q, EventId from_id, bool forget_previous, int32 unix_time_now,
MutableSpan<Event> &result_events) {
if (forget_previous) {
for (auto it = q.events.begin(); it != q.events.end() && it->first < from_id;) {
pop(q, queue_id, it, q.tail_id);
@ -327,7 +342,7 @@ class TQueueImpl : public TQueue {
size_t ready_n = 0;
for (auto it = q.events.lower_bound(from_id); it != q.events.end();) {
auto &event = it->second;
if (event.expires_at < now || event.data.empty()) {
if (event.expires_at < unix_time_now || event.data.empty()) {
pop(q, queue_id, it, q.tail_id);
} else {
CHECK(!(event.event_id < from_id));
@ -346,7 +361,18 @@ class TQueueImpl : public TQueue {
}
result_events.truncate(ready_n);
return get_size(queue_id);
}
void schedule_queue_gc(QueueId queue_id, Queue &q, int32 gc_at) {
if (q.gc_at != 0) {
bool is_deleted = queue_gc_at_.erase({q.gc_at, queue_id});
CHECK(is_deleted);
}
q.gc_at = gc_at;
if (q.gc_at != 0) {
bool is_inserted = queue_gc_at_.emplace(gc_at, queue_id).second;
CHECK(is_inserted);
}
}
};
@ -400,20 +426,15 @@ struct TQueueLogEvent : public Storer {
}
};
template <class BinlogT>
TQueueBinlog<BinlogT>::TQueueBinlog() {
diff_ = Clocks::system() - Time::now();
}
template <class BinlogT>
uint64 TQueueBinlog<BinlogT>::push(QueueId queue_id, const RawEvent &event) {
TQueueLogEvent log_event;
log_event.queue_id = queue_id;
log_event.event_id = event.event_id.value();
log_event.expires_at = static_cast<int32>(event.expires_at + diff_ + 1);
log_event.expires_at = event.expires_at;
log_event.data = event.data;
log_event.extra = event.extra;
auto magic = magic_ + (log_event.extra != 0);
auto magic = BINLOG_EVENT_TYPE + (log_event.extra != 0);
if (event.logevent_id == 0) {
return binlog_->add(magic, log_event);
}
@ -430,7 +451,7 @@ template <class BinlogT>
Status TQueueBinlog<BinlogT>::replay(const BinlogEvent &binlog_event, TQueue &q) const {
TQueueLogEvent event;
TlParser parser(binlog_event.data_);
int32 has_extra = binlog_event.type_ - magic_;
int32 has_extra = binlog_event.type_ - BINLOG_EVENT_TYPE;
if (has_extra != 0 && has_extra != 1) {
return Status::Error("Wrong magic");
}
@ -441,7 +462,7 @@ Status TQueueBinlog<BinlogT>::replay(const BinlogEvent &binlog_event, TQueue &q)
RawEvent raw_event;
raw_event.logevent_id = binlog_event.id_;
raw_event.event_id = event_id;
raw_event.expires_at = event.expires_at - diff_;
raw_event.expires_at = event.expires_at;
raw_event.data = event.data.str();
raw_event.extra = event.extra;
if (!q.do_push(event.queue_id, std::move(raw_event))) {
@ -477,6 +498,7 @@ void TQueueMemoryStorage::replay(TQueue &q) const {
}
}
void TQueueMemoryStorage::close(Promise<> promise) {
events_.clear();
promise.set_value({});
}

View File

@ -56,7 +56,7 @@ class TQueue {
EventId id;
Slice data;
int64 extra{0};
double expires_at{0};
int32 expires_at{0};
};
struct RawEvent {
@ -64,7 +64,7 @@ class TQueue {
EventId event_id;
string data;
int64 extra{0};
double expires_at{0};
int32 expires_at{0};
};
using QueueId = int64;
@ -101,19 +101,19 @@ class TQueue {
virtual bool do_push(QueueId queue_id, RawEvent &&raw_event) = 0;
virtual Result<EventId> push(QueueId queue_id, string data, double expires_at, int64 extra, EventId hint_new_id) = 0;
virtual Result<EventId> push(QueueId queue_id, string data, int32 expires_at, int64 extra, EventId hint_new_id) = 0;
virtual void forget(QueueId queue_id, EventId event_id) = 0;
virtual EventId get_head(QueueId queue_id) const = 0;
virtual EventId get_tail(QueueId queue_id) const = 0;
virtual Result<size_t> get(QueueId queue_id, EventId from_id, bool forget_previous, double now,
virtual Result<size_t> get(QueueId queue_id, EventId from_id, bool forget_previous, int32 unix_time_now,
MutableSpan<Event> &result_events) = 0;
virtual size_t get_size(QueueId queue_id) = 0;
virtual std::pair<uint64, uint64> run_gc(double now) = 0;
virtual int64 run_gc(int32 unix_time_now) = 0;
virtual void close(Promise<> promise) = 0;
};
@ -124,8 +124,6 @@ struct BinlogEvent;
template <class BinlogT>
class TQueueBinlog : public TQueue::StorageCallback {
public:
TQueueBinlog();
uint64 push(QueueId queue_id, const RawEvent &event) override;
void pop(uint64 logevent_id) override;
Status replay(const BinlogEvent &binlog_event, TQueue &q) const TD_WARN_UNUSED_RESULT;
@ -137,8 +135,7 @@ class TQueueBinlog : public TQueue::StorageCallback {
private:
std::shared_ptr<BinlogT> binlog_;
int32 magic_{2314};
double diff_{0};
static constexpr int32 BINLOG_EVENT_TYPE = 2314;
};
class TQueueMemoryStorage : public TQueue::StorageCallback {

View File

@ -647,6 +647,7 @@ void Binlog::do_reindex() {
fd_events_ = 0;
reset_encryption();
processor_->for_each([&](BinlogEvent &event) {
event.realloc();
do_event(std::move(event)); // NB: no move is actually happens
});
need_sync_ = true; // must sync creation of the file
@ -667,9 +668,16 @@ void Binlog::do_reindex() {
<< fd_size_ << ' ' << detail::file_size(path_) << ' ' << fd_events_ << ' ' << path_;
double ratio = static_cast<double>(start_size) / static_cast<double>(finish_size + 1);
LOG(INFO) << "Regenerate index " << tag("name", path_) << tag("time", format::as_time(finish_time - start_time))
<< tag("before_size", format::as_size(start_size)) << tag("after_size", format::as_size(finish_size))
<< tag("ratio", ratio) << tag("before_events", start_events) << tag("after_events", finish_events);
[&](Slice msg) {
if (start_size > (10 << 20) || finish_time - start_time > 1) {
LOG(WARNING) << "Slow " << msg;
} else {
LOG(INFO) << msg;
}
}(PSLICE() << "Regenerate index " << tag("name", path_) << tag("time", format::as_time(finish_time - start_time))
<< tag("before_size", format::as_size(start_size)) << tag("after_size", format::as_size(finish_size))
<< tag("ratio", ratio) << tag("before_events", start_events) << tag("after_events", finish_events));
buffer_writer_ = ChainBufferWriter();
buffer_reader_ = buffer_writer_.extract_reader();

View File

@ -70,4 +70,11 @@ BufferSlice BinlogEvent::create_raw(uint64 id, int32 type, int32 flags, const St
return raw_event;
}
void BinlogEvent::realloc() {
auto data_offset = data_.begin() - raw_event_.as_slice().begin();
auto data_size = data_.size();
raw_event_ = raw_event_.copy();
data_ = raw_event_.as_slice().substr(data_offset, data_size);
}
} // namespace td

View File

@ -108,6 +108,8 @@ struct BinlogEvent {
}
Status validate() const;
void realloc();
};
inline StringBuilder &operator<<(StringBuilder &sb, const BinlogEvent &event) {

View File

@ -7,6 +7,7 @@
#pragma once
#include "td/utils/logging.h"
#include "td/utils/optional.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
@ -56,10 +57,19 @@ class RawSqliteDb {
return begin_cnt_ == 0;
}
void set_cipher_version(int32 cipher_version) {
cipher_version_ = cipher_version;
}
optional<int32> get_cipher_version() const {
return cipher_version_.copy();
}
private:
sqlite3 *db_;
std::string path_;
size_t begin_cnt_{0};
optional<int32> cipher_version_;
};
} // namespace detail

View File

@ -74,7 +74,7 @@ bool HttpChunkedByteFlow::loop() {
state_ = State::ReadChunkLength;
len_ = 0;
}
} while (0);
} while (false);
if (!is_input_active_ && !result) {
finish(Status::Error("Unexpected end of stream"));
}

View File

@ -190,5 +190,13 @@ void HttpConnectionBase::loop() {
}
}
void HttpConnectionBase::on_start_migrate(int32 sched_id) {
Scheduler::unsubscribe(fd_.get_poll_info().get_pollable_fd_ref());
}
void HttpConnectionBase::on_finish_migrate() {
Scheduler::subscribe(fd_.get_poll_info().extract_pollable_fd(this));
}
} // namespace detail
} // namespace td

View File

@ -66,6 +66,9 @@ class HttpConnectionBase : public Actor {
void timeout_expired() override;
void loop() override;
void on_start_migrate(int32 sched_id) override;
void on_finish_migrate() override;
virtual void on_query(unique_ptr<HttpQuery> query) = 0;
virtual void on_error(Status error) = 0;
};

View File

@ -28,7 +28,7 @@ class ThreadSafeMultiCounter {
int64 sum(size_t index) const {
CHECK(index < N);
int64 res = 0;
tls_.for_each([&res](auto &value) { res += value[index].load(std::memory_order_relaxed); });
tls_.for_each([&res, &index](auto &value) { res += value[index].load(std::memory_order_relaxed); });
return res;
}
void clear() {

View File

@ -7,6 +7,7 @@
#include "td/utils/buffer.h"
#include "td/utils/port/thread_local.h"
#include "td/utils/ThreadSafeCounter.h"
#include <cstddef>
#include <new>
@ -24,6 +25,20 @@ TD_THREAD_LOCAL BufferAllocator::BufferRawTls *BufferAllocator::buffer_raw_tls;
std::atomic<size_t> BufferAllocator::buffer_mem;
static ThreadSafeCounter buffer_slice_size_;
int64 BufferAllocator::get_buffer_slice_size() {
return buffer_slice_size_.sum();
}
void BufferAllocator::track_buffer_slice(int64 size) {
if (size == 0) {
return;
}
buffer_slice_size_.add(size);
}
size_t BufferAllocator::get_buffer_mem() {
return buffer_mem;
}

View File

@ -67,10 +67,15 @@ class BufferAllocator {
static ReaderPtr create_reader(const ReaderPtr &raw);
static size_t get_buffer_mem();
static int64 get_buffer_slice_size();
static void clear_thread_local();
private:
friend class BufferSlice;
static void track_buffer_slice(int64 size);
static ReaderPtr create_reader_fast(size_t size);
static WriterPtr create_writer_exact(size_t size);
@ -104,16 +109,34 @@ class BufferSlice {
return;
}
begin_ = buffer_->begin_;
end_ = begin_;
sync_with_writer();
}
BufferSlice(BufferReaderPtr buffer_ptr, size_t begin, size_t end)
: buffer_(std::move(buffer_ptr)), begin_(begin), end_(end) {
debug_track();
}
BufferSlice(const BufferSlice &other) = delete;
BufferSlice &operator=(const BufferSlice &other) = delete;
BufferSlice(BufferSlice &&other) : BufferSlice(std::move(other.buffer_), other.begin_, other.end_) {
debug_untrack(); // yes, debug_untrack
}
BufferSlice &operator=(BufferSlice &&other) {
if (this == &other) {
return *this;
}
debug_untrack();
buffer_ = std::move(other.buffer_);
begin_ = other.begin_;
end_ = other.end_;
return *this;
}
explicit BufferSlice(size_t size) : buffer_(BufferAllocator::create_reader(size)) {
end_ = buffer_->end_.load(std::memory_order_relaxed);
begin_ = end_ - ((size + 7) & -8);
end_ = begin_ + size;
debug_track();
}
explicit BufferSlice(Slice slice) : BufferSlice(slice.size()) {
@ -123,6 +146,17 @@ class BufferSlice {
BufferSlice(const char *ptr, size_t size) : BufferSlice(Slice(ptr, size)) {
}
~BufferSlice() {
debug_untrack();
}
void debug_track() const {
BufferAllocator::track_buffer_slice(static_cast<int64>(size()));
}
void debug_untrack() const {
BufferAllocator::track_buffer_slice(-static_cast<int64>(size()));
}
BufferSlice clone() const {
if (is_null()) {
return BufferSlice(BufferReaderPtr(), begin_, end_);
@ -166,21 +200,27 @@ class BufferSlice {
}
bool confirm_read(size_t size) {
debug_untrack();
begin_ += size;
CHECK(begin_ <= end_);
debug_track();
return begin_ == end_;
}
void truncate(size_t limit) {
if (size() > limit) {
debug_untrack();
end_ = begin_ + limit;
debug_track();
}
}
BufferSlice from_slice(Slice slice) const {
auto res = BufferSlice(BufferAllocator::create_reader(buffer_));
res.debug_untrack();
res.begin_ = static_cast<size_t>(slice.ubegin() - buffer_->data_);
res.end_ = static_cast<size_t>(slice.uend() - buffer_->data_);
res.debug_track();
CHECK(buffer_->begin_ <= res.begin_);
CHECK(res.begin_ <= res.end_);
CHECK(res.end_ <= buffer_->end_.load(std::memory_order_relaxed));
@ -220,9 +260,11 @@ class BufferSlice {
// set end_ into writer's end_
size_t sync_with_writer() {
debug_untrack();
CHECK(!is_null());
auto old_end = end_;
end_ = buffer_->end_.load(std::memory_order_acquire);
debug_track();
return end_ - old_end;
}
bool is_writer_alive() const {
@ -230,6 +272,7 @@ class BufferSlice {
return buffer_->has_writer_.load(std::memory_order_acquire);
}
void clear() {
debug_untrack();
begin_ = 0;
end_ = 0;
buffer_ = nullptr;

View File

@ -6,13 +6,48 @@
//
#include "td/utils/port/Clocks.h"
#include "td/utils/port/platform.h"
#include <chrono>
#include <ctime>
#if TD_PORT_POSIX
#include <time.h>
#endif
namespace td {
double Clocks::monotonic() {
// TODO write system specific functions, because std::chrono::steady_clock is steady only under Windows
#if TD_PORT_POSIX
// use system specific functions, because std::chrono::steady_clock is steady only under Windows
#ifdef CLOCK_BOOTTIME
{
static bool skip = [] {
struct timespec spec;
return clock_gettime(CLOCK_BOOTTIME, &spec) != 0;
}();
struct timespec spec;
if (!skip && clock_gettime(CLOCK_BOOTTIME, &spec) == 0) {
return static_cast<double>(spec.tv_nsec) * 1e-9 + static_cast<double>(spec.tv_sec);
}
}
#endif
#ifdef CLOCK_MONOTONIC_RAW
{
static bool skip = [] {
struct timespec spec;
return clock_gettime(CLOCK_MONOTONIC_RAW, &spec) != 0;
}();
struct timespec spec;
if (!skip && clock_gettime(CLOCK_MONOTONIC_RAW, &spec) == 0) {
return static_cast<double>(spec.tv_nsec) * 1e-9 + static_cast<double>(spec.tv_sec);
}
}
#endif
#endif
auto duration = std::chrono::steady_clock::now().time_since_epoch();
return static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count()) * 1e-9;
}

View File

@ -12,6 +12,7 @@ char disable_linker_warning_about_empty_file_event_fd_bsd_cpp TD_UNUSED;
#include "td/utils/logging.h"
#include "td/utils/port/detail/NativeFd.h"
#include "td/utils/port/detail/skip_eintr.h"
#include "td/utils/port/PollFlags.h"
#include "td/utils/port/SocketFd.h"
#include "td/utils/Slice.h"
@ -93,10 +94,14 @@ void EventFdBsd::acquire() {
}
void EventFdBsd::wait(int timeout_ms) {
pollfd fd;
fd.fd = get_poll_info().native_fd().fd();
fd.events = POLLIN;
poll(&fd, 1, timeout_ms);
detail::skip_eintr_timeout(
[this](int timeout_ms) {
pollfd fd;
fd.fd = get_poll_info().native_fd().fd();
fd.events = POLLIN;
return poll(&fd, 1, timeout_ms);
},
timeout_ms);
}
} // namespace detail

View File

@ -117,10 +117,14 @@ void EventFdLinux::acquire() {
}
void EventFdLinux::wait(int timeout_ms) {
pollfd fd;
fd.fd = get_poll_info().native_fd().fd();
fd.events = POLLIN;
poll(&fd, 1, timeout_ms);
detail::skip_eintr_timeout(
[this](int timeout_ms) {
pollfd fd;
fd.fd = get_poll_info().native_fd().fd();
fd.events = POLLIN;
return poll(&fd, 1, timeout_ms);
},
timeout_ms);
}
} // namespace detail

View File

@ -6,8 +6,13 @@
//
#pragma once
#if TD_PORT_POSIX
#include "td/utils/common.h"
#include "td/utils/Time.h"
#include <cerrno>
#include <type_traits>
#endif
namespace td {
@ -33,6 +38,25 @@ auto skip_eintr_cstr(F &&f) {
} while (res == nullptr && errno == EINTR);
return res;
}
template <class F>
auto skip_eintr_timeout(F &&f, int32 timeout_ms) {
decltype(f(timeout_ms)) res;
static_assert(std::is_integral<decltype(res)>::value, "integral type expected");
auto start = Timestamp::now();
auto left_timeout_ms = timeout_ms;
while (true) {
errno = 0; // just in case
res = f(left_timeout_ms);
if (res >= 0 || errno != EINTR) {
break;
}
left_timeout_ms =
td::max(static_cast<int32>((start.at() - Timestamp::now().at()) * 1000 + timeout_ms + 1 - 1e-9), 0);
}
return res;
}
} // namespace detail
#endif

View File

@ -138,13 +138,13 @@ TestsRunner &TestsRunner::get_default() {
return default_runner;
}
void TestsRunner::add_test(string name, unique_ptr<Test> test) {
void TestsRunner::add_test(string name, std::function<unique_ptr<Test>()> test) {
for (auto &it : tests_) {
if (it.first == name) {
LOG(FATAL) << "Test name collision " << name;
}
}
tests_.emplace_back(name, std::move(test));
tests_.emplace_back(name, TestInfo{std::move(test), nullptr});
}
void TestsRunner::add_substr_filter(string str) {
@ -176,7 +176,7 @@ bool TestsRunner::run_all_step() {
while (state_.it != state_.end) {
auto &name = tests_[state_.it].first;
auto test = tests_[state_.it].second.get();
auto &test = tests_[state_.it].second.test;
if (!state_.is_running) {
bool ok = true;
for (const auto &filter : substr_filters_) {
@ -194,12 +194,17 @@ bool TestsRunner::run_all_step() {
state_.start = Time::now();
state_.start_unadjusted = Time::now_unadjusted();
state_.is_running = true;
CHECK(!test);
test = tests_[state_.it].second.creator();
}
if (test->step()) {
break;
}
test = {};
auto passed = Time::now() - state_.start;
auto real_passed = Time::now_unadjusted() - state_.start_unadjusted;
if (real_passed + 1e-1 > passed) {

View File

@ -96,7 +96,7 @@ class TestsRunner : public TestContext {
public:
static TestsRunner &get_default();
void add_test(string name, unique_ptr<Test> test);
void add_test(string name, std::function<unique_ptr<Test>()> test);
void add_substr_filter(string str);
void set_stress_flag(bool flag);
void run_all();
@ -113,7 +113,11 @@ class TestsRunner : public TestContext {
};
bool stress_flag_{false};
vector<string> substr_filters_;
vector<std::pair<string, unique_ptr<Test>>> tests_;
struct TestInfo {
std::function<unique_ptr<Test>()> creator;
unique_ptr<Test> test;
};
vector<std::pair<string, TestInfo>> tests_;
State state_;
unique_ptr<RegressionTester> regression_tester_;
@ -125,7 +129,7 @@ template <class T>
class RegisterTest {
public:
explicit RegisterTest(string name, TestsRunner &runner = TestsRunner::get_default()) {
runner.add_test(name, make_unique<T>());
runner.add_test(name, [] { return make_unique<T>(); });
}
};

View File

@ -7,15 +7,21 @@
#include "td/utils/common.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/port/EventFd.h"
#include "td/utils/port/FileFd.h"
#include "td/utils/port/IoSlice.h"
#include "td/utils/port/path.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/sleep.h"
#include "td/utils/port/thread.h"
#include "td/utils/port/thread_local.h"
#include "td/utils/Random.h"
#include "td/utils/ScopeGuard.h"
#include "td/utils/Slice.h"
#include "td/utils/tests.h"
#include "td/utils/Time.h"
#include <atomic>
#include <set>
using namespace td;
@ -155,9 +161,12 @@ static void on_user_signal(int sig) {
ptrs.push_back(std::string(ptr));
}
TEST(Post, SignalsAndThread) {
TEST(Port, SignalsAndThread) {
setup_signals_alt_stack().ensure();
set_signal_handler(SignalType::User, on_user_signal).ensure();
SCOPE_EXIT {
set_signal_handler(SignalType::User, nullptr).ensure();
};
std::vector<std::string> ans = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
{
std::vector<td::thread> threads;
@ -212,4 +221,43 @@ TEST(Post, SignalsAndThread) {
//LOG(ERROR) << addrs;
}
}
TEST(Port, EventFdAndSignals) {
set_signal_handler(SignalType::User, [](int signal) {}).ensure();
SCOPE_EXIT {
set_signal_handler(SignalType::User, nullptr).ensure();
};
std::atomic_flag flag;
flag.test_and_set();
auto main_thread = pthread_self();
td::thread interrupt_thread{[&flag, &main_thread] {
setup_signals_alt_stack().ensure();
while (flag.test_and_set()) {
pthread_kill(main_thread, SIGUSR1);
td::usleep_for(1000 * td::Random::fast(1, 10)); // 0.001s - 0.01s
}
}};
for (int timeout_ms : {0, 1, 2, 10, 100, 500}) {
double min_diff = 10000000;
double max_diff = 0;
for (int t = 0; t < max(5, 1000 / td::max(timeout_ms, 1)); t++) {
td::EventFd event_fd;
event_fd.init();
auto start = td::Timestamp::now();
event_fd.wait(timeout_ms);
auto end = td::Timestamp::now();
auto passed = end.at() - start.at();
auto diff = passed * 1000 - timeout_ms;
min_diff = td::min(min_diff, diff);
max_diff = td::max(max_diff, diff);
}
LOG_CHECK(min_diff >= 0) << min_diff;
LOG_CHECK(max_diff < 10) << max_diff;
LOG(INFO) << min_diff << " " << max_diff;
}
flag.clear();
}
#endif

View File

@ -5,7 +5,9 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "data.h"
namespace td {
static const char thumbnail_arr[] =
"_9j_4AAQSkZJRgABAQEASABIAAD_2wBDAAICAgICAQICAgIDAgIDAwYEAwMDAwcFBQQGCAcJCAgHCAgJCg0LCQoMCggICw8LDA0ODg8OCQsQERAOEQ"
"0ODg7_2wBDAQIDAwMDAwcEBAcOCQgJDg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg7_wAARCAAyADIDASIA"
@ -66,4 +68,94 @@ static const char gzip_bomb_arr[] =
"TLGznukoHjpzn3qgqJTV2ogJXaK6ctqTgxKUoPyfUeqmx4szeRJuj3josnbUu0O57kcXXX-bi25IozxSONDzF5jalI4";
const char *gzip_bomb = gzip_bomb_arr;
const size_t gzip_bomb_size = sizeof(gzip_bomb_arr) - 1;
static const char sqlite_sample_db_arr[] =
"olFZ1MdfY0Abj+LtR9ft6DTZgEHW7/"
"z7yAhC07NKr7pBAHWkbQyMPtyVSIW7PLdVaQIHYwLgd7ovQSzD7eTINxZh6Nxpwa8HTynvjhHIdQhtysRL9m3mTEj4mbjU48zq+jcFdsnzG+"
"GJAzk5MQRCi+NyDWGYnBoPhiiPc4QBoFgKoYGIhQwfVci5kf2fYIQrCM1H7QQZ8RHoqCuQ3IjMpZjt/Gzqy+P8kn2PXKWHG8/y5eDc5nQCk/"
"XhkY7A9Wl7ZUsgK7mkA1O1VHp9X0Kz/WCuWhsULuUSeshXmJ1zKciUmTMhS3T7/"
"mc2jVrR00SyT22XwpL6dRwaNtUXVJKJwtzxrTHTxWq33KdxKXFlMr5ffbWsOfpkEHlpeKybJF70bzOgKUF5pmCHOll+3gfZcJOVFI4DvHFSnt/"
"Y3XlhJDrHliXeXcfsSUNzpBsBO+/+O/MMGLi2m/kJ9GHXGpieJsHPSQG1RMNqe84QIymLEwnGptg/"
"I+gw6xqFsUqBo2Z3Hllgz0t9GqvI1ENZr16nwf9hUGMEpj2pdKGR+eSSHMac3BJaiGgoKE7BfUjaaXzI5a8FfZTyl+"
"JUMf3ou2YBuO9fiuR1AhpAyydLSAn93OdbIF+VUHea8944nyUQB2k6idA9zfOFOVPZlaWC8/KxJeLDIAYYv3s+aK3kz/"
"EyU4SSRvDLXhMdSrkNaGM4zbYc/8r4WJSAIgFq5yg3jidRq0xJ3eb+BHs6pCTz3ql50BtPd2ngzz2y51kiW2xVIP3K/"
"hI53loi9UWTIYQPxtWl8RBWD2J1rbMsG0c8CbCQAo3u0SJ2A+4gQ2q5ZRPl9rp0IEgHwhg1xtjZhz7Ss2X7HO9Bfb/"
"ioe6ZlRPPhLR5AueL6YjretqfCs0C6Y3D7Ax6ho3vae5a2HCzasqgD42OSn6YwSq4d85AurIf4GhGykmQnkHPiblLSi9LE8w59B1a9IQgrdnVHqto3"
"IYYJELdEHrEOzDOsHoXM3aiXi3kURyDw+L/ljvIwWpgrVic94CCBlwUkUCtbw+n9Gfn06GE4V1J7/"
"omTHBKJXfd1hEDBegyEf6l2mx6p6zWCRcBEIZNObMRsX0P7P9A09/ZyzQPAMJrfI25fy2PvEuHWpVmbFBm7Xsf/B/"
"pGuP3j4td+e62Fu8yhMpSNhPclCdz+MXO9yCCondvU9DUzPQxU26yQhYNasu4cLipXCYpNhc9+dpLakoqlBB7Qq52R1S/f3PgsbTYy/uJs0NwoQV7/"
"aQTgjWutM5Nb+"
"yxxebr6dfRG6HfN0AXvLq8ON2FimTK6mXa9YI5YXKROAX4VssccBw1dGM8RaaAvMKQKEjfzwcPMo0C2mCcfFB2Nkj3A2SLvWdL7APgkEnGATDjs8Kn"
"bbI5Idr9ReU38zyB2l3Ys+CVbl6dvXdCu9QMS5t9Ez6e6zu3ZJKbMDEmrD7+0QyryYwSTFMDR1LJsbHavYzfGm/"
"bAC2yFlwGuN1nqpxvHCrFJH4Gjvs/"
"IVsX1Hnr1IZFJdIaMI8DRkksKijAYxxizan62LjrGQ8Lx4SGEYqTKU182XJdG9joSEuIvh2BaLZwu6AGEO1BbtJpGeVUiupqORQMGD9+"
"jOzo3KN0u3amsHO9QASeJ2fhMM7ej7C2aBnUrsX3zayB+seS0PTpZPqhI4IImvRmuwWiWXlWqhuEMSrnfuUN+"
"oZ8LfhsUPrRriUsuM7ZQJhzeVHGLXKeO0uFhL2KW7EQs7bdnOtQw6vw2FEe6bzYUZdR7SNWvRpN1BFm48vSLnLyhjtRN0ZAI5j6FNB6sWGVXRp32uH"
"p0BH/Nuss6Q+xcn0ZhBKIUGPtVtyUZcgoy1JT23JusETl83vsEx5NkWhSUCdhThOyB/N7fl4lRgfF0VxRabLXa0RcPlF7m79R5Mn/+/mveGQtd/"
"3UurCuDd2bjJ2ZL+GNgwGpliPpjPa1LHDX7WXi/yyYHHjGq7uYuauQql0ID/"
"bZY4kx9W0YTpzeKRd3Y4FZifDtFkxbosTFsUL+svpNSmQLuGptxPrfIHadHBkwP4g5CvAswfos6FGAx+ntE9+"
"jVt9WF6n73F7awQY0RxKOPRz0ESRPI3Z3r5m4AXoaEWkzqBIcCsYLBf3gIuxQxCbo5kMxhj7+qAAbJlqUTZQZS21ZbQS/"
"CRxXEv5TIYrQv0h004kzRenULxyM2fVgnPF09eLCW1wIeLfy5q5ShfkewBJ2xoqon5Pq9MgyG+EkwZ5ZphjGTEQkRlLfVNeD6s+HBildUL1+"
"sQkICmRxIKhubnrJ0WpD4EkpvTOEZkFalGjkp3t1L7KeBseX/qFfCBlcNThLbBVZQMRLGeCYZ/OZ1Z1qkN/KB6ltAjI+ZALJ73G/"
"PzPF19S0vUmka0Aeq+Q13X1fD27HGTIW2zVhgQvgIk+shlQWLCDn9qDwNxyGWNplR8dIsnl1lAIVXokjA+qIz3RNAkwDkk60x+"
"rZKJSjLiy3RtbJ6ZTsDl4U6NIzln1zbPkbS6ttbtoI86aBtSQribN7zoG3zG9pkdr+"
"hGso6jP7QhhEVskGfdbHTtOkTOhGqcrg3jALtv5J4fTNK4kzyjJRYQ0HVuWtPMvP022bI4uA8SbjnWkH7Z2Kt8LujV9ji9RDs4+"
"Y3bQn2TlPiShyPeOJ0f2Tlaeo2liySol7PZT1rbDjr8Zp/"
"UIbkyeEl0BIg8O6BAJ3h8JMXRQTklu23Fkl6PMHsGHcz0GE58+WJMgM6RyCgc2ka7L4YeGu7mPjJRSo3umdhi2GqOfSgELUzWr/"
"gVmFljsiHJkg5xMrksDmGoG+kXv57iyNi8Dphr6SsT3lFdSG4Tx9WeMSSNOngSyK8yzJStqUmq5wiTNeBeIW2KgSQMzGETMpMVZqoAX/"
"fHdgAjYxwooM15G2R98Vs1xlX5fjEHz1DNJQ39pSPBJInvdZAQqDFVzD9A4IktiIthEIWj0RemW+HRQKQ/"
"rODTVeZB2bY+IAx+qr7JyUPkYziNWQKnXhRUm1t4ZJarr1Ud6/"
"G6RxdNjt3pX1HBfn0t4+6nOuWA7MAsdA+EvQjXd8XPLPEFReAHnIXqE0DAAQPmRdcnfDCfXtPQv+"
"hD82s4sQCsaqA1dwV3CsRzhfWiZlQ5iMPJtjU0A3UgGPg+"
"7MAXNfPUV8eiRyCwC4fEnSkj2LLMf1de1wlyjosXcM6GTMroBo8wFsUWxdTSGA1xsPWDAL3DWi6szxVLp7EGNssLZ8OWKHALYy9P6bN5qUS23FahYg"
"Tu6jVCGVAuCGwnaPLGi4yUdQIOTvTEgJiPNf8jZ2wKiOZZ4belGxh6H7Y54kfVCZwxGdhcyktUV+H3TgBZmR70x/"
"SF6ct1GeZd1W9IxEJTTcRc179RNcRk4pd5KjwyIO6/WFOtSRKOmPs+cb9bArVV/"
"HjeIDM0rvahdWvqjMo8q9BSyzjvrvLrSxkaLskfhu3KHnfftGZdiYypGsngBFN9RDmSHknNttmal5tnWZP/"
"5RhfDnfnDwCq9ARP3USRkaUpKl87l0qzZkHnSoKBUpcQ70qrhrMGyQyn7dobM7mHw8UZ4fOuCxY/vEQ3dql4RsczsaqHsl3z/"
"AgXKhs2+MI32L9lC5RSz/"
"ix2uzbExljLdYgUe6aNsUqKbYkZfugFEbTtwHXPsrSioXuusKGX00muMADmvxpqrVt63omwKlK4IJ9la10DCsJiv5NOFsIZhPTIb2fzJUR6eSRyNFL"
"Wt3IKpVTwsLXqI/"
"biB6vInyvJvqNWgc8wSIQWvngtSyJugYmFG3k9GuuJQ6VdbafPAR5BCeuJy8JvX0dANbaRvsZPsLWa7nNCM2iwmtkNMMLdQe6+"
"DdCHz5XGwW91spC1pORsSTM/"
"pegYHDptkICvczJSSTwDs1aATBZGMfVtKzed4Vxx9nxN23uqwcVCwDljkRB7AXbFaCbRLi0glGmK8CaeGq+KAuLj7eAm8w6ihS9IWGAD8oGhVyJR+"
"D4U4ah5YX/GAysJA8aK3g0xKmUfveHTUQKDs0dzdTOrTr18++t7IqK1x2jDCmU9/"
"C6saN75gcZr4Q9QyULNHFgtXCpydThPIMBJ47jZFuvFSmoBbqD6m8WUjZjDJ4+odZISIGBzUoCKut9jjok8o2RzK6oY265stKOE0Ud7EI+"
"7rAtQY71LhsUSC6Sb4QbIsJlG7vb/"
"l0fF6Kh5IRGrzNVBJFsd+0ws6JQxDEVFSuO5UZVviYt0GHS+Qtt4EnoWbARCPCQfq4EiZJSbUhIPGWLoh6ozv/"
"U+5LArEPD7JcAXvpe+ZwYyrS5c8HWtMng7B7eiNdfjv9HtpfTVidxawNwhgC4igZ18yigsRJvyGuqpCipA/"
"p5sfXFb4hibSZsif7HAPja0G4CFxGL96Vxx1eKiSCNyLYL42m2slvgI6rvYKFTVvdQtBFhiav7vg+"
"Oz2wwzYRWRlHsIdOfcNws8XAgTL384gT8km9UtO4WtUyJZL5xDb2iWGsSoqRCAFiNYsxpwcCfZa4p5YP8E7PX4tzdUJ+"
"m2XNxuM7esUyjDouRnVu49PP78Q5mFAsKUZ/4mwPGlzInGVr8g7piw4FueB5qFfCHibo8gsC355UnT6WB9Gdu2h4+dsI0wh51a5UW7/"
"GY8zQ7VDmorGfSiELm3SpS3xvRhBOHGBLgn68hyFNMpzg/"
"XfJkEUUlVvayVpmJsKqeQEVwPzLW02XkvsFmjY98JIIDg4PqRw+2vWTQu4yHDx5AwtAYZaCDUYS10OjYZgzVp0NqlA2Lmc4oRYRumyr8w+"
"gNFxX16vxrG6DMAJeMtYyACbiuAp3RsW8G3rAWifNmTx8mEkTzZHW6Xqt9nD1qPeVxCZMq+wq7LH333FAVFW/"
"V6qccLaqy2uquIW41fWrKW3MkrD3fKqjdGSz0rj278X4kLakpOVvr9ww6FNk8wRL0TcfRxurhhLtRLQp6zgyu5BFA44xFIbq+"
"0Yvmics8iY9He45gODgaWRB9vfM8JhpTpI6c6ovoxL8fOuWEPzadjg388Lhaqv/"
"CJa8IVbKO9BBMrrHQVbF1iVKDO5UrGR+4LY7NSe7Jt5vrwzhFPaOhDw6VoL3p5jUq3D7ABG3tKbcdrrL+"
"lCJ44J0T0fYMVlzFlRjc75oNqPiKDyKOI1e9Fvw9ybZw5b0iU0kyBf1hW+JTtgr/qsszaWe/mHDdGVNXk6OBBCzECTrUj4WdHGi/"
"VorxztlwJ5GXoTTdFMhckg//ExJweev/"
"s2aYgKZRSgZVkpKHVqyNTVuEaB8UQuPhGGwEerawjiK0hRJaF4Bg9UtJMPuIu8V1bis9oCjWKVcqgiyam4t6N06O5tM38wfPTWtyD4b8ZUDl0koAfa"
"n9+uE1mJQw1DSMixM4QDnGXFA9bxgt/"
"LvKWdz0MwN9wgI5yhYtmHau0l5lO2WRsRhZvJJof1z3LvZCEqQB2F2z7GHuzmmNnyvZ8QqrnV9EBScfY25vjjBisylp2dorLh7oI2W4z8RsvegvXn4"
"nsh8bsEj1DJtXNRIHuhQGY9ewKOYFTc3zUK1NJaNpzBZmW8ccWYJYi6Mk7ZLfpL1A6V/C0AyePBAysg4r/"
"VoaLnZxgvhCZvjTH2uqfX7iQuS4F0t+qAijrgPwmm5Vy9JJrgWPKujTZkCg6Px0VVtFC+EfJSx9QyvPY6w4St/"
"0D4EjTxRXuEoDGkr1oYBQ8kVBj5KHyIkHCEEBAmrwA0pwtdOyzpRMj79IahmbNNuWftCHx3LklCpaD3Yo0pjTfML4ToJl5S2sQ8wvHsd960fr5fdXZ"
"EORmJtkLLgu5Ca6eiKf5GIw/yKSLUwY0F7rMvySfHB3PzBjJjgnt04MzGFg9vSEt6+OsRMKhV1eRGgPpLai6WzxcGY5vuiqw/"
"14TsoLKeHbkRO6qJgiJzo2HlDc2+MCrYNp31aeyro7WWQr/"
"sPybVj7BVFLuplVprsOG5TWwpzP84I3euP12UlSUma6TgVgyQmoms9rutumle3d26+b7fmnS/aQ3ps9kqYwN0+oDXzkQaP7apliI1Ks/"
"3z3ZsGaiLlyVSkDxgLmov1p23Qy7yI1TxxsGt4hVyD5kSJIxzoFnqT09wKhHHa1/"
"smUNIqeDLoo5L5e+TiBEGsiHWPcG4bsUWBF9NkbjFxp34tnO9RlE5cFALntzx2418tlQ+"
"4CnAljWUAiKEFJrHGH5IBIOU4jMiHmA6w0WYa9bzTnvhaRXVtxWKK9VuNbkciK8+PZOVEz7F/foJ7ERZ2P+9w8htm9J/"
"rxKW17GAJN5VVEotpmOPao4PJ/bi3x7Tt/ckZr8444ax/w2BZw0aLt/DgA6Kd04+MOr+pEpi9J3WHKvNnYGFWgYvSg0alOsp/"
"Nnwjo6OK6fvTOokwi78PxOy7+yQ2uWZOTzDkFnZ1Ri7X11X1MlAXqGehz+QfjtF2FcPVDLVFsAiLlt/"
"Di7LUUhzf3xitZHFkphtSE2ilrIgQAF7cPeRJBFM2MIXNhhlMfAgychBtUcPgzSzkdUbRpZ2pKNtpNZr9Xq5GQLIcKJ4MkBOBUeoduEBjWPxiGcYWo"
"tFatmZRoxiYAHxNTcN2FrQ0I9E12UC3NcaFTkqvCaBonx2CvBayKeXuewhxbLB503TQi8E9FSrsi9efYPhGDqqX2EsJD/"
"3DHOg28NZvOpZGLs9AEWpgrl+x/"
"Wk6mXCxM++OZxA8K3MGlQuG7Gmodcz6FHh9mqoIZZh6OrObpBUrJfdoZeWXR+"
"GVt8zi3m0oPlAhNUyi3a6zeZcvqfwI3M7zoXxGU2q0ETZgfCE26H9E+PNxes7mw4SwEl78lclmnNhUlZ5C4Y8v2YJnmFn8+a6WdrgjTU2awQ/"
"osSJFtKuNgOw9n72uyhPOkEB4qcVZ1A=";
const char *sqlite_sample_db = sqlite_sample_db_arr;
const size_t sqlite_sample_db_size = sizeof(sqlite_sample_db_arr) - 1;
} // namespace td

View File

@ -16,4 +16,7 @@ extern const size_t thumbnail_size;
extern const char *gzip_bomb;
extern const size_t gzip_bomb_size;
extern const char *sqlite_sample_db;
extern const size_t sqlite_sample_db_size;
} // namespace td

View File

@ -4,6 +4,8 @@
// 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 "data.h"
#include "td/db/binlog/BinlogHelper.h"
#include "td/db/binlog/ConcurrentBinlog.h"
#include "td/db/BinlogKeyValue.h"
@ -17,7 +19,9 @@
#include "td/actor/actor.h"
#include "td/utils/base64.h"
#include "td/utils/common.h"
#include "td/utils/filesystem.h"
#include "td/utils/logging.h"
#include "td/utils/port/FileFd.h"
#include "td/utils/port/thread.h"
@ -191,6 +195,33 @@ TEST(DB, sqlite_encryption) {
SqliteDb::open_with_key(path, cucumber).ensure_error();
}
TEST(DB, sqlite_encryption_migrate) {
string path = "test_sqlite_db";
SqliteDb::destroy(path).ignore();
auto cucumber = DbKey::password("cucumber");
auto empty = DbKey::empty();
if (false) {
// sqlite_sample_db was generated by the following code
{
SqliteDb::change_key(path, cucumber, empty).ensure();
auto db = SqliteDb::open_with_key(path, cucumber).move_as_ok();
db.set_user_version(123).ensure();
auto kv = SqliteKeyValue();
kv.init_with_connection(db.clone(), "kv").ensure();
kv.set("hello", "world");
}
LOG(ERROR) << base64_encode(read_file(path).move_as_ok());
}
write_file(path, base64_decode(Slice(sqlite_sample_db, sqlite_sample_db_size)).move_as_ok()).ensure();
{
auto db = SqliteDb::open_with_key(path, cucumber).move_as_ok();
auto kv = SqliteKeyValue();
kv.init_with_connection(db.clone(), "kv").ensure();
CHECK(kv.get("hello") == "world");
CHECK(db.user_version().ok() == 123);
}
}
using SeqNo = uint64;
struct DbQuery {
enum class Type { Get, Set, Erase } type = Type::Get;

View File

@ -4,7 +4,7 @@
// 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/utils/tests.h"
#include "data.h"
#include "td/net/HttpChunkedByteFlow.h"
#include "td/net/HttpHeaderCreator.h"
@ -31,10 +31,9 @@
#include "td/utils/Random.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include "td/utils/tests.h"
#include "td/utils/UInt.h"
#include "data.h"
#include <algorithm>
#include <limits>
@ -133,6 +132,19 @@ TEST(Http, reader) {
clear_thread_locals();
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
auto start_mem = BufferAllocator::get_buffer_mem();
auto start_size = BufferAllocator::get_buffer_slice_size();
{
BufferSlice a("test test");
BufferSlice b = std::move(a);
a = std::move(a);
b = std::move(b);
a = std::move(b);
BufferSlice c = a.from_slice(a);
CHECK(c.size() == a.size());
}
clear_thread_locals();
ASSERT_EQ(start_mem, BufferAllocator::get_buffer_mem());
ASSERT_EQ(start_size, BufferAllocator::get_buffer_slice_size());
for (int i = 0; i < 20; i++) {
td::ChainBufferWriter input_writer;
auto input = input_writer.extract_reader();
@ -184,6 +196,7 @@ TEST(Http, reader) {
}
clear_thread_locals();
ASSERT_EQ(start_mem, BufferAllocator::get_buffer_mem());
ASSERT_EQ(start_size, BufferAllocator::get_buffer_slice_size());
}
TEST(Http, gzip_bomb) {

View File

@ -4,13 +4,12 @@
// 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/utils/tests.h"
#include "td/utils/common.h"
#include "td/utils/crypto.h"
#include "td/utils/logging.h"
#include "td/utils/OptionParser.h"
#include "td/utils/Slice.h"
#include "td/utils/tests.h"
#if TD_EMSCRIPTEN
#include <emscripten.h>

View File

@ -4,10 +4,11 @@
// 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/utils/tests.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/telegram/ConfigManager.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/net/PublicRsaKeyShared.h"
#include "td/telegram/net/Session.h"
#include "td/telegram/NotificationManager.h"
#include "td/mtproto/AuthData.h"
#include "td/mtproto/DhHandshake.h"
@ -25,11 +26,8 @@
#include "td/net/Socks5.h"
#include "td/net/TransparentProxy.h"
#include "td/telegram/ConfigManager.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/net/PublicRsaKeyShared.h"
#include "td/telegram/net/Session.h"
#include "td/telegram/NotificationManager.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/base64.h"
#include "td/utils/common.h"
@ -39,6 +37,7 @@
#include "td/utils/port/SocketFd.h"
#include "td/utils/Random.h"
#include "td/utils/Status.h"
#include "td/utils/tests.h"
#include "td/utils/Time.h"
REGISTER_TESTS(mtproto);

View File

@ -4,14 +4,14 @@
// 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/SecureStorage.h"
#include "td/utils/buffer.h"
#include "td/utils/filesystem.h"
#include "td/utils/logging.h"
#include "td/utils/port/path.h"
#include "td/utils/tests.h"
#include "td/telegram/SecureStorage.h"
using namespace td;
TEST(SecureStorage, secret) {

View File

@ -6,15 +6,14 @@
//
#include "data.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/telegram/Client.h"
#include "td/telegram/ClientActor.h"
#include "td/telegram/files/PartsManager.h"
#include "td/telegram/td_api.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/base64.h"
#include "td/utils/BufferedFd.h"
#include "td/utils/common.h"
@ -30,6 +29,7 @@
#include "td/utils/Status.h"
#include "td/utils/tests.h"
#include <atomic>
#include <cstdio>
#include <functional>
#include <map>
@ -858,14 +858,18 @@ TEST(Client, SimpleMulti) {
//client.execute({1, td::td_api::make_object<td::td_api::setLogTagVerbosityLevel>("td_requests", 1)});
//}
for (auto &client : clients) {
client.send({3, td::make_tl_object<td::td_api::testSquareInt>(3)});
for (size_t i = 0; i < clients.size(); i++) {
clients[i].send({i + 2, td::make_tl_object<td::td_api::testSquareInt>(3)});
if (Random::fast(0, 1) == 1) {
clients[i].send({1, td::make_tl_object<td::td_api::close>()});
}
}
for (auto &client : clients) {
for (size_t i = 0; i < clients.size(); i++) {
while (true) {
auto result = client.receive(10);
if (result.id == 3) {
auto result = clients[i].receive(10);
if (result.id == i + 2) {
CHECK(result.object->get_id() == td::td_api::testInt::ID);
auto test_int = td::td_api::move_object_as<td::td_api::testInt>(result.object);
ASSERT_EQ(test_int->value_, 9);
break;
@ -877,14 +881,29 @@ TEST(Client, SimpleMulti) {
#if !TD_THREAD_UNSUPPORTED
TEST(Client, Multi) {
td::vector<td::thread> threads;
std::atomic<int> ok_count{0};
for (int i = 0; i < 4; i++) {
threads.emplace_back([] {
for (int i = 0; i < 1000; i++) {
threads.emplace_back([i, &ok_count] {
for (int j = 0; j < 1000; j++) {
td::Client client;
client.send({3, td::make_tl_object<td::td_api::testSquareInt>(3)});
auto request_id = static_cast<td::uint64>(j + 2 + 1000 * i);
client.send({request_id, td::make_tl_object<td::td_api::testSquareInt>(3)});
if (j & 1) {
client.send({1, td::make_tl_object<td::td_api::close>()});
}
while (true) {
auto result = client.receive(10);
if (result.id == 3) {
if (result.id == request_id) {
ok_count++;
if ((j & 1) == 0) {
client.send({1, td::make_tl_object<td::td_api::close>()});
}
}
if (result.id == 0 && result.object != nullptr &&
result.object->get_id() == td::td_api::updateAuthorizationState::ID &&
static_cast<const td::td_api::updateAuthorizationState *>(result.object.get())
->authorization_state_->get_id() == td::td_api::authorizationStateClosed::ID) {
ok_count++;
break;
}
}
@ -895,6 +914,7 @@ TEST(Client, Multi) {
for (auto &thread : threads) {
thread.join();
}
ASSERT_EQ(8 * 1000, ok_count.load());
}
TEST(Client, MultiNew) {

View File

@ -9,9 +9,11 @@
#include "td/db/binlog/BinlogHelper.h"
#include "td/db/TQueue.h"
#include "td/utils/buffer.h"
#include "td/utils/int_types.h"
#include "td/utils/misc.h"
#include "td/utils/port/path.h"
#include "td/utils/Random.h"
#include "td/utils/Slice.h"
#include "td/utils/Span.h"
#include "td/utils/Status.h"
@ -29,7 +31,7 @@ TEST(TQueue, hands) {
auto qid = 12;
ASSERT_EQ(true, tqueue->get_head(qid).empty());
ASSERT_EQ(true, tqueue->get_tail(qid).empty());
tqueue->push(qid, "hello", 0, 0, td::TQueue::EventId());
tqueue->push(qid, "hello", 1, 0, td::TQueue::EventId());
auto head = tqueue->get_head(qid);
auto tail = tqueue->get_tail(qid);
ASSERT_EQ(head.next().ok(), tail);
@ -66,7 +68,7 @@ class TestTQueue {
binlog_->set_callback(std::move(tqueue_binlog));
}
void restart(td::Random::Xorshift128plus &rnd, double now) {
void restart(td::Random::Xorshift128plus &rnd, td::int32 now) {
if (rnd.fast(0, 10) == 0) {
baseline_->run_gc(now);
}
@ -99,7 +101,7 @@ class TestTQueue {
}
}
EventId push(td::TQueue::QueueId queue_id, td::string data, double expires_at, EventId new_id = EventId()) {
EventId push(td::TQueue::QueueId queue_id, td::string data, td::int32 expires_at, EventId new_id = EventId()) {
auto a_id = baseline_->push(queue_id, data, expires_at, 0, new_id).move_as_ok();
auto b_id = memory_->push(queue_id, data, expires_at, 0, new_id).move_as_ok();
auto c_id = binlog_->push(queue_id, data, expires_at, 0, new_id).move_as_ok();
@ -108,14 +110,14 @@ class TestTQueue {
return a_id;
}
void check_head_tail(td::TQueue::QueueId qid, double now) {
void check_head_tail(td::TQueue::QueueId qid) {
//ASSERT_EQ(baseline_->get_head(qid), memory_->get_head(qid));
//ASSERT_EQ(baseline_->get_head(qid), binlog_->get_head(qid));
ASSERT_EQ(baseline_->get_tail(qid), memory_->get_tail(qid));
ASSERT_EQ(baseline_->get_tail(qid), binlog_->get_tail(qid));
}
void check_get(td::TQueue::QueueId qid, td::Random::Xorshift128plus &rnd, double now) {
void check_get(td::TQueue::QueueId qid, td::Random::Xorshift128plus &rnd, td::int32 now) {
td::TQueue::Event a[10];
td::MutableSpan<td::TQueue::Event> a_span(a, 10);
td::TQueue::Event b[10];
@ -167,7 +169,7 @@ TEST(TQueue, random) {
};
TestTQueue q;
double now = 0;
td::int32 now = 1000;
auto push_event = [&] {
auto data = PSTRING() << rnd();
if (rnd.fast(0, 10000) == 0) {
@ -179,7 +181,7 @@ TEST(TQueue, random) {
now += 10;
};
auto check_head_tail = [&] {
q.check_head_tail(next_queue_id(), now);
q.check_head_tail(next_queue_id());
};
auto restart = [&] {
q.restart(rnd, now);
@ -192,3 +194,35 @@ TEST(TQueue, random) {
steps.step(rnd);
}
}
TEST(TQueue, memory_leak) {
return;
auto tqueue = td::TQueue::create();
auto tqueue_binlog = td::make_unique<td::TQueueBinlog<td::Binlog>>();
std::string binlog_path = "test_tqueue.binlog";
td::Binlog::destroy(binlog_path).ensure();
auto binlog = std::make_shared<td::Binlog>();
binlog->init(binlog_path, [&](const td::BinlogEvent &event) { UNREACHABLE(); }).ensure();
tqueue_binlog->set_binlog(std::move(binlog));
tqueue->set_callback(std::move(tqueue_binlog));
td::int32 now = 0;
std::vector<td::TQueue::EventId> ids;
td::Random::Xorshift128plus rnd(123);
int i = 0;
while (true) {
auto id = tqueue->push(1, "a", now + 600000, 0, {}).move_as_ok();
ids.push_back(id);
if (ids.size() > static_cast<std::size_t>(rnd()) % 100000) {
auto it = static_cast<std::size_t>(rnd()) % ids.size();
std::swap(ids.back(), ids[it]);
tqueue->forget(1, ids.back());
ids.pop_back();
}
now++;
if (i++ % 100000 == 0) {
LOG(ERROR) << td::BufferAllocator::get_buffer_mem() << " " << tqueue->get_size(1) << " "
<< td::BufferAllocator::get_buffer_slice_size();
}
}
}