Remove offset from getChats and respect app-specified limit.

This commit is contained in:
levlam 2021-08-11 15:59:09 +03:00
parent b002c2d4a8
commit d49fdf3261
6 changed files with 136 additions and 97 deletions

View File

@ -116,16 +116,15 @@ class TdExample {
send_query(std::move(send_message), {});
} else if (action == "c") {
std::cout << "Loading chat list..." << std::endl;
send_query(td_api::make_object<td_api::getChats>(nullptr, std::numeric_limits<std::int64_t>::max(), 0, 20),
[this](Object object) {
if (object->get_id() == td_api::error::ID) {
return;
}
auto chats = td::move_tl_object_as<td_api::chats>(object);
for (auto chat_id : chats->chat_ids_) {
std::cout << "[chat_id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl;
}
});
send_query(td_api::make_object<td_api::getChats>(nullptr, 20), [this](Object object) {
if (object->get_id() == td_api::error::ID) {
return;
}
auto chats = td::move_tl_object_as<td_api::chats>(object);
for (auto chat_id : chats->chat_ids_) {
std::cout << "[chat_id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl;
}
});
}
}
}

View File

@ -4027,12 +4027,8 @@ getRemoteFile remote_file_id:string file_type:FileType = File;
//@limit The maximum number of chats to be loaded. For optimal performance, the number of loaded chats is chosen by TDLib and can be smaller than the specified limit, even if the end of the list is not reached
loadChats chat_list:ChatList limit:int32 = Ok;
//@description Returns an ordered list of chats in a chat list. Chats are sorted by the pair (chat.position.order, chat.id) in descending order. (For example, to get a list of chats from the beginning, the offset_order should be equal to a biggest signed 64-bit number 9223372036854775807 == 2^63 - 1).
//-For optimal performance, the number of returned chats is chosen by TDLib
//@chat_list The chat list in which to return chats
//@offset_order Chat order to return chats from @offset_chat_id Chat identifier to return chats from
//@limit The maximum number of chats to be returned. For optimal performance, the number of returned chats is chosen by TDLib and can be smaller than the specified limit, even if the end of the list is not reached
getChats chat_list:ChatList offset_order:int64 offset_chat_id:int53 limit:int32 = Chats;
//@description Returns an ordered list of chats from the beginning of a chat list. For informational purposes only. Use loadChats instead to maintain chat lists @chat_list The chat list in which to return chats @limit The maximum number of chats to be returned
getChats chat_list:ChatList limit:int32 = Chats;
//@description Searches a public chat by its username. Currently only private chats, supergroups and channels can be public. Returns the chat if found; otherwise an error is returned @username Username to be resolved
searchPublicChat username:string = Chat;

View File

