Support multiple chat lists.

GitOrigin-RevId: 8adecce0ddf36bb2408eecc19b7f1fc8856151fc
This commit is contained in:
levlam 2019-08-22 18:24:02 +03:00
parent 7c8cda75a2
commit c1afa189f3
16 changed files with 802 additions and 541 deletions

View File

@ -114,7 +114,7 @@ class TdExample {
send_query(std::move(send_message), {});
} else if (action == "c") {
std::cerr << "Loading chat list..." << std::endl;
send_query(td_api::make_object<td_api::getChats>(std::numeric_limits<std::int64_t>::max(), 0, 20),
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;

View File

@ -231,7 +231,7 @@ namespace TdExample
_gotAuthorization.Reset();
_gotAuthorization.WaitOne();
_client.Send(new TdApi.GetChats(Int64.MaxValue, 0, 100), _defaultHandler); // preload chat list
_client.Send(new TdApi.GetChats(null, Int64.MaxValue, 0, 100), _defaultHandler); // preload main chat list
while (_haveAuthorization)
{
GetCommand();

View File

@ -42,8 +42,8 @@ public final class Example {
private static final ConcurrentMap<Integer, TdApi.SecretChat> secretChats = new ConcurrentHashMap<Integer, TdApi.SecretChat>();
private static final ConcurrentMap<Long, TdApi.Chat> chats = new ConcurrentHashMap<Long, TdApi.Chat>();
private static final NavigableSet<OrderedChat> chatList = new TreeSet<OrderedChat>();
private static boolean haveFullChatList = false;
private static final NavigableSet<OrderedChat> mainChatList = new TreeSet<OrderedChat>();
private static boolean haveFullMainChatList = false;
private static final ConcurrentMap<Integer, TdApi.UserFullInfo> usersFullInfo = new ConcurrentHashMap<Integer, TdApi.UserFullInfo>();
private static final ConcurrentMap<Integer, TdApi.BasicGroupFullInfo> basicGroupsFullInfo = new ConcurrentHashMap<Integer, TdApi.BasicGroupFullInfo>();
@ -72,20 +72,26 @@ public final class Example {
}
private static void setChatOrder(TdApi.Chat chat, long order) {
synchronized (chatList) {
synchronized (mainChatList) {
synchronized (chat) {
if (chat.chatList == null || chat.chatList.getConstructor() != TdApi.ChatListMain.CONSTRUCTOR) {
return;
}
if (chat.order != 0) {
boolean isRemoved = chatList.remove(new OrderedChat(chat.order, chat.id));
boolean isRemoved = mainChatList.remove(new OrderedChat(chat.order, chat.id));
assert isRemoved;
}
chat.order = order;
if (chat.order != 0) {
boolean isAdded = chatList.add(new OrderedChat(chat.order, chat.id));
boolean isAdded = mainChatList.add(new OrderedChat(chat.order, chat.id));
assert isAdded;
}
}
}
}
private static void onAuthorizationStateUpdated(TdApi.AuthorizationState authorizationState) {
if (authorizationState != null) {
@ -201,7 +207,7 @@ public final class Example {
if (commands.length > 1) {
limit = toInt(commands[1]);
}
getChatList(limit);
getMainChatList(limit);
break;
}
case "gc":
@ -232,18 +238,18 @@ public final class Example {
}
}
private static void getChatList(final int limit) {
synchronized (chatList) {
if (!haveFullChatList && limit > chatList.size()) {
private static void getMainChatList(final int limit) {
synchronized (mainChatList) {
if (!haveFullMainChatList && limit > mainChatList.size()) {
// have enough chats in the chat list or chat list is too small
long offsetOrder = Long.MAX_VALUE;
long offsetChatId = 0;
if (!chatList.isEmpty()) {
OrderedChat last = chatList.last();
if (!mainChatList.isEmpty()) {
OrderedChat last = mainChatList.last();
offsetOrder = last.order;
offsetChatId = last.chatId;
}
client.send(new TdApi.GetChats(offsetOrder, offsetChatId, limit - chatList.size()), new Client.ResultHandler() {
client.send(new TdApi.GetChats(new TdApi.ChatListMain(), offsetOrder, offsetChatId, limit - mainChatList.size()), new Client.ResultHandler() {
@Override
public void onResult(TdApi.Object object) {
switch (object.getConstructor()) {
@ -253,12 +259,12 @@ public final class Example {
case TdApi.Chats.CONSTRUCTOR:
long[] chatIds = ((TdApi.Chats) object).chatIds;
if (chatIds.length == 0) {
synchronized (chatList) {
haveFullChatList = true;
synchronized (mainChatList) {
haveFullMainChatList = true;
}
}
// chats had already been received through updates, let's retry request
getChatList(limit);
getMainChatList(limit);
break;
default:
System.err.println("Receive wrong response from TDLib:" + newLine + object);
@ -269,9 +275,9 @@ public final class Example {
}
// have enough chats in the chat list to answer request
java.util.Iterator<OrderedChat> iter = chatList.iterator();
java.util.Iterator<OrderedChat> iter = mainChatList.iterator();
System.out.println();
System.out.println("First " + limit + " chat(s) out of " + chatList.size() + " known chat(s):");
System.out.println("First " + limit + " chat(s) out of " + mainChatList.size() + " known chat(s):");
for (int i = 0; i < limit; i++) {
long chatId = iter.next().chatId;
TdApi.Chat chat = chats.get(chatId);
@ -418,6 +424,17 @@ public final class Example {
}
break;
}
case TdApi.UpdateChatChatList.CONSTRUCTOR: {
TdApi.UpdateChatChatList updateChat = (TdApi.UpdateChatChatList) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (mainChatList) { // to not change Chat.chatList while mainChatList is locked
synchronized (chat) {
assert chat.order == 0; // guaranteed by TDLib
chat.chatList = updateChat.chatList;
}
}
break;
}
case TdApi.UpdateChatLastMessage.CONSTRUCTOR: {
TdApi.UpdateChatLastMessage updateChat = (TdApi.UpdateChatLastMessage) object;
TdApi.Chat chat = chats.get(updateChat.chatId);

View File

@ -604,19 +604,19 @@ chatTypeSupergroup supergroup_id:int32 is_channel:Bool = ChatType;
chatTypeSecret secret_chat_id:int32 user_id:int32 = ChatType;
//@class ChatListType @description Describes a list of chats a chat belongs to
//@class ChatList @description Describes a list of chats
//@description A main list of chats. Can contain ordinary chats and other lists of chats as folders
chatListTypeMain = ChatListType;
chatListMain = ChatList;
//@description A list of chats located at the top of main chat list. Unmuted chats are automatically moved from the Archive to the Main chat list
chatListTypeArchive = ChatListType;
//@description A list of chats usually located at the top of the main chat list. Unmuted chats are automatically moved from the Archive to the Main chat list when a new message arrives
chatListArchive = ChatList;
//@description A chat. (Can be a private chat, basic group, supergroup, or secret chat)
//@id Chat unique identifier
//@type Type of the chat
//@list_type The type of a chat list the chat belongs to; may be null
//@chat_list A chat list to which the chat belongs; may be null
//@title Chat title
//@photo Chat photo; may be null
//@permissions Actions that non-administrator chat members are allowed to take in the chat
@ -638,7 +638,7 @@ chatListTypeArchive = ChatListType;
//@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat
//@draft_message A draft of a message in the chat; may be null
//@client_data Contains client-specific data associated with the chat. (For example, the chat position or local chat notification settings can be stored here.) Persistent if a message database is used
chat id:int53 type:ChatType list_type:ChatListType title:string photo:chatPhoto permissions:chatPermissions last_message:message order:int64 is_pinned:Bool is_marked_as_unread:Bool is_sponsored:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings pinned_message_id:int53 reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
chat id:int53 type:ChatType chat_list:ChatList title:string photo:chatPhoto permissions:chatPermissions last_message:message order:int64 is_pinned:Bool is_marked_as_unread:Bool is_sponsored:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings pinned_message_id:int53 reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
//@description Represents a list of chats @chat_ids List of chat identifiers
chats chat_ids:vector<int53> = Chats;
@ -2605,8 +2605,8 @@ updateMessageMentionRead chat_id:int53 message_id:int53 unread_mention_count:int
//@description A new chat has been loaded/created. This update is guaranteed to come before the chat identifier is returned to the client. The chat field changes will be reported through separate updates @chat The chat
updateNewChat chat:chat = Update;
//@description The list to which the chat belongs was changed @chat_id Chat identifier @list_type The new chat list type; may be null
updateChatListType chat_id:int53 list_type:ChatListType = Update;
//@description The list to which the chat belongs was changed. This update is guaranteed to be sent only when chat.order == 0 and the current or the new chat list is null @chat_id Chat identifier @chat_list The new chat's list; may be null
updateChatChatList chat_id:int53 chat_list:ChatList = Update;
//@description The title of a chat was changed @chat_id Chat identifier @title The new chat title
updateChatTitle chat_id:int53 title:string = Update;
@ -2740,13 +2740,15 @@ updateCall call:call = Update;
//@description Some privacy setting rules have been changed @setting The privacy setting @rules New privacy rules
updateUserPrivacySettingRules setting:UserPrivacySetting rules:userPrivacySettingRules = Update;
//@description Number of unread messages has changed. This update is sent only if a message database is used @unread_count Total number of unread messages @unread_unmuted_count Total number of unread messages in unmuted chats
updateUnreadMessageCount unread_count:int32 unread_unmuted_count:int32 = Update;
//@description Number of unread messages in a chat list has changed. This update is sent only if a message database is used @chat_list The chat list with changed number of unread messages
//@unread_count Total number of unread messages @unread_unmuted_count Total number of unread messages in unmuted chats
updateUnreadMessageCount chat_list:ChatList unread_count:int32 unread_unmuted_count:int32 = Update;
//@description Number of unread chats, i.e. with unread messages or marked as unread, has changed. This update is sent only if a message database is used
//@chat_list The chat list with changed number of unread messages
//@unread_count Total number of unread chats @unread_unmuted_count Total number of unread unmuted chats
//@marked_as_unread_count Total number of chats marked as unread @marked_as_unread_unmuted_count Total number of unmuted chats marked as unread
updateUnreadChatCount unread_count:int32 unread_unmuted_count:int32 marked_as_unread_count:int32 marked_as_unread_unmuted_count:int32 = Update;
updateUnreadChatCount chat_list:ChatList unread_count:int32 unread_unmuted_count:int32 marked_as_unread_count:int32 marked_as_unread_unmuted_count:int32 = Update;
//@description An option changed its value @name The option name @value The new option value
updateOption name:string value:OptionValue = Update;
@ -2987,10 +2989,12 @@ getFile file_id:int32 = File;
//@remote_file_id Remote identifier of the file to get @file_type File type, if known
getRemoteFile remote_file_id:string file_type:FileType = File;
//@description Returns an ordered list of chats. Chats are sorted by the pair (order, chat_id) in decreasing 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 the library @offset_order Chat order to return chats from @offset_chat_id Chat identifier to return chats from
//@description Returns an ordered list of chats in a chat list. Chats are sorted by the pair (order, chat_id) in decreasing 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 the library
//@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. It is possible that fewer chats than the limit are returned even if the end of the list is not reached
getChats offset_order:int64 offset_chat_id:int53 limit:int32 = Chats;
getChats chat_list:ChatList offset_order:int64 offset_chat_id:int53 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;
@ -3341,7 +3345,7 @@ setChatDraftMessage chat_id:int53 draft_message:draftMessage = Ok;
//@description Changes the notification settings of a chat @chat_id Chat identifier @notification_settings New notification settings for the chat
setChatNotificationSettings chat_id:int53 notification_settings:chatNotificationSettings = Ok;
//@description Changes the pinned state of a chat. You can pin up to GetOption("pinned_chat_count_max") non-secret chats and the same number of secret chats @chat_id Chat identifier @is_pinned New value of is_pinned
//@description Changes the pinned state of a chat. You can pin up to GetOption("pinned_chat_count_max")/GetOption("pinned_archived_chat_count_max") non-secret chats and the same number of secret chats in the main/archive chat list @chat_id Chat identifier @is_pinned New value of is_pinned
toggleChatIsPinned chat_id:int53 is_pinned:Bool = Ok;
//@description Changes the marked as unread state of a chat @chat_id Chat identifier @is_marked_as_unread New value of is_marked_as_unread
@ -3407,8 +3411,8 @@ setScopeNotificationSettings scope:NotificationSettingsScope notification_settin
resetAllNotificationSettings = Ok;
//@description Changes the order of pinned chats @chat_ids The new list of pinned chats
setPinnedChats chat_ids:vector<int53> = Ok;
//@description Changes the order of pinned chats @chat_list Chat list in which to change the order of pinned chats @chat_ids The new list of pinned chats
setPinnedChats chat_list:ChatList chat_ids:vector<int53> = Ok;
//@description Downloads a file from the cloud. Download progress and completion of the download will be notified through updateFile updates

Binary file not shown.

View File

@ -1006,6 +1006,7 @@ void ConfigManager::process_config(tl_object_ptr<telegram_api::config> config) {
shared_config.set_option_integer("basic_group_size_max", config->chat_size_max_);
shared_config.set_option_integer("supergroup_size_max", config->megagroup_size_max_);
shared_config.set_option_integer("pinned_chat_count_max", config->pinned_dialogs_count_max_);
shared_config.set_option_integer("pinned_archived_chat_count_max", config->pinned_infolder_count_max_);
if (is_from_main_dc || !shared_config.have_option("expect_blocking")) {
shared_config.set_option_boolean("expect_blocking",
(config->flags_ & telegram_api::config::BLOCKED_MODE_MASK) != 0);

View File

@ -190,7 +190,8 @@ class DialogDbImpl : public DialogDbSyncInterface {
get_last_notification_date(get_notification_group_stmt_, 1));
}
Result<vector<BufferSlice>> get_dialogs(int64 order, DialogId dialog_id, int32 limit) override {
Result<vector<BufferSlice>> get_dialogs(FolderId folder_id, int64 order, DialogId dialog_id, int32 limit) override {
// TODO use folder_id
SCOPE_EXIT {
get_dialogs_stmt_.reset();
};
@ -305,8 +306,9 @@ class DialogDbAsync : public DialogDbAsyncInterface {
void get_dialog(DialogId dialog_id, Promise<BufferSlice> promise) override {
send_closure_later(impl_, &Impl::get_dialog, dialog_id, std::move(promise));
}
void get_dialogs(int64 order, DialogId dialog_id, int32 limit, Promise<vector<BufferSlice>> promise) override {
send_closure_later(impl_, &Impl::get_dialogs, order, dialog_id, limit, std::move(promise));
void get_dialogs(FolderId folder_id, int64 order, DialogId dialog_id, int32 limit,
Promise<vector<BufferSlice>> promise) override {
send_closure_later(impl_, &Impl::get_dialogs, folder_id, order, dialog_id, limit, std::move(promise));
}
void close(Promise<> promise) override {
send_closure_later(impl_, &Impl::close, std::move(promise));
@ -342,9 +344,10 @@ class DialogDbAsync : public DialogDbAsyncInterface {
add_read_query();
promise.set_result(sync_db_->get_dialog(dialog_id));
}
void get_dialogs(int64 order, DialogId dialog_id, int32 limit, Promise<vector<BufferSlice>> promise) {
void get_dialogs(FolderId folder_id, int64 order, DialogId dialog_id, int32 limit,
Promise<vector<BufferSlice>> promise) {
add_read_query();
promise.set_result(sync_db_->get_dialogs(order, dialog_id, limit));
promise.set_result(sync_db_->get_dialogs(folder_id, order, dialog_id, limit));
}
void close(Promise<> promise) {
do_flush();

View File

@ -7,6 +7,7 @@
#pragma once
#include "td/telegram/DialogId.h"
#include "td/telegram/FolderId.h"
#include "td/telegram/NotificationGroupId.h"
#include "td/telegram/NotificationGroupKey.h"
@ -36,7 +37,7 @@ class DialogDbSyncInterface {
virtual Result<BufferSlice> get_dialog(DialogId dialog_id) = 0;
virtual Result<vector<BufferSlice>> get_dialogs(int64 order, DialogId dialog_id, int32 limit) = 0;
virtual Result<vector<BufferSlice>> get_dialogs(FolderId folder_id, int64 order, DialogId dialog_id, int32 limit) = 0;
virtual Result<vector<NotificationGroupKey>> get_notification_groups_by_last_notification_date(
NotificationGroupKey notification_group_key, int32 limit) = 0;
@ -69,7 +70,8 @@ class DialogDbAsyncInterface {
virtual void get_dialog(DialogId dialog_id, Promise<BufferSlice> promise) = 0;
virtual void get_dialogs(int64 order, DialogId dialog_id, int32 limit, Promise<vector<BufferSlice>> promise) = 0;
virtual void get_dialogs(FolderId folder_id, int64 order, DialogId dialog_id, int32 limit,
Promise<vector<BufferSlice>> promise) = 0;
virtual void get_notification_groups_by_last_notification_date(NotificationGroupKey notification_group_key,
int32 limit,

File diff suppressed because it is too large Load Diff

View File

@ -259,8 +259,9 @@ class MessagesManager : public Actor {
void on_update_message_web_page(FullMessageId full_message_id, bool have_web_page);
void on_get_dialogs(vector<tl_object_ptr<telegram_api::Dialog>> &&dialog_folders, int32 total_count,
vector<tl_object_ptr<telegram_api::Message>> &&messages, Promise<Unit> &&promise);
void on_get_dialogs(FolderId folder_id, vector<tl_object_ptr<telegram_api::Dialog>> &&dialog_folders,
int32 total_count, vector<tl_object_ptr<telegram_api::Message>> &&messages,
Promise<Unit> &&promise);
void on_get_common_dialogs(UserId user_id, int32 offset_chat_id, vector<tl_object_ptr<telegram_api::Chat>> &&chats,
int32 total_count);
@ -269,9 +270,9 @@ class MessagesManager : public Actor {
void on_update_dialog_draft_message(DialogId dialog_id, tl_object_ptr<telegram_api::DraftMessage> &&draft_message);
void on_update_dialog_is_pinned(DialogId dialog_id, bool is_pinned);
void on_update_dialog_is_pinned(FolderId folder_id, DialogId dialog_id, bool is_pinned);
void on_update_pinned_dialogs();
void on_update_pinned_dialogs(FolderId folder_id);
void on_update_dialog_is_marked_as_unread(DialogId dialog_id, bool is_marked_as_unread);
@ -464,7 +465,7 @@ class MessagesManager : public Actor {
void load_dialogs(vector<DialogId> dialog_ids, Promise<Unit> &&promise);
vector<DialogId> get_dialogs(DialogDate offset, int32 limit, bool force, Promise<Unit> &&promise);
vector<DialogId> get_dialogs(FolderId folder_id, DialogDate offset, int32 limit, bool force, Promise<Unit> &&promise);
vector<DialogId> search_public_dialogs(const string &query, Promise<Unit> &&promise);
@ -521,13 +522,15 @@ class MessagesManager : public Actor {
void clear_all_draft_messages(bool exclude_secret_chats, Promise<Unit> &&promise);
void set_dialog_is_pinned(DialogId dialog_id, bool is_pinned);
Status toggle_dialog_is_pinned(DialogId dialog_id, bool is_pinned) TD_WARN_UNUSED_RESULT;
Status toggle_dialog_is_marked_as_unread(DialogId dialog_id, bool is_marked_as_unread) TD_WARN_UNUSED_RESULT;
Status toggle_dialog_silent_send_message(DialogId dialog_id, bool silent_send_message) TD_WARN_UNUSED_RESULT;
Status set_pinned_dialogs(vector<DialogId> dialog_ids) TD_WARN_UNUSED_RESULT;
Status set_pinned_dialogs(FolderId folder_id, vector<DialogId> dialog_ids) TD_WARN_UNUSED_RESULT;
Status set_dialog_client_data(DialogId dialog_id, string &&client_data) TD_WARN_UNUSED_RESULT;
@ -1125,6 +1128,35 @@ class MessagesManager : public Actor {
void parse(ParserT &parser);
};
struct DialogList {
FolderId folder_id;
bool is_message_unread_count_inited_ = false;
bool is_dialog_unread_count_inited_ = false;
bool need_unread_count_recalc_ = true;
int32 unread_message_total_count_ = 0;
int32 unread_message_muted_count_ = 0;
int32 unread_dialog_total_count_ = 0;
int32 unread_dialog_muted_count_ = 0;
int32 unread_dialog_marked_count_ = 0;
int32 unread_dialog_muted_marked_count_ = 0;
std::set<DialogDate> ordered_dialogs_;
std::set<DialogDate> ordered_server_dialogs_;
// date of last dialog in the dialog list
// last_dialog_date_ == min(last_server_dialog_date_, last_secret_chat_dialog_date_)
DialogDate last_dialog_date_ = MIN_DIALOG_DATE; // in memory
// date of last known user/group/channel dialog in the right order
DialogDate last_server_dialog_date_ = MIN_DIALOG_DATE;
DialogDate last_loaded_database_dialog_date_ = MIN_DIALOG_DATE;
DialogDate last_database_server_dialog_date_ = MIN_DIALOG_DATE;
MultiPromiseActor load_dialog_list_multipromise_{
"LoadDialogListMultiPromiseActor"}; // should be defined before pending_on_get_dialogs_
int32 load_dialog_list_limit_max_ = 0;
};
class MessagesIteratorBase {
vector<const Message *> stack_;
@ -1594,11 +1626,11 @@ class MessagesManager : public Actor {
void try_reuse_notification_group(NotificationGroupInfo &group_info);
void load_dialog_list(int32 limit, bool only_local, Promise<Unit> &&promise);
void load_dialog_list(FolderId folder_id, int32 limit, bool only_local, Promise<Unit> &&promise);
void load_dialog_list_from_database(int32 limit, Promise<Unit> &&promise);
void load_dialog_list_from_database(FolderId folder_id, int32 limit, Promise<Unit> &&promise);
static void preload_dialog_list(void *messages_manager_void);
void preload_dialog_list(FolderId folderId);
void update_message_count_by_index(Dialog *d, int diff, const Message *m);
@ -1731,9 +1763,9 @@ class MessagesManager : public Actor {
void send_update_chat_last_message_impl(const Dialog *d, const char *source) const;
void send_update_unread_message_count(DialogId dialog_id, bool force, const char *source);
void send_update_unread_message_count(FolderId folder_id, DialogId dialog_id, bool force, const char *source);
void send_update_unread_chat_count(DialogId dialog_id, bool force, const char *source);
void send_update_unread_chat_count(FolderId folder_id, DialogId dialog_id, bool force, const char *source);
void send_update_chat_read_inbox(const Dialog *d, bool force, const char *source);
@ -1745,7 +1777,7 @@ class MessagesManager : public Actor {
void send_update_chat_online_member_count(DialogId dialog_id, int32 online_member_count) const;
void send_update_chat_list_type(const Dialog *d) const;
void send_update_chat_chat_list(const Dialog *d) const;
tl_object_ptr<td_api::message> get_message_object(DialogId dialog_id, const Message *m,
bool for_event_log = false) const;
@ -1759,11 +1791,13 @@ class MessagesManager : public Actor {
static bool need_unread_counter(int64 dialog_order);
void recalc_unread_count();
void recalc_unread_count(FolderId folder_id);
td_api::object_ptr<td_api::updateUnreadMessageCount> get_update_unread_message_count_object() const;
td_api::object_ptr<td_api::updateUnreadMessageCount> get_update_unread_message_count_object(
FolderId folder_id, const DialogList &list) const;
td_api::object_ptr<td_api::updateUnreadChatCount> get_update_unread_chat_count_object() const;
td_api::object_ptr<td_api::updateUnreadChatCount> get_update_unread_chat_count_object(FolderId folder_id,
const DialogList &list) const;
void set_dialog_last_read_inbox_message_id(Dialog *d, MessageId message_id, int32 server_unread_count,
int32 local_unread_count, bool force_update, const char *source);
@ -1784,12 +1818,10 @@ class MessagesManager : public Actor {
void set_dialog_is_empty(Dialog *d, const char *source);
static int32 get_pinned_dialogs_limit();
static int32 get_pinned_dialogs_limit(FolderId folder_id);
static vector<DialogId> remove_secret_chat_dialog_ids(vector<DialogId> dialog_ids);
void set_dialog_is_pinned(DialogId dialog_id, bool is_pinned);
void set_dialog_is_pinned(Dialog *d, bool is_pinned);
void set_dialog_is_marked_as_unread(Dialog *d, bool is_marked_as_unread);
@ -1802,7 +1834,7 @@ class MessagesManager : public Actor {
void toggle_dialog_is_marked_as_unread_on_server(DialogId dialog_id, bool is_marked_as_unread, uint64 logevent_id);
void reorder_pinned_dialogs_on_server(const vector<DialogId> &dialog_ids, uint64 logevent_id);
void reorder_pinned_dialogs_on_server(FolderId folder_id, const vector<DialogId> &dialog_ids, uint64 logevent_id);
void set_dialog_reply_markup(Dialog *d, MessageId message_id);
@ -1864,7 +1896,9 @@ class MessagesManager : public Actor {
td_api::object_ptr<td_api::ChatType> get_chat_type_object(DialogId dialog_id) const;
static td_api::object_ptr<td_api::ChatListType> get_chat_list_type_object(const Dialog *d);
static td_api::object_ptr<td_api::ChatList> get_chat_list_object(const Dialog *d);
static td_api::object_ptr<td_api::ChatList> get_chat_list_object(FolderId folder_id);
td_api::object_ptr<td_api::chat> get_chat_object(const Dialog *d) const;
@ -1878,19 +1912,23 @@ class MessagesManager : public Actor {
Dialog *on_load_dialog_from_database(DialogId dialog_id, const BufferSlice &value);
void on_get_dialogs_from_database(int32 limit, vector<BufferSlice> &&dialogs, Promise<Unit> &&promise);
void on_get_dialogs_from_database(FolderId folder_id, int32 limit, vector<BufferSlice> &&dialogs,
Promise<Unit> &&promise);
void send_get_dialog_query(DialogId dialog_id, Promise<Unit> &&promise, uint64 logevent_id = 0);
void send_search_public_dialogs_query(const string &query, Promise<Unit> &&promise);
vector<DialogId> get_pinned_dialogs() const;
vector<DialogId> get_pinned_dialogs(FolderId folder_id) const;
void reload_pinned_dialogs(Promise<Unit> &&promise);
void reload_pinned_dialogs(FolderId folder_id, Promise<Unit> &&promise);
void update_dialogs_hints(const Dialog *d);
void update_dialogs_hints_rating(const Dialog *d);
DialogList &get_dialog_list(FolderId folder_id);
const DialogList *get_dialog_list(FolderId folder_id) const;
std::pair<int32, vector<DialogParticipant>> search_private_chat_participants(UserId my_user_id, UserId peer_user_id,
const string &query, int32 limit,
DialogParticipantsFilter filter) const;
@ -2052,7 +2090,7 @@ class MessagesManager : public Actor {
bool set_dialog_order(Dialog *d, int64 new_order, bool need_send_update_chat_order, bool is_loaded_from_database,
const char *source);
void update_last_dialog_date();
void update_last_dialog_date(FolderId folder_id);
void load_notification_settings();
@ -2111,6 +2149,8 @@ class MessagesManager : public Actor {
static void on_update_dialog_online_member_count_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int);
static void on_preload_dialog_list_timeout_callback(void *messages_manager_ptr, int64 folder_id_int);
void load_secret_thumbnail(FileId thumbnail_file_id);
static tl_object_ptr<telegram_api::channelAdminLogEventsFilter> get_channel_admin_log_events_filter(
@ -2187,7 +2227,7 @@ class MessagesManager : public Actor {
uint64 save_toggle_dialog_is_pinned_on_server_logevent(DialogId dialog_id, bool is_pinned);
uint64 save_reorder_pinned_dialogs_on_server_logevent(const vector<DialogId> &dialog_ids);
uint64 save_reorder_pinned_dialogs_on_server_logevent(FolderId folder_id, const vector<DialogId> &dialog_ids);
uint64 save_toggle_dialog_is_marked_as_unread_on_server_logevent(DialogId dialog_id, bool is_marked_as_unread);
@ -2393,39 +2433,16 @@ class MessagesManager : public Actor {
std::unordered_map<NotificationGroupId, DialogId, NotificationGroupIdHash> notification_group_id_to_dialog_id_;
uint64 current_message_edit_generation_ = 0;
bool include_sponsored_dialog_to_unread_count_ = false;
bool have_postponed_unread_message_count_update_ = false;
bool have_postponed_unread_chat_count_update_ = false;
bool is_message_unread_count_inited_ = false;
bool is_dialog_unread_count_inited_ = false;
bool need_unread_count_recalc_ = true;
int32 unread_message_total_count_ = 0;
int32 unread_message_muted_count_ = 0;
int32 unread_dialog_total_count_ = 0;
int32 unread_dialog_muted_count_ = 0;
int32 unread_dialog_marked_count_ = 0;
int32 unread_dialog_muted_marked_count_ = 0;
std::unordered_set<FolderId, FolderIdHash> postponed_unread_message_count_updates_;
std::unordered_set<FolderId, FolderIdHash> postponed_unread_chat_count_updates_;
int64 current_pinned_dialog_order_ = DEFAULT_ORDER;
uint64 current_message_edit_generation_ = 0;
std::set<DialogDate> ordered_dialogs_;
std::set<DialogDate> ordered_server_dialogs_;
// date of last dialog in the dialog list
// last_dialog_date_ == min(last_server_dialog_date_, last_secret_chat_dialog_date_)
DialogDate last_dialog_date_ = MIN_DIALOG_DATE; // in memory
// date of last known user/group/channel dialog in the right order
DialogDate last_server_dialog_date_ = MIN_DIALOG_DATE;
DialogDate last_loaded_database_dialog_date_ = MIN_DIALOG_DATE;
DialogDate last_database_server_dialog_date_ = MIN_DIALOG_DATE;
MultiPromiseActor load_dialog_list_multipromise_{
"LoadDialogListMultiPromiseActor"}; // should be defined before pending_on_get_dialogs_
int32 load_dialog_list_limit_max_ = 0;
Timeout preload_dialog_list_timeout_;
std::unordered_map<FolderId, DialogList, FolderIdHash> dialog_lists_;
std::unordered_map<DialogId, string, DialogIdHash> active_get_channel_differencies_;
std::unordered_map<DialogId, uint64, DialogIdHash> get_channel_difference_to_logevent_id_;
@ -2441,6 +2458,7 @@ class MessagesManager : public Actor {
MultiTimeout pending_send_dialog_action_timeout_{"PendingSendDialogActionTimeout"};
MultiTimeout active_dialog_action_timeout_{"ActiveDialogActionTimeout"};
MultiTimeout update_dialog_online_member_count_timeout_{"UpdateDialogOnlineMemberCountTimeout"};
MultiTimeout preload_dialog_list_timeout_{"PreloadDialogListTimeout"};
Hints dialogs_hints_; // search dialogs by title and username
@ -2457,6 +2475,7 @@ class MessagesManager : public Actor {
std::unordered_map<string, DialogId> inaccessible_resolved_usernames_;
struct PendingOnGetDialogs {
FolderId folder_id;
vector<tl_object_ptr<telegram_api::Dialog>> dialogs;
int32 total_count;
vector<tl_object_ptr<telegram_api::Message>> messages;

View File

@ -32,6 +32,7 @@
#include "td/telegram/files/FileManager.h"
#include "td/telegram/files/FileSourceId.h"
#include "td/telegram/files/FileType.h"
#include "td/telegram/FolderId.h"
#include "td/telegram/Global.h"
#include "td/telegram/HashtagHints.h"
#include "td/telegram/InlineQueriesManager.h"
@ -898,13 +899,14 @@ class GetChatRequest : public RequestActor<> {
};
class GetChatsRequest : public RequestActor<> {
FolderId folder_id_;
DialogDate offset_;
int32 limit_;
vector<DialogId> dialog_ids_;
void do_run(Promise<Unit> &&promise) override {
dialog_ids_ = td->messages_manager_->get_dialogs(offset_, limit_, get_tries() < 2, std::move(promise));
dialog_ids_ = td->messages_manager_->get_dialogs(folder_id_, offset_, limit_, get_tries() < 2, std::move(promise));
}
void do_send_result() override {
@ -912,8 +914,12 @@ class GetChatsRequest : public RequestActor<> {
}
public:
GetChatsRequest(ActorShared<Td> td, uint64 request_id, int64 offset_order, int64 offset_dialog_id, int32 limit)
: RequestActor(std::move(td), request_id), offset_(offset_order, DialogId(offset_dialog_id)), limit_(limit) {
GetChatsRequest(ActorShared<Td> td, uint64 request_id, FolderId folder_id, int64 offset_order, int64 offset_dialog_id,
int32 limit)
: RequestActor(std::move(td), request_id)
, folder_id_(folder_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);
}
@ -5459,7 +5465,8 @@ void Td::on_request(uint64 id, const td_api::removeTopChat &request) {
void Td::on_request(uint64 id, const td_api::getChats &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetChatsRequest, request.offset_order_, request.offset_chat_id_, request.limit_);
CREATE_REQUEST(GetChatsRequest, FolderId(request.chat_list_), request.offset_order_, request.offset_chat_id_,
request.limit_);
}
void Td::on_request(uint64 id, td_api::searchPublicChat &request) {
@ -6010,6 +6017,7 @@ void Td::on_request(uint64 id, const td_api::toggleChatDefaultDisableNotificatio
void Td::on_request(uint64 id, const td_api::setPinnedChats &request) {
CHECK_IS_USER();
answer_ok_query(id, messages_manager_->set_pinned_dialogs(
FolderId(request.chat_list_),
transform(request.chat_ids_, [](int64 chat_id) { return DialogId(chat_id); })));
}

View File

@ -342,9 +342,9 @@ Status TdDb::init_sqlite(int32 scheduler_id, const TdParameters &parameters, DbK
}
if (dialog_db_was_created) {
binlog_pmc.erase("unread_message_count");
binlog_pmc.erase("unread_dialog_count");
binlog_pmc.erase("last_server_dialog_date");
binlog_pmc.erase_by_prefix("last_server_dialog_date");
binlog_pmc.erase_by_prefix("unread_message_count");
binlog_pmc.erase_by_prefix("unread_dialog_count");
binlog_pmc.erase("promoted_dialog_id");
binlog_pmc.erase("sponsored_dialog_id");
binlog_pmc.erase_by_prefix("top_dialogs");

View File

@ -1724,12 +1724,14 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateDraftMessage> u
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateDialogPinned> update, bool /*force_apply*/) {
FolderId folder_id(update->flags_ & telegram_api::updateDialogPinned::FOLDER_ID_MASK ? update->folder_id_ : 0);
td_->messages_manager_->on_update_dialog_is_pinned(
DialogId(update->peer_), (update->flags_ & telegram_api::updateDialogPinned::PINNED_MASK) != 0);
folder_id, DialogId(update->peer_), (update->flags_ & telegram_api::updateDialogPinned::PINNED_MASK) != 0);
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updatePinnedDialogs> update, bool /*force_apply*/) {
td_->messages_manager_->on_update_pinned_dialogs(); // TODO use update->order_
FolderId folder_id(update->flags_ & telegram_api::updatePinnedDialogs::FOLDER_ID_MASK ? update->folder_id_ : 0);
td_->messages_manager_->on_update_pinned_dialogs(folder_id); // TODO use update->order_
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateDialogUnreadMark> update, bool /*force_apply*/) {

View File

@ -34,6 +34,7 @@ enum class Version : int32 {
SupportMinithumbnails,
AddVideoCallsSupport,
AddPhotoSizeSource,
SupportFolders,
Next
};

View File

@ -401,7 +401,7 @@ class CliClient final : public Actor {
case td_api::authorizationStateWaitTdlibParameters::ID: {
auto parameters = td_api::make_object<td_api::tdlibParameters>();
parameters->use_test_dc_ = use_test_dc_;
parameters->use_message_database_ = false;
parameters->use_message_database_ = true;
parameters->use_chat_info_database_ = true;
parameters->use_secret_chats_ = true;
parameters->api_id_ = api_id_;
@ -861,7 +861,7 @@ class CliClient final : public Actor {
Scheduler::subscribe(stdin_.get_poll_info().extract_pollable_fd(this), PollFlags::Read());
if (get_chat_list_) {
send_request(td_api::make_object<td_api::getChats>(std::numeric_limits<int64>::max(), 0, 100));
send_request(td_api::make_object<td_api::getChats>(nullptr, std::numeric_limits<int64>::max(), 0, 100));
}
if (disable_network_) {
send_request(td_api::make_object<td_api::setNetworkType>(td_api::make_object<td_api::networkTypeNone>()));
@ -1602,7 +1602,7 @@ class CliClient final : public Actor {
op_not_found_count++;
}
if (op == "gc" || op == "GetChats") {
if (op == "gc" || op == "GetChats" || op == "gca") {
string offset_order_string;
string offset_chat_id;
string limit;
@ -1610,6 +1610,10 @@ class CliClient final : public Actor {
std::tie(limit, args) = split(args);
std::tie(offset_order_string, offset_chat_id) = split(args);
td_api::object_ptr<td_api::ChatList> chat_list;
if (op == "gca") {
chat_list = td_api::make_object<td_api::chatListArchive>();
}
if (limit.empty()) {
limit = "10000";
}
@ -1619,12 +1623,12 @@ class CliClient final : public Actor {
} else {
offset_order = to_integer<int64>(offset_order_string);
}
send_request(
td_api::make_object<td_api::getChats>(offset_order, as_chat_id(offset_chat_id), to_integer<int32>(limit)));
send_request(td_api::make_object<td_api::getChats>(std::move(chat_list), offset_order, as_chat_id(offset_chat_id),
to_integer<int32>(limit)));
} else if (op == "gctest") {
send_request(td_api::make_object<td_api::getChats>(std::numeric_limits<int64>::max(), 0, 1));
send_request(td_api::make_object<td_api::getChats>(std::numeric_limits<int64>::max(), 0, 10));
send_request(td_api::make_object<td_api::getChats>(std::numeric_limits<int64>::max(), 0, 5));
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));
} else if (op == "gcc" || op == "GetCommonChats") {
string user_id;
string offset_chat_id;
@ -2648,13 +2652,17 @@ class CliClient final : public Actor {
std::tie(chat_id, default_disable_notification) = split(args);
send_request(td_api::make_object<td_api::toggleChatDefaultDisableNotification>(
as_chat_id(chat_id), as_bool(default_disable_notification)));
} else if (op == "spchats") {
} else if (op == "spchats" || op == "spchatsa") {
vector<string> chat_ids_str = full_split(args, ' ');
vector<int64> chat_ids;
for (auto &chat_id_str : chat_ids_str) {
chat_ids.push_back(as_chat_id(chat_id_str));
}
send_request(td_api::make_object<td_api::setPinnedChats>(std::move(chat_ids)));
td_api::object_ptr<td_api::ChatList> chat_list = td_api::make_object<td_api::chatListMain>();
if (op == "spchatsa") {
chat_list = td_api::make_object<td_api::chatListArchive>();
}
send_request(td_api::make_object<td_api::setPinnedChats>(std::move(chat_list), std::move(chat_ids)));
} else if (op == "sca") {
string chat_id;
string action;

View File

@ -30,7 +30,6 @@ void TcpListener::start_up() {
}
void TcpListener::tear_down() {
LOG(ERROR) << "TcpListener closed";
if (!server_fd_.empty()) {
Scheduler::unsubscribe_before_close(server_fd_.get_poll_info().get_pollable_fd_ref());
server_fd_.close();
@ -53,7 +52,6 @@ void TcpListener::loop() {
}
if (can_close(server_fd_)) {
LOG(ERROR) << "HELLO!";
stop();
}
}