Merge commit '83c9f5180bf9738df2667841ed0c4df9ebeaec40'

Conflicts:
	td/telegram/MessagesManager.cpp
This commit is contained in:
Andrea Cavalli 2020-08-31 11:51:02 +02:00
commit 510aec55de
30 changed files with 199 additions and 139 deletions

View File

@ -220,6 +220,7 @@ if (NOT MSVC)
add_cxx_compiler_flag("-Wno-sign-conversion")
add_cxx_compiler_flag("-Wc++14-compat-pedantic")
add_cxx_compiler_flag("-Wdeprecated")
add_cxx_compiler_flag("-Wno-unused-command-line-argument")
add_cxx_compiler_flag("-Qunused-arguments")
add_cxx_compiler_flag("-Wodr")
add_cxx_compiler_flag("-flto-odr-type-merging")

View File

@ -15,7 +15,7 @@ endif()
message(STATUS "Found JNI: ${JNI_INCLUDE_DIRS} ${JNI_LIBRARIES}")
if (NOT Java_FOUND)
find_package(Java 1.6 REQUIRED)
find_package(Java REQUIRED)
endif()
message(STATUS "Found Java: ${Java_JAVAC_EXECUTABLE} ${Java_JAVADOC_EXECUTABLE}")

View File

@ -301,7 +301,7 @@ venue location:location title:string address:string provider:string id:string ty
//@param_description Game description @photo Game photo @animation Game animation; may be null
game id:int64 short_name:string title:string text:formattedText description:string photo:photo animation:animation = Game;
//@description Describes a poll @id Unique poll identifier @question Poll question, 1-255 characters @options List of poll answer options
//@description Describes a poll @id Unique poll identifier @question Poll question, 1-300 characters @options List of poll answer options
//@total_voter_count Total number of voters, participating in the poll @recent_voter_user_ids User identifiers of recent voters, if the poll is non-anonymous
//@is_anonymous True, if the poll is anonymous @type Type of the poll
//@open_period Amount of time the poll will be active after creation, in seconds @close_date Point in time (Unix timestamp) when the poll will be automatically closed @is_closed True, if the poll is closed
@ -428,7 +428,7 @@ chatAdministrators administrators:vector<chatAdministrator> = ChatAdministrators
//@can_send_messages True, if the user can send text messages, contacts, locations, and venues
//@can_send_media_messages True, if the user can send audio files, documents, photos, videos, video notes, and voice notes. Implies can_send_messages permissions
//@can_send_polls True, if the user can send polls. Implies can_send_messages permissions
//@can_send_other_messages True, if the user can send animations, games, and stickers and use inline bots. Implies can_send_messages permissions
//@can_send_other_messages True, if the user can send animations, games, stickers and dice and use inline bots. Implies can_send_messages permissions
//@can_add_web_page_previews True, if the user may add a web page preview to their messages. Implies can_send_messages permissions
//@can_change_info True, if the user can change the chat title, photo, and other settings
//@can_invite_users True, if the user can invite new users to the chat
@ -1750,7 +1750,7 @@ inputMessageGame bot_user_id:int32 game_short_name:string = InputMessageContent;
//@payload The invoice payload @provider_token Payment provider token @provider_data JSON-encoded data about the invoice, which will be shared with the payment provider @start_parameter Unique invoice bot start_parameter for the generation of this invoice
inputMessageInvoice invoice:invoice title:string description:string photo_url:string photo_size:int32 photo_width:int32 photo_height:int32 payload:bytes provider_token:string provider_data:string start_parameter:string = InputMessageContent;
//@description A message with a poll. Polls can't be sent to secret chats. Polls can be sent only to a private chat with a bot @question Poll question, 1-255 characters @options List of poll answer options, 2-10 strings 1-100 characters each
//@description A message with a poll. Polls can't be sent to secret chats. Polls can be sent only to a private chat with a bot @question Poll question, 1-255 characters (up to 300 characters for bots) @options List of poll answer options, 2-10 strings 1-100 characters each
//@is_anonymous True, if the poll voters are anonymous. Non-anonymous polls can't be sent or forwarded to channels @type Type of the poll
//@open_period Amount of time the poll will be active after creation, in seconds; for bots only
//@close_date Point in time (Unix timestamp) when the poll will be automatically closed; for bots only
@ -3244,7 +3244,7 @@ updateSelectedBackground for_dark_theme:Bool background:background = Update;
//@description Some language pack strings have been updated @localization_target Localization target to which the language pack belongs @language_pack_id Identifier of the updated language pack @strings List of changed language pack strings
updateLanguagePackStrings localization_target:string language_pack_id:string strings:vector<languagePackString> = Update;
//@description The connection state has changed @state The new connection state
//@description The connection state has changed. This update must be used only to show the user a human-readable description of the connection state @state The new connection state
updateConnectionState state:ConnectionState = Update;
//@description New terms of service must be accepted by the user. If the terms of service are declined, then the deleteAccount method should be called with the reason "Decline ToS update" @terms_of_service_id Identifier of the terms of service @terms_of_service The new terms of service
@ -3339,7 +3339,7 @@ testVectorStringObject value:vector<testString> = TestVectorStringObject;
---functions---
//@description Returns the current authorization state; this is an offline request. For informational purposes only. Use updateAuthorizationState instead to maintain the current authorization state
//@description Returns the current authorization state; this is an offline request. For informational purposes only. Use updateAuthorizationState instead to maintain the current authorization state. Can be called before initialization
getAuthorizationState = AuthorizationState;
@ -3384,10 +3384,10 @@ checkAuthenticationBotToken token:string = Ok;
//@description Closes the TDLib instance after a proper logout. Requires an available network connection. All local data will be destroyed. After the logout completes, updateAuthorizationState with authorizationStateClosed will be sent
logOut = Ok;
//@description Closes the TDLib instance. All databases will be flushed to disk and properly closed. After the close completes, updateAuthorizationState with authorizationStateClosed will be sent
//@description Closes the TDLib instance. All databases will be flushed to disk and properly closed. After the close completes, updateAuthorizationState with authorizationStateClosed will be sent. Can be called before initialization
close = Ok;
//@description Closes the TDLib instance, destroying all local data without a proper logout. The current user session will remain in the list of all active sessions. All local data will be destroyed. After the destruction completes updateAuthorizationState with authorizationStateClosed will be sent
//@description Closes the TDLib instance, destroying all local data without a proper logout. The current user session will remain in the list of all active sessions. All local data will be destroyed. After the destruction completes updateAuthorizationState with authorizationStateClosed will be sent. Can be called before authorization
destroy = Ok;
@ -3395,7 +3395,7 @@ destroy = Ok;
confirmQrCodeAuthentication link:string = Session;
//@description Returns all updates needed to restore current TDLib state, i.e. all actual UpdateAuthorizationState/UpdateUser/UpdateNewChat and others. This is especially useful if TDLib is run in a separate process. This is an offline method. Can be called before authorization
//@description Returns all updates needed to restore current TDLib state, i.e. all actual UpdateAuthorizationState/UpdateUser/UpdateNewChat and others. This is especially useful if TDLib is run in a separate process. Can be called before initialization
getCurrentState = Updates;
@ -3720,36 +3720,36 @@ editInlineMessageReplyMarkup inline_message_id:string reply_markup:ReplyMarkup =
editMessageSchedulingState chat_id:int53 message_id:int53 scheduling_state:MessageSchedulingState = Ok;
//@description Returns all entities (mentions, hashtags, cashtags, bot commands, bank card numbers, URLs, and email addresses) contained in the text. This is an offline method. Can be called before authorization. Can be called synchronously @text The text in which to look for entites
//@description Returns all entities (mentions, hashtags, cashtags, bot commands, bank card numbers, URLs, and email addresses) contained in the text. Can be called synchronously @text The text in which to look for entites
getTextEntities text:string = TextEntities;
//@description Parses Bold, Italic, Underline, Strikethrough, Code, Pre, PreCode, TextUrl and MentionName entities contained in the text. This is an offline method. Can be called before authorization. Can be called synchronously @text The text to parse @parse_mode Text parse mode
//@description Parses Bold, Italic, Underline, Strikethrough, Code, Pre, PreCode, TextUrl and MentionName entities contained in the text. Can be called synchronously @text The text to parse @parse_mode Text parse mode
parseTextEntities text:string parse_mode:TextParseMode = FormattedText;
//@description Parses Markdown entities in a human-friendly format, ignoring mark up errors. This is an offline method. Can be called before authorization. Can be called synchronously
//@description Parses Markdown entities in a human-friendly format, ignoring markup errors. Can be called synchronously
//@text The text to parse. For example, "__italic__ ~~strikethrough~~ **bold** `code` ```pre``` __[italic__ text_url](telegram.org) __italic**bold italic__bold**"
parseMarkdown text:formattedText = FormattedText;
//@description Replaces text entities with Markdown formatting in a human-friendly format. Entities that can't be represented in Markdown unambiguously are kept as is. This is an offline method. Can be called before authorization. Can be called synchronously @text The text
//@description Replaces text entities with Markdown formatting in a human-friendly format. Entities that can't be represented in Markdown unambiguously are kept as is. Can be called synchronously @text The text
getMarkdownText text:formattedText = FormattedText;
//@description Returns the MIME type of a file, guessed by its extension. Returns an empty string on failure. This is an offline method. Can be called before authorization. Can be called synchronously @file_name The name of the file or path to the file
//@description Returns the MIME type of a file, guessed by its extension. Returns an empty string on failure. Can be called synchronously @file_name The name of the file or path to the file
getFileMimeType file_name:string = Text;
//@description Returns the extension of a file, guessed by its MIME type. Returns an empty string on failure. This is an offline method. Can be called before authorization. Can be called synchronously @mime_type The MIME type of the file
//@description Returns the extension of a file, guessed by its MIME type. Returns an empty string on failure. Can be called synchronously @mime_type The MIME type of the file
getFileExtension mime_type:string = Text;
//@description Removes potentially dangerous characters from the name of a file. The encoding of the file name is supposed to be UTF-8. Returns an empty string on failure. This is an offline method. Can be called before authorization. Can be called synchronously @file_name File name or path to the file
//@description Removes potentially dangerous characters from the name of a file. The encoding of the file name is supposed to be UTF-8. Returns an empty string on failure. Can be called synchronously @file_name File name or path to the file
cleanFileName file_name:string = Text;
//@description Returns a string stored in the local database from the specified localization target and language pack by its key. Returns a 404 error if the string is not found. This is an offline method. Can be called before authorization. Can be called synchronously
//@description Returns a string stored in the local database from the specified localization target and language pack by its key. Returns a 404 error if the string is not found. Can be called synchronously
//@language_pack_database_path Path to the language pack database in which strings are stored @localization_target Localization target to which the language pack belongs @language_pack_id Language pack identifier @key Language pack key of the string to be returned
getLanguagePackString language_pack_database_path:string localization_target:string language_pack_id:string key:string = LanguagePackStringValue;
//@description Converts a JSON-serialized string to corresponding JsonValue object. This is an offline method. Can be called before authorization. Can be called synchronously @json The JSON-serialized string
//@description Converts a JSON-serialized string to corresponding JsonValue object. Can be called synchronously @json The JSON-serialized string
getJsonValue json:string = JsonValue;
//@description Converts a JsonValue object to corresponding JSON-serialized string. This is an offline method. Can be called before authorization. Can be called synchronously @json_value The JsonValue object
//@description Converts a JsonValue object to corresponding JSON-serialized string. Can be called synchronously @json_value The JsonValue object
getJsonString json_value:JsonValue = Text;
@ -3901,7 +3901,7 @@ reorderChatFilters chat_filter_ids:vector<int32> = Ok;
//@description Returns recommended chat filters for the current user
getRecommendedChatFilters = RecommendedChatFilters;
//@description Returns default icon name for a filter. This is an offline method. Can be called before authorization. Can be called synchronously @filter Chat filter
//@description Returns default icon name for a filter. Can be called synchronously @filter Chat filter
getChatFilterDefaultIconName filter:chatFilter = Text;
@ -4408,7 +4408,7 @@ registerDevice device_token:DeviceToken other_user_ids:vector<int32> = PushRecei
//@payload JSON-encoded push notification payload with all fields sent by the server, and "google.sent_time" and "google.notification.sound" fields added
processPushNotification payload:string = Ok;
//@description Returns a globally unique push notification subscription identifier for identification of an account, which has received a push notification. This is an offline method. Can be called before authorization. Can be called synchronously @payload JSON-encoded push notification payload
//@description Returns a globally unique push notification subscription identifier for identification of an account, which has received a push notification. Can be called synchronously @payload JSON-encoded push notification payload
getPushReceiverId payload:string = PushReceiverId;
@ -4616,7 +4616,7 @@ sendCustomRequest method:string parameters:string = CustomRequestResult;
answerCustomQuery custom_query_id:int64 data:string = Ok;
//@description Succeeds after a specified amount of time has passed. Can be called before authorization. Can be called before initialization @seconds Number of seconds before the function returns
//@description Succeeds after a specified amount of time has passed. Can be called before initialization @seconds Number of seconds before the function returns
setAlarm seconds:double = Ok;
@ -4662,30 +4662,30 @@ getProxyLink proxy_id:int32 = Text;
pingProxy proxy_id:int32 = Seconds;
//@description Sets new log stream for internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously @log_stream New log stream
//@description Sets new log stream for internal logging of TDLib. Can be called synchronously @log_stream New log stream
setLogStream log_stream:LogStream = Ok;
//@description Returns information about currently used log stream for internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously
//@description Returns information about currently used log stream for internal logging of TDLib. Can be called synchronously
getLogStream = LogStream;
//@description Sets the verbosity level of the internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously
//@description Sets the verbosity level of the internal logging of TDLib. Can be called synchronously
//@new_verbosity_level New value of the verbosity level for logging. Value 0 corresponds to fatal errors, value 1 corresponds to errors, value 2 corresponds to warnings and debug warnings, value 3 corresponds to informational, value 4 corresponds to debug, value 5 corresponds to verbose debug, value greater than 5 and up to 1023 can be used to enable even more logging
setLogVerbosityLevel new_verbosity_level:int32 = Ok;
//@description Returns current verbosity level of the internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously
//@description Returns current verbosity level of the internal logging of TDLib. Can be called synchronously
getLogVerbosityLevel = LogVerbosityLevel;
//@description Returns list of available TDLib internal log tags, for example, ["actor", "binlog", "connections", "notifications", "proxy"]. This is an offline method. Can be called before authorization. Can be called synchronously
//@description Returns list of available TDLib internal log tags, for example, ["actor", "binlog", "connections", "notifications", "proxy"]. Can be called synchronously
getLogTags = LogTags;
//@description Sets the verbosity level for a specified TDLib internal log tag. This is an offline method. Can be called before authorization. Can be called synchronously
//@description Sets the verbosity level for a specified TDLib internal log tag. Can be called synchronously
//@tag Logging tag to change verbosity level @new_verbosity_level New verbosity level; 1-1024
setLogTagVerbosityLevel tag:string new_verbosity_level:int32 = Ok;
//@description Returns current verbosity level for a specified TDLib internal log tag. This is an offline method. Can be called before authorization. Can be called synchronously @tag Logging tag to change verbosity level
//@description Returns current verbosity level for a specified TDLib internal log tag. Can be called synchronously @tag Logging tag to change verbosity level
getLogTagVerbosityLevel tag:string = LogVerbosityLevel;
//@description Adds a message to TDLib internal log. This is an offline method. Can be called before authorization. Can be called synchronously
//@description Adds a message to TDLib internal log. Can be called synchronously
//@verbosity_level The minimum verbosity level needed for the message to be logged, 0-1023 @text Text of a message to log
addLogMessage verbosity_level:int32 text:string = Ok;
@ -4715,5 +4715,5 @@ testProxy server:string port:int32 type:ProxyType dc_id:int32 timeout:double = O
testGetDifference = Ok;
//@description Does nothing and ensures that the Update object is used; for testing only. This is an offline method. Can be called before authorization
testUseUpdate = Update;
//@description Returns the specified error and ensures that the Error object is used; for testing only. This is an offline method. Can be called before authorization. Can be called synchronously @error The error to be returned
//@description Returns the specified error and ensures that the Error object is used; for testing only. Can be called synchronously @error The error to be returned
testReturnError error:error = Error;