@ -9179,7 +9179,7 @@ void MessagesManager::after_get_difference() {
if (!list->is_dialog_unread_count_inited_) {
int32 limit = list->are_pinned_dialogs_inited_ ? static_cast<int32>(list->pinned_dialogs_.size())
: get_pinned_dialogs_limit(dialog_list_id);
get_dialogs(dialog_list_id, MIN_DIALOG_DATE, limit + 2, false,
get_dialogs(dialog_list_id, MIN_DIALOG_DATE, limit + 2, true, false,
PromiseCreator::lambda([dialog_list_id](Result<Unit> result) {
if (!G()->close_flag() && result.is_ok()) {
LOG(INFO) << "Inited total chat count in " << dialog_list_id;
@ -15559,8 +15559,8 @@ Result<DialogDate> MessagesManager::get_dialog_list_last_date(DialogListId dialo
return list_ptr->list_last_dialog_date_;
}
std::pair<int32, vector<DialogId>> MessagesManager::get_dialogs(DialogListId dialog_list_id, DialogDate offset,
int32 limit, bool force, Promise<Unit> &&promise) {
vector<DialogId> MessagesManager::get_dialogs(DialogListId dialog_list_id, DialogDate offset, int32 limit,
bool exact_limit, bool force, Promise<Unit> &&promise) {
CHECK(!td_->auth_manager_->is_bot());
auto *list_ptr = get_dialog_list(dialog_list_id);
@ -15576,14 +15576,10 @@ std::pair<int32, vector<DialogId>> MessagesManager::get_dialogs(DialogListId dia
<< ", are_pinned_dialogs_inited_ = " << list.are_pinned_dialogs_inited_;
if (limit <= 0) {
promise.set_error(Status::Error(3, "Parameter limit in getChats must be positive"));
promise.set_error(Status::Error(3, "Parameter limit must be positive"));
return {};
}
if (limit > MAX_GET_DIALOGS + 2) {
limit = MAX_GET_DIALOGS + 2;
}
vector<DialogId> result;
if (dialog_list_id == DialogListId(FolderId::main()) && sponsored_dialog_id_.is_valid()) {
auto d = get_dialog(sponsored_dialog_id_);
@ -15601,7 +15597,7 @@ std::pair<int32, vector<DialogId>> MessagesManager::get_dialogs(DialogListId dia
if (!list.are_pinned_dialogs_inited_) {
if (limit == 0 || force) {
promise.set_value(Unit());
return {get_dialog_total_count(list), std::move(result)};
return std::move(result);
} else {
if (dialog_list_id.is_folder()) {
auto &folder = *get_dialog_folder(dialog_list_id.get_folder_id());
@ -15635,7 +15631,7 @@ std::pair<int32, vector<DialogId>> MessagesManager::get_dialogs(DialogListId dia
if (!input_dialog_ids.empty()) {
if (limit == 0 || force) {
promise.set_value(Unit());
return {get_dialog_total_count(list), std::move(result)};
return std::move(result);
} else {
td_->create_handler<GetDialogsQuery>(std::move(promise))->send(std::move(input_dialog_ids));
return {};
@ -15705,13 +15701,13 @@ std::pair<int32, vector<DialogId>> MessagesManager::get_dialogs(DialogListId dia
++folder_iterators[best_pos];
}
if (!result.empty() || force || list.list_last_dialog_date_ == MAX_DIALOG_DATE) {
if ((!result.empty() && (!exact_limit || limit == 0)) || force || list.list_last_dialog_date_ == MAX_DIALOG_DATE) {
if (limit > 0 && list.list_last_dialog_date_ != MAX_DIALOG_DATE) {
load_dialog_list(list, limit, Promise<Unit>());
}
promise.set_value(Unit());
return {get_dialog_total_count(list), std::move(result)};
return std::move(result);
} else {
load_dialog_list(list, limit, std::move(promise));
return {};
@ -15720,6 +15716,9 @@ std::pair<int32, vector<DialogId>> MessagesManager::get_dialogs(DialogListId dia
void MessagesManager::load_dialog_list(DialogList &list, int32 limit, Promise<Unit> &&promise) {
CHECK(!td_->auth_manager_->is_bot());
if (limit > MAX_GET_DIALOGS + 2) {
limit = MAX_GET_DIALOGS + 2;
}
bool is_request_sent = false;
for (auto folder_id : get_dialog_list_folder_ids(list)) {
const auto &folder = *get_dialog_folder(folder_id);
@ -15931,6 +15930,79 @@ void MessagesManager::preload_folder_dialog_list(FolderId folder_id) {
}
}
void MessagesManager::get_dialogs_from_list(DialogListId dialog_list_id, int32 limit,
Promise<td_api::object_ptr<td_api::chats>> &&promise) {
CHECK(!td_->auth_manager_->is_bot());
if (get_dialog_list(dialog_list_id) == nullptr) {
return promise.set_error(Status::Error(400, "Chat list not found"));
}
if (limit <= 0) {
return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
}
auto task_id = ++current_get_dialogs_task_id_;
auto &task = get_dialogs_tasks_[task_id];
task.dialog_list_id = dialog_list_id;
task.retry_count = 5;
task.limit = limit;
task.promise = std::move(promise);
get_dialogs_from_list_impl(task_id);
}
void MessagesManager::get_dialogs_from_list_impl(int64 task_id) {
auto task_it = get_dialogs_tasks_.find(task_id);
CHECK(task_it != get_dialogs_tasks_.end());
auto &task = task_it->second;
auto promise = PromiseCreator::lambda([actor_id = actor_id(this), task_id](Result<Unit> &&result) {
send_closure_later(actor_id, &MessagesManager::on_get_dialogs_from_list, task_id, std::move(result));
});
auto dialog_ids = get_dialogs(task.dialog_list_id, MIN_DIALOG_DATE, task.limit, true, false, std::move(promise));
auto &list = *get_dialog_list(task.dialog_list_id);
auto total_count = get_dialog_total_count(list);
LOG(INFO) << "Receive " << dialog_ids.size() << " chats out of " << total_count << "/" << task.limit;
CHECK(dialog_ids.size() <= static_cast<size_t>(total_count));
CHECK(dialog_ids.size() <= static_cast<size_t>(task.limit));
if (dialog_ids.size() == static_cast<size_t>(min(total_count, task.limit)) ||
list.list_last_dialog_date_ == MAX_DIALOG_DATE || task.retry_count == 0) {
auto task_promise = std::move(task.promise);
get_dialogs_tasks_.erase(task_it);
if (!task_promise) {
dialog_ids.clear();
}
return task_promise.set_value(get_chats_object(total_count, dialog_ids));
}
// nor the limit, nor the end of the list were reached; wait for the promise
}
void MessagesManager::on_get_dialogs_from_list(int64 task_id, Result<Unit> &&result) {
auto task_it = get_dialogs_tasks_.find(task_id);
if (task_it == get_dialogs_tasks_.end()) {
// the task has already been completed successfully
return;
}
auto &task = task_it->second;
if (result.is_error()) {
auto task_promise = std::move(task.promise);
get_dialogs_tasks_.erase(task_it);
return task_promise.set_error(result.move_as_error());
}
auto list_ptr = get_dialog_list(task.dialog_list_id);
CHECK(list_ptr != nullptr);
auto &list = *list_ptr;
if (task.last_dialog_date == list.list_last_dialog_date_) {
// no new chats were loaded
task.retry_count--;
} else {
CHECK(task.last_dialog_date < list.list_last_dialog_date_);
task.last_dialog_date = list.list_last_dialog_date_;
task.retry_count = 5;
}
get_dialogs_from_list_impl(task_id);
}
vector<DialogId> MessagesManager::get_pinned_dialog_ids(DialogListId dialog_list_id) const {
CHECK(!td_->auth_manager_->is_bot());
if (dialog_list_id.is_filter()) {
@ -18266,8 +18338,8 @@ void MessagesManager::edit_dialog_filter(unique_ptr<DialogFilter> new_dialog_fil
if (old_list.need_unread_count_recalc_) {
// repair unread count
get_dialogs(dialog_list_id, MIN_DIALOG_DATE, static_cast<int32>(old_list.pinned_dialogs_.size() + 2), false,
Promise<Unit>());
get_dialogs(dialog_list_id, MIN_DIALOG_DATE, static_cast<int32>(old_list.pinned_dialogs_.size() + 2), true,
false, Promise<Unit>());
}
for (auto &promise : load_list_promises) {
@ -29494,7 +29566,7 @@ void MessagesManager::on_update_pinned_dialogs(FolderId folder_id) {
}
// preload all pinned dialogs
get_dialogs(DialogListId(folder_id), {SPONSORED_DIALOG_ORDER - 1, DialogId()},
narrow_cast<int32>(list->pinned_dialogs_.size()), true, Auto());
narrow_cast<int32>(list->pinned_dialogs_.size()), true, true, Auto());
reload_pinned_dialogs(DialogListId(folder_id), Auto());
}
@ -37406,7 +37478,7 @@ bool MessagesManager::load_recently_found_dialogs(Promise<Unit> &promise) {
}
resolve_recently_found_dialogs_multipromise_.get_promise().set_value(Unit());
} else {
get_dialogs(DialogListId(FolderId::main()), MIN_DIALOG_DATE, MAX_GET_DIALOGS, false,
get_dialogs(DialogListId(FolderId::main()), MIN_DIALOG_DATE, MAX_GET_DIALOGS, false, false,
resolve_recently_found_dialogs_multipromise_.get_promise());
td_->contacts_manager_->search_contacts("", 1, resolve_recently_found_dialogs_multipromise_.get_promise());
}

View File

@ -524,8 +524,11 @@ class MessagesManager final : public Actor {
Result<DialogDate> get_dialog_list_last_date(DialogListId dialog_list_id);
std::pair<int32, vector<DialogId>> get_dialogs(DialogListId dialog_list_id, DialogDate offset, int32 limit,
bool force, Promise<Unit> &&promise);
vector<DialogId> get_dialogs(DialogListId dialog_list_id, DialogDate offset, int32 limit, bool exact_limit,
bool force, Promise<Unit> &&promise);
void get_dialogs_from_list(DialogListId dialog_list_id, int32 limit,
Promise<td_api::object_ptr<td_api::chats>> &&promise);
vector<DialogId> search_public_dialogs(const string &query, Promise<Unit> &&promise);
@ -2075,6 +2078,10 @@ class MessagesManager final : public Actor {
void preload_folder_dialog_list(FolderId folder_id);
void get_dialogs_from_list_impl(int64 task_id);
void on_get_dialogs_from_list(int64 task_id, Result<Unit> &&result);
static void invalidate_message_indexes(Dialog *d);
void update_message_count_by_index(Dialog *d, int diff, const Message *m);
@ -3312,6 +3319,17 @@ class MessagesManager final : public Actor {
std::unordered_map<string, DialogId> inaccessible_resolved_usernames_;
std::unordered_set<string> reload_voice_chat_on_search_usernames_;
struct GetDialogsTask {
DialogListId dialog_list_id;
int32 limit;
int32 retry_count;
DialogDate last_dialog_date = MIN_DIALOG_DATE;
Promise<td_api::object_ptr<td_api::chats>> promise;
};
std::unordered_map<int64, GetDialogsTask> get_dialogs_tasks_;
int64 current_get_dialogs_task_id_ = 0;
struct PendingOnGetDialogs {
FolderId folder_id;
vector<tl_object_ptr<telegram_api::Dialog>> dialogs;

View File

@ -791,7 +791,7 @@ class LoadChatsRequest final : public RequestActor<> {
int32 limit_;
void do_run(Promise<Unit> &&promise) final {
td->messages_manager_->get_dialogs(dialog_list_id_, offset_, limit_, get_tries() < 2, std::move(promise));
td->messages_manager_->get_dialogs(dialog_list_id_, offset_, limit_, false, get_tries() < 2, std::move(promise));
}
public:
@ -799,34 +799,10 @@ class LoadChatsRequest final : public RequestActor<> {
: RequestActor(std::move(td), request_id), dialog_list_id_(dialog_list_id), offset_(offset), limit_(limit) {
// 1 for database + 1 for server request + 1 for server request at the end + 1 for return + 1 just in case
set_tries(5);
}
};
class GetChatsRequest final : public RequestActor<> {
DialogListId dialog_list_id_;
DialogDate offset_;
int32 limit_;
std::pair<int32, vector<DialogId>> dialog_ids_;
void do_run(Promise<Unit> &&promise) final {
dialog_ids_ =
td->messages_manager_->get_dialogs(dialog_list_id_, offset_, limit_, get_tries() < 2, std::move(promise));
}
void do_send_result() final {
send_result(MessagesManager::get_chats_object(dialog_ids_));
}
public:
GetChatsRequest(ActorShared<Td> td, uint64 request_id, DialogListId dialog_list_id, int64 offset_order,
int64 offset_dialog_id, int32 limit)
: RequestActor(std::move(td), request_id)
, dialog_list_id_(dialog_list_id)
, offset_(offset_order, DialogId(offset_dialog_id))
, limit_(limit) {
// 1 for database + 1 for server request + 1 for server request at the end + 1 for return + 1 just in case
set_tries(5);
if (limit > 100) {
limit = 100;
}
}
};
@ -5356,8 +5332,8 @@ void Td::on_request(uint64 id, const td_api::loadChats &request) {
void Td::on_request(uint64 id, const td_api::getChats &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetChatsRequest, DialogListId(request.chat_list_), request.offset_order_, request.offset_chat_id_,
request.limit_);
CREATE_REQUEST_PROMISE();
messages_manager_->get_dialogs_from_list(DialogListId(request.chat_list_), request.limit_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::searchPublicChat &request) {

View File

@ -131,22 +131,11 @@ static void reactivate_readline() {
}
static char *command_generator(const char *text, int state) {
static const vector<CSlice> commands{"GetChats",
"GetHistory",
"SetVerbosity",
"SendVideo",
"SearchDocument",
"GetChatMember",
"GetSupergroupAdministrators",
"GetSupergroupBanned",
"GetSupergroupMembers",
"GetFile",
"DownloadFile",
"CancelDownloadFile",
"ImportContacts",
"RemoveContacts",
"CreateSecretChat",
"CreateNewSecretChat"};
static const vector<CSlice> commands{"GetHistory", "SetVerbosity", "SendVideo",
"SearchDocument", "GetChatMember", "GetSupergroupAdministrators",
"GetSupergroupBanned", "GetSupergroupMembers", "GetFile",
"DownloadFile", "CancelDownloadFile", "ImportContacts",
"RemoveContacts", "CreateSecretChat", "CreateNewSecretChat"};
static size_t cmd_i;
if (state == 0) {
cmd_i = 0;
@ -944,7 +933,7 @@ class CliClient final : public Actor {
td_client_ = create_actor<ClientActor>(name, make_unique<TdCallbackImpl>(this, ++generation_), std::move(options));
if (get_chat_list_) {
send_request(td_api::make_object<td_api::getChats>(nullptr, std::numeric_limits<int64>::max(), 0, 10000));
send_request(td_api::make_object<td_api::getChats>(nullptr, 10000));
}
if (disable_network_) {
send_request(td_api::make_object<td_api::setNetworkType>(td_api::make_object<td_api::networkTypeNone>()));
@ -1965,25 +1954,14 @@ class CliClient final : public Actor {
op_not_found_count++;
}
if (op == "gc" || op == "GetChats" || op == "gca" || begins_with(op, "gc-")) {
string limit;
string offset_order_string;
string offset_chat_id;
get_args(args, limit, offset_order_string, offset_chat_id);
int64 offset_order;
if (offset_order_string.empty()) {
offset_order = std::numeric_limits<int64>::max();
} else {
offset_order = to_integer<int64>(offset_order_string);
}
send_request(td_api::make_object<td_api::getChats>(as_chat_list(op), offset_order, as_chat_id(offset_chat_id),
as_limit(limit, 10000)));
if (op == "gc" || op == "gca" || begins_with(op, "gc-")) {
send_request(td_api::make_object<td_api::getChats>(as_chat_list(op), as_limit(args, 10000)));
} else if (op == "lc" || op == "lca" || begins_with(op, "lc-")) {
send_request(td_api::make_object<td_api::loadChats>(as_chat_list(op), as_limit(args, 10000)));
} else if (op == "gctest") {
send_request(td_api::make_object<td_api::getChats>(nullptr, std::numeric_limits<int64>::max(), 0, 1));
send_request(td_api::make_object<td_api::getChats>(nullptr, std::numeric_limits<int64>::max(), 0, 10));
send_request(td_api::make_object<td_api::getChats>(nullptr, std::numeric_limits<int64>::max(), 0, 5));
send_request(td_api::make_object<td_api::getChats>(nullptr, 1));
send_request(td_api::make_object<td_api::getChats>(nullptr, 10));
send_request(td_api::make_object<td_api::getChats>(nullptr, 5));
} else if (op == "gcc" || op == "GetCommonChats") {
string user_id;
string offset_chat_id;