View File

@ -67,7 +67,7 @@ class TdReceiver {
MultiClient::Response receive(double timeout) {
if (!responses_.empty()) {
auto result = std::move(responses_.front());
responses_.pop_front();
responses_.pop();
return result;
}
return {0, 0, nullptr};
@ -79,17 +79,17 @@ class TdReceiver {
Callback(MultiClient::ClientId client_id, TdReceiver *impl) : client_id_(client_id), impl_(impl) {
}
void on_result(uint64 id, td_api::object_ptr<td_api::Object> result) override {
impl_->responses_.push_back({client_id_, id, std::move(result)});
impl_->responses_.push({client_id_, id, std::move(result)});
}
void on_error(uint64 id, td_api::object_ptr<td_api::error> error) override {
impl_->responses_.push_back({client_id_, id, std::move(error)});
impl_->responses_.push({client_id_, id, std::move(error)});
}
Callback(const Callback &) = delete;
Callback &operator=(const Callback &) = delete;
Callback(Callback &&) = delete;
Callback &operator=(Callback &&) = delete;
~Callback() override {
impl_->responses_.push_back({client_id_, 0, nullptr});
impl_->responses_.push({client_id_, 0, nullptr});
}
private:
@ -153,7 +153,6 @@ class MultiClient::Impl final {
return response;
}
Impl() = default;
Impl(const Impl &) = delete;
Impl &operator=(const Impl &) = delete;
Impl(Impl &&) = delete;

View File

@ -161,6 +161,7 @@ class MultiClient final {
MultiClient &operator=(MultiClient &&other);
private:
friend class Client;
class Impl;
std::unique_ptr<Impl> impl_;
};

View File

@ -1055,7 +1055,7 @@ void ConfigManager::request_config_from_dc_impl(DcId dc_id) {
config_sent_cnt_++;
auto query = G()->net_query_creator().create_unauth(telegram_api::help_getConfig(), dc_id);
query->total_timeout_limit_ = 60 * 60 * 24;
G()->net_query_dispatcher().dispatch_with_callback(std::move(query), actor_shared(this, 0));
G()->net_query_dispatcher().dispatch_with_callback(std::move(query), actor_shared(this, 8));
}
void ConfigManager::do_set_ignore_sensitive_content_restrictions(bool ignore_sensitive_content_restrictions) {
@ -1276,7 +1276,7 @@ void ConfigManager::on_result(NetQueryPtr res) {
return;
}
CHECK(token == 0);
CHECK(token == 8);
CHECK(config_sent_cnt_ > 0);
config_sent_cnt_--;
auto r_config = fetch_result<telegram_api::help_getConfig>(std::move(res));

View File

@ -62,6 +62,7 @@ void DelayDispatcher::tear_down() {
query.net_query->set_error(Status::Error(500, "Request aborted"));
send_closure(std::move(query.callback), &NetQueryCallback::on_result, std::move(query.net_query));
}
parent_.reset();
}
} // namespace td

View File

@ -18,7 +18,8 @@ namespace td {
class DelayDispatcher : public Actor {
public:
explicit DelayDispatcher(double default_delay) : default_delay_(default_delay) {
DelayDispatcher(double default_delay, ActorShared<> parent)
: default_delay_(default_delay), parent_(std::move(parent)) {
}
void send_with_callback(NetQueryPtr query, ActorShared<NetQueryCallback> callback);
@ -35,6 +36,7 @@ class DelayDispatcher : public Actor {
std::queue<Query> queue_;
Timestamp wakeup_at_;
double default_delay_;
ActorShared<> parent_;
void loop() override;
void tear_down() override;

View File

@ -8116,7 +8116,8 @@ void MessagesManager::after_get_difference() {
auto *list = get_dialog_list(dialog_list_id);
CHECK(list != nullptr);
if (!list->is_dialog_unread_count_inited_) {
get_dialogs(dialog_list_id, MIN_DIALOG_DATE, 1, false, PromiseCreator::lambda([dialog_list_id](Unit) {
get_dialogs(dialog_list_id, MIN_DIALOG_DATE, static_cast<int32>(list->pinned_dialogs_.size() + 2), false,
PromiseCreator::lambda([dialog_list_id](Unit) {
if (!G()->close_flag()) {
LOG(INFO) << "Inited total chat count in " << dialog_list_id;
}
@ -10862,6 +10863,7 @@ void MessagesManager::start_up() {
}
void MessagesManager::create_folders() {
LOG(INFO) << "Create folders";
dialog_folders_[FolderId::main()].folder_id = FolderId::main();
dialog_folders_[FolderId::archive()].folder_id = FolderId::archive();
@ -10879,15 +10881,16 @@ void MessagesManager::init() {
start_time_ = Time::now();
bool is_authorized_user = td_->auth_manager_->is_authorized() && !td_->auth_manager_->is_bot();
if (is_authorized_user) {
bool is_authorized = td_->auth_manager_->is_authorized();
bool was_authorized_user = td_->auth_manager_->was_authorized() && !td_->auth_manager_->is_bot();
if (was_authorized_user) {
create_folders(); // ensure that Main and Archive dialog lists are created
}
if (td_->auth_manager_->is_authorized() && td_->auth_manager_->is_bot()) {
if (is_authorized && td_->auth_manager_->is_bot()) {
disable_get_dialog_filter_ = true;
}
if (is_authorized_user) {
if (was_authorized_user) {
vector<NotificationSettingsScope> scopes{NotificationSettingsScope::Private, NotificationSettingsScope::Group,
NotificationSettingsScope::Channel};
for (auto scope : scopes) {
@ -10905,7 +10908,7 @@ void MessagesManager::init() {
send_closure(G()->td(), &Td::send_update, get_update_scope_notification_settings_object(scope));
}
}
if (!channels_notification_settings_.is_synchronized) {
if (!channels_notification_settings_.is_synchronized && is_authorized) {
channels_notification_settings_ = chats_notification_settings_;
channels_notification_settings_.disable_pinned_message_notifications = false;
channels_notification_settings_.disable_mention_notifications = false;
@ -10915,7 +10918,7 @@ void MessagesManager::init() {
}
G()->td_db()->get_binlog_pmc()->erase("nsfac");
if (is_authorized_user) {
if (was_authorized_user) {
auto dialog_filters = G()->td_db()->get_binlog_pmc()->get("dialog_filters");
if (!dialog_filters.empty()) {
DialogFiltersLogEvent log_event;
@ -10939,7 +10942,7 @@ void MessagesManager::init() {
send_update_chat_filters(); // always send updateChatFilters
}
if (G()->parameters().use_message_db && is_authorized_user) {
if (G()->parameters().use_message_db && was_authorized_user) {
// erase old keys
G()->td_db()->get_binlog_pmc()->erase("last_server_dialog_date");
G()->td_db()->get_binlog_pmc()->erase("unread_message_count");
@ -11114,7 +11117,7 @@ void MessagesManager::init() {
load_calls_db_state();
if (is_authorized_user) {
if (was_authorized_user && is_authorized) {
if (need_synchronize_dialog_filters()) {
reload_dialog_filters();
} else {
@ -24948,6 +24951,11 @@ void MessagesManager::send_update_new_chat(Dialog *d, int64 real_order) {
}
void MessagesManager::send_update_chat_draft_message(const Dialog *d) {
if (td_->auth_manager_->is_bot()) {
// just in case
return;
}
CHECK(d != nullptr);
LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_draft_message";
on_dialog_updated(d->dialog_id, "send_update_chat_draft_message");
@ -24964,9 +24972,16 @@ void MessagesManager::send_update_chat_last_message(Dialog *d, const char *sourc
}
void MessagesManager::send_update_chat_last_message_impl(const Dialog *d, const char *source) const {
if (td_->auth_manager_->is_bot()) {
return;
}
//TDLIGHT-PATCH-START
if (!G()->shared_config().get_option_boolean("ignore_update_chat_last_message")) {
return;
}
//TDLIGHT-PATCH-END
CHECK(d != nullptr);
LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_last_message from "
<< source;
@ -24975,9 +24990,6 @@ void MessagesManager::send_update_chat_last_message_impl(const Dialog *d, const
d->dialog_id.get(), get_message_object(d->dialog_id, get_message(d, d->last_message_id)),
get_chat_positions_object(d));
send_closure(G()->td(), &Td::send_update, std::move(update));
//TDLIGHT-PATCH-START
}
//TDLIGHT-PATCH-END
}
void MessagesManager::send_update_chat_filters() {
@ -30899,9 +30911,18 @@ bool MessagesManager::set_dialog_order(Dialog *d, int64 new_order, bool need_sen
DialogDate old_date(d->order, dialog_id);
DialogDate new_date(new_order, dialog_id);
auto &folder = *get_dialog_folder(d->folder_id);
if (old_date == new_date) {
LOG(INFO) << "Order of " << d->dialog_id << " is still " << new_order << " from " << source;
LOG(INFO) << "Order of " << d->dialog_id << " from " << d->folder_id << " is still " << new_order << " from "
<< source;
} else {
LOG(INFO) << "Update order of " << dialog_id << " from " << d->folder_id << " from " << d->order << " to "
<< new_order << " from " << source;
}
auto folder_ptr = get_dialog_folder(d->folder_id);
CHECK(folder_ptr != nullptr);
auto &folder = *folder_ptr;
if (old_date == new_date) {
if (new_order == DEFAULT_ORDER) {
// first addition of a new left dialog
if (folder.ordered_dialogs_.insert(new_date).second) {
@ -30916,8 +30937,6 @@ bool MessagesManager::set_dialog_order(Dialog *d, int64 new_order, bool need_sen
return false;
}
LOG(INFO) << "Update order of " << dialog_id << " from " << d->order << " to " << new_order << " from " << source;
auto dialog_positions = get_dialog_positions(d);
if (folder.ordered_dialogs_.erase(old_date) == 0) {
@ -31572,6 +31591,9 @@ MessagesManager::DialogList &MessagesManager::add_dialog_list(DialogListId dialo
if (dialog_list_id.is_folder() && dialog_list_id.get_folder_id() != FolderId::archive()) {
dialog_list_id = DialogListId(FolderId::main());
}
if (dialog_lists_.find(dialog_list_id) == dialog_lists_.end()) {
LOG(INFO) << "Create " << dialog_list_id;
}
auto &list = dialog_lists_[dialog_list_id];
list.dialog_list_id = dialog_list_id;
return list;

View File

@ -2818,7 +2818,7 @@ class MessagesManager : public Actor {
KHeap<double> ttl_heap_;
Slot ttl_slot_;
enum YieldType : int32 { None, Ttl, TtlDb }; // None must be first
enum YieldType : int32 { None, TtlDb }; // None must be first
int32 ttl_db_expires_from_;
int32 ttl_db_expires_till_;
bool ttl_db_has_query_;

View File

@ -3378,6 +3378,8 @@ void Td::request(uint64 id, tl_object_ptr<td_api::Function> function) {
return send_result(id, get_fake_authorization_state_object());
case td_api::getCurrentState::ID: {
vector<td_api::object_ptr<td_api::Update>> updates;
updates.push_back(td_api::make_object<td_api::updateOption>(
"version", td_api::make_object<td_api::optionValueString>(TDLIB_VERSION)));
updates.push_back(td_api::make_object<td_api::updateAuthorizationState>(get_fake_authorization_state_object()));
// send response synchronously to prevent "Request aborted"
return send_result(id, td_api::make_object<td_api::updates>(std::move(updates)));

View File

@ -158,7 +158,8 @@ void FileLoadManager::update_local_file_location(QueryId id, const LocalFileLoca
}
send_closure(node->loader_, &FileLoaderActor::update_local_file_location, local);
}
void FileLoadManager::update_download_offset(QueryId id, int64 offset) {
void FileLoadManager::update_downloaded_part(QueryId id, int64 offset, int64 limit) {
if (stop_flag_) {
return;
}
@ -170,22 +171,9 @@ void FileLoadManager::update_download_offset(QueryId id, int64 offset) {
if (node == nullptr) {
return;
}
send_closure(node->loader_, &FileLoaderActor::update_download_offset, offset);
}
void FileLoadManager::update_download_limit(QueryId id, int64 limit) {
if (stop_flag_) {
return;
}
auto it = query_id_to_node_id_.find(id);
if (it == query_id_to_node_id_.end()) {
return;
}
auto node = nodes_container_.get(it->second);
if (node == nullptr) {
return;
}
send_closure(node->loader_, &FileLoaderActor::update_download_limit, limit);
send_closure(node->loader_, &FileLoaderActor::update_downloaded_part, offset, limit);
}
void FileLoadManager::hangup() {
nodes_container_.for_each([](auto id, auto &node) { node.loader_.reset(); });
stop_flag_ = true;

View File

@ -58,8 +58,7 @@ class FileLoadManager final : public Actor {
void from_bytes(QueryId id, FileType type, BufferSlice bytes, string name);
void cancel(QueryId id);
void update_local_file_location(QueryId id, const LocalFileLocation &local);
void update_download_offset(QueryId id, int64 offset);
void update_download_limit(QueryId id, int64 limit);
void update_downloaded_part(QueryId id, int64 offset, int64 limit);
void get_content(const FullLocalFileLocation &local_location, Promise<BufferSlice> promise);
private:

View File

@ -40,12 +40,15 @@ void FileLoader::set_ordered_flag(bool flag) {
size_t FileLoader::get_part_size() const {
return parts_manager_.get_part_size();
}
void FileLoader::hangup() {
// if (!stop_flag_) {
// stop_flag_ = true;
// on_error(Status::Error("Cancelled"));
//}
stop();
delay_dispatcher_.reset();
}
void FileLoader::hangup_shared() {
if (get_link_token() == 1) {
stop();
}
}
void FileLoader::update_local_file_location(const LocalFileLocation &local) {
@ -65,24 +68,27 @@ void FileLoader::update_local_file_location(const LocalFileLocation &local) {
loop();
}
void FileLoader::update_download_offset(int64 offset) {
void FileLoader::update_downloaded_part(int64 offset, int64 limit) {
if (parts_manager_.get_streaming_offset() != offset) {
parts_manager_.set_streaming_offset(offset);
//TODO: cancel only some queries
auto begin_part_id = parts_manager_.set_streaming_offset(offset, limit);
auto new_end_part_id = limit <= 0 ? parts_manager_.get_part_count()
: static_cast<int32>((offset + limit - 1) / parts_manager_.get_part_size()) + 1;
auto max_parts = static_cast<int32>(ResourceManager::MAX_RESOURCE_LIMIT / parts_manager_.get_part_size());
auto end_part_id = begin_part_id + td::min(max_parts, new_end_part_id - begin_part_id);
VLOG(files) << "Protect parts " << begin_part_id << " ... " << end_part_id - 1;
for (auto &it : part_map_) {
it.second.second.reset(); // cancel_query(it.second.second);
if (!it.second.second.empty() && !(begin_part_id <= it.second.first.id && it.second.first.id < end_part_id)) {
VLOG(files) << "Cancel part " << it.second.first.id;
it.second.second.reset(); // cancel_query(it.second.second);
}
}
} else {
parts_manager_.set_streaming_limit(limit);
}
update_estimated_limit();
loop();
}
void FileLoader::update_download_limit(int64 limit) {
parts_manager_.set_streaming_limit(limit);
update_estimated_limit();
loop();
}
void FileLoader::start_up() {
auto r_file_info = init();
if (r_file_info.is_error()) {
@ -120,13 +126,12 @@ void FileLoader::start_up() {
if (file_info.only_check) {
parts_manager_.set_checked_prefix_size(0);
}
parts_manager_.set_streaming_offset(file_info.offset);
parts_manager_.set_streaming_limit(file_info.limit);
parts_manager_.set_streaming_offset(file_info.offset, file_info.limit);
if (ordered_flag_) {
ordered_parts_ = OrderedEventsProcessor<std::pair<Part, NetQueryPtr>>(parts_manager_.get_ready_prefix_count());
}
if (file_info.need_delay) {
delay_dispatcher_ = create_actor<DelayDispatcher>("DelayDispatcher", 0.003);
delay_dispatcher_ = create_actor<DelayDispatcher>("DelayDispatcher", 0.003, actor_shared(this, 1));
next_delay_ = 0.05;
}
resource_state_.set_unit_size(parts_manager_.get_part_size());
@ -149,6 +154,7 @@ void FileLoader::loop() {
return;
}
}
Status FileLoader::do_loop() {
TRY_RESULT(check_info,
check_loop(parts_manager_.get_checked_prefix_size(), parts_manager_.get_unchecked_ready_prefix_size(),
@ -210,6 +216,7 @@ Status FileLoader::do_loop() {
if (delay_dispatcher_.empty()) {
G()->net_query_dispatcher().dispatch_with_callback(std::move(query), std::move(callback));
} else {
query->debug("sent to DelayDispatcher");
send_closure(delay_dispatcher_, &DelayDispatcher::send_with_callback_and_delay, std::move(query),
std::move(callback), next_delay_);
next_delay_ = max(next_delay_ * 0.8, 0.003);
@ -223,8 +230,11 @@ void FileLoader::tear_down() {
it.second.second.reset(); // cancel_query(it.second.second);
}
ordered_parts_.clear([](auto &&part) { part.second->clear(); });
send_closure(std::move(delay_dispatcher_), &DelayDispatcher::close_silent);
if (!delay_dispatcher_.empty()) {
send_closure(std::move(delay_dispatcher_), &DelayDispatcher::close_silent);
}
}
void FileLoader::update_estimated_limit() {
if (stop_flag_) {
return;
@ -259,6 +269,7 @@ void FileLoader::on_result(NetQueryPtr query) {
Part part = it->second.first;
it->second.second.release();
CHECK(query->is_ready());
part_map_.erase(it);
bool next = false;
auto status = [&] {

View File

@ -8,6 +8,7 @@
#include "td/actor/actor.h"
#include "td/telegram/DelayDispatcher.h"
#include "td/telegram/files/FileLoaderActor.h"
#include "td/telegram/files/FileLocation.h"
#include "td/telegram/files/PartsManager.h"
@ -15,8 +16,6 @@
#include "td/telegram/files/ResourceState.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/DelayDispatcher.h"
#include "td/utils/OrderedEventsProcessor.h"
#include "td/utils/Status.h"
@ -39,8 +38,7 @@ class FileLoader : public FileLoaderActor {
void update_resources(const ResourceState &other) override;
void update_local_file_location(const LocalFileLocation &local) override;
void update_download_offset(int64 offset) override;
void update_download_limit(int64 limit) override;
void update_downloaded_part(int64 offset, int64 limit) override;
protected:
void set_ordered_flag(bool flag);
@ -130,6 +128,7 @@ class FileLoader : public FileLoaderActor {
void loop() override;
Status do_loop();
void hangup() override;
void hangup_shared() override;
void tear_down() override;
void update_estimated_limit();

View File

@ -26,9 +26,7 @@ class FileLoaderActor : public NetQueryCallback {
// TODO: existence of these three functions is a dirty hack. Refactoring is highly appreciated
virtual void update_local_file_location(const LocalFileLocation &local) {
}
virtual void update_download_offset(int64 offset) {
}
virtual void update_download_limit(int64 limit) {
virtual void update_downloaded_part(int64 offset, int64 limit) {
}
};

View File

@ -2287,13 +2287,17 @@ void FileManager::run_download(FileNodePtr node) {
LOG(INFO) << "Update download offset and limits of file " << node->main_file_id_;
CHECK(node->download_id_ != 0);
send_closure(file_load_manager_, &FileLoadManager::update_priority, node->download_id_, priority);
if (need_update_limit) {
if (need_update_limit || need_update_offset) {
auto download_offset = node->download_offset_;
auto download_limit = node->download_limit_;
send_closure(file_load_manager_, &FileLoadManager::update_download_limit, node->download_id_, download_limit);
}
if (need_update_offset) {
auto download_offset = file_view.is_encrypted_any() ? 0 : node->download_offset_;
send_closure(file_load_manager_, &FileLoadManager::update_download_offset, node->download_id_, download_offset);
if (file_view.is_encrypted_any()) {
CHECK(download_offset <= MAX_FILE_SIZE);
CHECK(download_limit <= std::numeric_limits<int32>::max());
download_limit += download_offset;
download_offset = 0;
}
send_closure(file_load_manager_, &FileLoadManager::update_downloaded_part, node->download_id_, download_offset,
download_limit);
}
return;
}
@ -2353,8 +2357,14 @@ void FileManager::run_download(FileNodePtr node) {
LOG(INFO) << "Run download of file " << file_id << " of size " << node->size_ << " from "
<< node->remote_.full.value() << " with suggested name " << node->suggested_name() << " and encyption key "
<< node->encryption_key_;
auto download_offset = file_view.is_encrypted_any() ? 0 : node->download_offset_;
auto download_offset = node->download_offset_;
auto download_limit = node->download_limit_;
if (file_view.is_encrypted_any()) {
CHECK(download_offset <= MAX_FILE_SIZE);
CHECK(download_limit <= std::numeric_limits<int32>::max());
download_limit += download_offset;
download_offset = 0;
}
send_closure(file_load_manager_, &FileLoadManager::download, id, node->remote_.full.value(), node->local_,
node->size_, node->suggested_name(), node->encryption_key_, node->can_search_locally_, download_offset,
download_limit, priority);

View File

@ -29,22 +29,27 @@ Status PartsManager::init_known_prefix(int64 known_prefix, size_t part_size, con
return init_no_size(part_size, ready_parts);
}
void PartsManager::set_streaming_offset(int64 offset) {
SCOPE_EXIT {
set_streaming_limit(streaming_limit_);
int32 PartsManager::set_streaming_offset(int64 offset, int64 limit) {
auto finish = [&] {
set_streaming_limit(limit);
update_first_not_ready_part();
return first_streaming_not_ready_part_;
};
if (offset < 0 || need_check_ || (!unknown_size_flag_ && get_size() < offset)) {
streaming_offset_ = 0;
LOG_IF(ERROR, offset != 0) << "Ignore streaming_offset " << offset << ", need_check_ = " << need_check_
<< ", unknown_size_flag_ = " << unknown_size_flag_ << ", size = " << get_size();
return;
return finish();
}
auto part_i = offset / part_size_;
if (use_part_count_limit_ && part_i >= MAX_PART_COUNT) {
streaming_offset_ = 0;
LOG(ERROR) << "Ignore streaming_offset " << offset << " in part " << part_i;
return;
return finish();
}
streaming_offset_ = offset;
@ -54,6 +59,12 @@ void PartsManager::set_streaming_offset(int64 offset) {
part_count_ = first_streaming_empty_part_;
part_status_.resize(part_count_, PartStatus::Empty);
}
return finish();
}
int32 PartsManager::get_pending_count() const {
return pending_count_;
}
void PartsManager::set_streaming_limit(int64 limit) {
@ -215,6 +226,7 @@ string PartsManager::get_bitmask() {
}
bool PartsManager::is_part_in_streaming_limit(int part_i) const {
CHECK(part_i < part_count_);
auto offset_begin = static_cast<int64>(part_i) * static_cast<int64>(get_part_size());
auto offset_end = offset_begin + static_cast<int64>(get_part(part_i).size);
@ -253,6 +265,9 @@ bool PartsManager::is_streaming_limit_reached() {
if (!unknown_size_flag_ && part_i == part_count_) {
part_i = first_not_ready_part_;
}
if (part_i == part_count_) {
return false;
}
return !is_part_in_streaming_limit(part_i);
}
@ -487,7 +502,7 @@ Status PartsManager::init_common(const std::vector<int> &ready_parts) {
void PartsManager::set_need_check() {
need_check_ = true;
set_streaming_offset(0);
set_streaming_offset(0, 0);
}
void PartsManager::set_checked_prefix_size(int64 size) {

View File

@ -35,7 +35,7 @@ class PartsManager {
Status set_known_prefix(size_t size, bool is_ready);
void set_need_check();
void set_checked_prefix_size(int64 size);
void set_streaming_offset(int64 offset);
int32 set_streaming_offset(int64 offset, int64 limit);
void set_streaming_limit(int64 limit);
int64 get_checked_prefix_size() const;
@ -51,6 +51,7 @@ class PartsManager {
int32 get_ready_prefix_count();
int64 get_streaming_offset() const;
string get_bitmask();
int32 get_pending_count() const;
private:
static constexpr int MAX_PART_COUNT = 4000;

View File

@ -132,7 +132,7 @@ void ResourceManager::loop() {
return;
}
auto active_limit = resource_state_.active_limit();
resource_state_.update_limit(2 * 1024 * (1 << 10) - active_limit);
resource_state_.update_limit(MAX_RESOURCE_LIMIT - active_limit);
LOG(INFO) << tag("unused", resource_state_.unused());
if (mode_ == Mode::Greedy) {

View File

@ -28,6 +28,8 @@ class ResourceManager : public Actor {
void register_worker(ActorShared<FileLoaderActor> callback, int8 priority);
static constexpr int64 MAX_RESOURCE_LIMIT = 1 << 21;
private:
Mode mode_;
using NodeId = uint64;

View File

@ -72,7 +72,7 @@ class Slot final : public Actor {
}
ActorShared<> get_signal_new() {
register_if_empty();
return actor_shared();
return actor_shared(this);
}
private:

View File

@ -101,7 +101,6 @@ class Actor : public ObserverBase {
template <class SelfT>
ActorId<SelfT> actor_id(SelfT *self);
ActorShared<> actor_shared();
template <class SelfT>
ActorShared<SelfT> actor_shared(SelfT *self, uint64 id = static_cast<uint64>(-1));

View File

@ -125,12 +125,11 @@ ActorId<SelfT> Actor::actor_id(SelfT *self) {
return ActorId<SelfT>(info_.get_weak());
}
inline ActorShared<> Actor::actor_shared() {
return actor_shared(this);
}
template <class SelfT>
ActorShared<SelfT> Actor::actor_shared(SelfT *self, uint64 id) {
CHECK(static_cast<Actor *>(self) == this);
// TODO replace with CHECK
LOG_IF(ERROR, id == 0) << "ActorShared with token 0 must not be created";
return ActorShared<SelfT>(actor_id(self), id);
}

View File

@ -353,7 +353,7 @@ class SendToDead : public Actor {
set_timeout_in(Random::fast_uint32() % 3 * 0.001);
if (ttl_ != 0) {
child_ = create_actor_on_scheduler<Parent>(
"Child", Random::fast_uint32() % Scheduler::instance()->sched_count(), actor_shared(), ttl_ - 1);
"Child", Random::fast_uint32() % Scheduler::instance()->sched_count(), actor_shared(this), ttl_ - 1);
}
}
void timeout_expired() override {
@ -376,7 +376,7 @@ class SendToDead : public Actor {
ActorShared<> create_reference() {
ref_cnt_++;
return actor_shared();
return actor_shared(this);
}
void hangup_shared() override {
ref_cnt_--;

View File

@ -482,7 +482,7 @@ class LaterMasterActor : public Actor {
std::vector<ActorOwn<LaterSlave>> children_;
void start_up() override {
for (int i = 0; i < cnt_; i++) {
children_.push_back(create_actor<LaterSlave>("B", actor_shared()));
children_.push_back(create_actor<LaterSlave>("B", actor_shared(this)));
}
yield();
}

View File

@ -186,11 +186,7 @@ class TQueueImpl : public TQueue {
if (it == queues_.end()) {
return EventId();
}
auto &q = it->second;
if (q.events.empty()) {
return q.tail_id;
}
return q.events.begin()->first;
return get_queue_head(it->second);
}
EventId get_tail(QueueId queue_id) const override {
@ -227,7 +223,7 @@ class TQueueImpl : public TQueue {
if (from_id.value() > q.tail_id.value() + 10) {
return Status::Error("Specified from_id is in the future");
}
if (from_id.value() < q.tail_id.value() - static_cast<int32>(MAX_QUEUE_EVENTS) * 2) {
if (from_id.value() < get_queue_head(q).value() - static_cast<int32>(MAX_QUEUE_EVENTS)) {
return Status::Error("Specified from_id is in the past");
}
@ -267,7 +263,7 @@ class TQueueImpl : public TQueue {
return deleted_events;
}
size_t get_size(QueueId queue_id) override {
size_t get_size(QueueId queue_id) const override {
auto it = queues_.find(queue_id);
if (it == queues_.end()) {
return 0;
@ -294,7 +290,14 @@ class TQueueImpl : public TQueue {
std::set<std::pair<int32, QueueId>> queue_gc_at_;
unique_ptr<StorageCallback> callback_;
static size_t get_size(Queue &q) {
static EventId get_queue_head(const Queue &q) {
if (q.events.empty()) {
return q.tail_id;
}
return q.events.begin()->first;
}
static size_t get_size(const Queue &q) {
if (q.events.empty()) {
return 0;
}

View File

@ -111,7 +111,7 @@ class TQueue {
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 size_t get_size(QueueId queue_id) const = 0;
virtual int64 run_gc(int32 unix_time_now) = 0;
virtual void close(Promise<> promise) = 0;

View File

@ -39,9 +39,22 @@ class StringBuilder {
return error_flag_;
}
StringBuilder &operator<<(const char *str) {
template <class T>
std::enable_if_t<std::is_same<char *, std::remove_const_t<T>>::value, StringBuilder> &operator<<(T str) {
return *this << Slice(str);
}
template <class T>
std::enable_if_t<std::is_same<const char *, std::remove_const_t<T>>::value, StringBuilder> &operator<<(T str) {
return *this << Slice(str);
}
template <size_t N>
StringBuilder &operator<<(char (&str)[N]) = delete;
template <size_t N>
StringBuilder &operator<<(const char (&str)[N]) {
return *this << Slice(str, N - 1);
}
StringBuilder &operator<<(const wchar_t *str) = delete;
@ -94,11 +107,6 @@ class StringBuilder {
StringBuilder &operator<<(const void *ptr);
template <class T>
StringBuilder &operator<<(const T *ptr) {
return *this << static_cast<const void *>(ptr);
}
private:
char *begin_ptr_;
char *current_ptr_;

View File

@ -459,7 +459,7 @@ class Socks5TestActor : public Actor {
return promise.set_error(Status::Error(PSTRING() << "Failed to open socket: " << r_socket.error()));
}
create_actor<Socks5>("socks5", r_socket.move_as_ok(), mtproto_ip_address, "", "",
make_unique<Callback>(std::move(promise)), actor_shared())
make_unique<Callback>(std::move(promise)), actor_shared(this))
.release();
}