From bcf3643cf7b99afa2d3c7083869bb1983c28988b Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 2 Mar 2021 17:27:44 +0300 Subject: [PATCH 001/281] Update layer to 125. --- td/generate/scheme/telegram_api.tl | 37 +++++++++++------- td/telegram/GroupCallManager.cpp | 58 +++++++++++++++++----------- td/telegram/GroupCallParticipant.cpp | 6 ++- td/telegram/MessagesManager.cpp | 33 ++++++++++------ td/telegram/MessagesManager.h | 5 ++- td/telegram/UpdatesManager.cpp | 10 ++--- td/telegram/Version.h | 2 +- 7 files changed, 93 insertions(+), 58 deletions(-) diff --git a/td/generate/scheme/telegram_api.tl b/td/generate/scheme/telegram_api.tl index d37b95efc..b908d8528 100644 --- a/td/generate/scheme/telegram_api.tl +++ b/td/generate/scheme/telegram_api.tl @@ -79,6 +79,7 @@ inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes th inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; inputPeerPhotoFileLocation#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation; inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation; +inputGroupCallStream#bba51639 call:InputGroupCall time_ms:long scale:int = InputFileLocation; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; @@ -114,8 +115,8 @@ chatForbidden#7328bdb id:int title:string = Chat; channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; -chatFull#f06c4018 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int = ChatFull; -channelFull#2548c037 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector = ChatFull; +chatFull#8a1e2983 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer = ChatFull; +channelFull#548c3f93 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; @@ -273,7 +274,7 @@ updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; -updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; +updateChatUserTyping#86cadb6c chat_id:int from_id:Peer action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; @@ -350,7 +351,7 @@ updateChannelMessageForwards#6e8a84df channel_id:int id:int forwards:int = Updat updateReadChannelDiscussionInbox#1cc7de54 flags:# channel_id:int top_msg_id:int read_max_id:int broadcast_id:flags.0?int broadcast_post:flags.0?int = Update; updateReadChannelDiscussionOutbox#4638a26c channel_id:int top_msg_id:int read_max_id:int = Update; updatePeerBlocked#246a4b22 peer_id:Peer blocked:Bool = Update; -updateChannelUserTyping#ff2abe9f flags:# channel_id:int top_msg_id:flags.0?int user_id:int action:SendMessageAction = Update; +updateChannelUserTyping#6b171718 flags:# channel_id:int top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update; updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector pts:int pts_count:int = Update; updatePinnedChannelMessages#8588878b flags:# pinned:flags.0?true channel_id:int messages:Vector pts:int pts_count:int = Update; updateChat#1330a196 chat_id:int = Update; @@ -1189,15 +1190,15 @@ peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats; groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#55903081 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true id:long access_hash:long participants_count:int params:flags.0?DataJSON version:int = GroupCall; +groupCall#c0c2052e flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true id:long access_hash:long participants_count:int params:flags.0?DataJSON title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int version:int = GroupCall; inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; -groupCallParticipant#64c62a15 flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true user_id:int date:int active_date:flags.3?int source:int volume:flags.7?int = GroupCallParticipant; +groupCallParticipant#19adba89 flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long = GroupCallParticipant; -phone.groupCall#66ab0bfc call:GroupCall participants:Vector participants_next_offset:string users:Vector = phone.GroupCall; +phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; -phone.groupParticipants#9cfeb92d count:int participants:Vector next_offset:string users:Vector version:int = phone.GroupParticipants; +phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; @@ -1226,6 +1227,10 @@ messages.chatAdminsWithInvites#b69b72d7 admins:Vector user messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; +phone.joinAsPeers#afe5623f peers:Vector chats:Vector users:Vector = phone.JoinAsPeers; + +phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1458,8 +1463,8 @@ messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector = Vector; -messages.requestUrlAuth#e33f5613 peer:InputPeer msg_id:int button_id:int = UrlAuthResult; -messages.acceptUrlAuth#f729ea98 flags:# write_allowed:flags.0?true peer:InputPeer msg_id:int button_id:int = UrlAuthResult; +messages.requestUrlAuth#198fb446 flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; +messages.acceptUrlAuth#b12c7125 flags:# write_allowed:flags.0?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; messages.getScheduledHistory#e2c2685b peer:InputPeer hash:int = messages.Messages; messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; @@ -1598,15 +1603,19 @@ phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhon phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; phone.createGroupCall#bd3dabe0 peer:InputPeer random_id:int = Updates; -phone.joinGroupCall#5f9c8e62 flags:# muted:flags.0?true call:InputGroupCall params:DataJSON = Updates; +phone.joinGroupCall#b132ff7b flags:# muted:flags.0?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string params:DataJSON = Updates; phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; -phone.editGroupCallMember#a5e76cd8 flags:# muted:flags.0?true call:InputGroupCall user_id:InputUser volume:flags.1?int = Updates; phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; -phone.toggleGroupCallSettings#74bbb43d flags:# call:InputGroupCall join_muted:flags.0?Bool = Updates; +phone.toggleGroupCallSettings#74bbb43d flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool = Updates; phone.getGroupCall#c7cb017 call:InputGroupCall = phone.GroupCall; -phone.getGroupParticipants#c9f1d285 call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; +phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; phone.checkGroupCall#b74a7bea call:InputGroupCall source:int = Bool; +phone.toggleGroupCallRecord#c02a66d7 flags:# start:flags.0?true call:InputGroupCall title:flags.1?string = Updates; +phone.editGroupCallParticipant#d975eb80 flags:# muted:flags.0?true call:InputGroupCall participant:InputPeer volume:flags.1?int raise_hand:flags.2?Bool = Updates; +phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; +phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; +phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 71b331239..086d58302 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -121,11 +121,13 @@ class GetGroupCallParticipantQuery : public Td::ResultHandler { explicit GetGroupCallParticipantQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(InputGroupCallId input_group_call_id, vector user_ids, vector audio_sources) { + void send(InputGroupCallId input_group_call_id, vector> input_peers, + vector audio_sources) { input_group_call_id_ = input_group_call_id; - auto limit = narrow_cast(max(user_ids.size(), audio_sources.size())); - send_query(G()->net_query_creator().create(telegram_api::phone_getGroupParticipants( - input_group_call_id.get_input_group_call(), std::move(user_ids), std::move(audio_sources), string(), limit))); + auto limit = narrow_cast(max(input_peers.size(), audio_sources.size())); + send_query(G()->net_query_creator().create( + telegram_api::phone_getGroupParticipants(input_group_call_id.get_input_group_call(), std::move(input_peers), + std::move(audio_sources), string(), limit))); } void on_result(uint64 id, BufferSlice packet) override { @@ -158,7 +160,8 @@ class GetGroupCallParticipantsQuery : public Td::ResultHandler { input_group_call_id_ = input_group_call_id; offset_ = std::move(offset); send_query(G()->net_query_creator().create(telegram_api::phone_getGroupParticipants( - input_group_call_id.get_input_group_call(), vector(), vector(), offset_, limit))); + input_group_call_id.get_input_group_call(), vector>(), vector(), + offset_, limit))); } void on_result(uint64 id, BufferSlice packet) override { @@ -191,13 +194,17 @@ class JoinGroupCallQuery : public Td::ResultHandler { input_group_call_id_ = input_group_call_id; generation_ = generation; + auto join_as_input_peer = + td->messages_manager_->get_input_peer(DialogId(td->contacts_manager_->get_my_id()), AccessRights::Read); + CHECK(join_as_input_peer != nullptr); + int32 flags = 0; if (is_muted) { flags |= telegram_api::phone_joinGroupCall::MUTED_MASK; } - auto query = G()->net_query_creator().create( - telegram_api::phone_joinGroupCall(flags, false /*ignored*/, input_group_call_id.get_input_group_call(), - make_tl_object(payload))); + auto query = G()->net_query_creator().create(telegram_api::phone_joinGroupCall( + flags, false /*ignored*/, input_group_call_id.get_input_group_call(), std::move(join_as_input_peer), string(), + make_tl_object(payload))); auto join_query_ref = query.get_weak(); send_query(std::move(query)); return join_query_ref; @@ -228,8 +235,8 @@ class ToggleGroupCallSettingsQuery : public Td::ResultHandler { } void send(int32 flags, InputGroupCallId input_group_call_id, bool join_muted) { - send_query(G()->net_query_creator().create( - telegram_api::phone_toggleGroupCallSettings(flags, input_group_call_id.get_input_group_call(), join_muted))); + send_query(G()->net_query_creator().create(telegram_api::phone_toggleGroupCallSettings( + flags, false /*ignored*/, input_group_call_id.get_input_group_call(), join_muted))); } void on_result(uint64 id, BufferSlice packet) override { @@ -280,36 +287,37 @@ class InviteToGroupCallQuery : public Td::ResultHandler { } }; -class EditGroupCallMemberQuery : public Td::ResultHandler { +class EditGroupCallParticipantQuery : public Td::ResultHandler { Promise promise_; public: - explicit EditGroupCallMemberQuery(Promise &&promise) : promise_(std::move(promise)) { + explicit EditGroupCallParticipantQuery(Promise &&promise) : promise_(std::move(promise)) { } void send(InputGroupCallId input_group_call_id, UserId user_id, bool is_muted, int32 volume_level) { - auto input_user = td->contacts_manager_->get_input_user(user_id); - CHECK(input_user != nullptr); + auto input_peer = MessagesManager::get_input_peer_force(DialogId(user_id)); + CHECK(input_peer != nullptr); int32 flags = 0; if (volume_level) { - flags |= telegram_api::phone_editGroupCallMember::VOLUME_MASK; + flags |= telegram_api::phone_editGroupCallParticipant::VOLUME_MASK; } else if (is_muted) { - flags |= telegram_api::phone_editGroupCallMember::MUTED_MASK; + flags |= telegram_api::phone_editGroupCallParticipant::MUTED_MASK; } - send_query(G()->net_query_creator().create(telegram_api::phone_editGroupCallMember( - flags, false /*ignored*/, input_group_call_id.get_input_group_call(), std::move(input_user), volume_level))); + send_query(G()->net_query_creator().create(telegram_api::phone_editGroupCallParticipant( + flags, false /*ignored*/, input_group_call_id.get_input_group_call(), std::move(input_peer), volume_level, + false))); } void on_result(uint64 id, BufferSlice packet) override { - auto result_ptr = fetch_result(packet); + auto result_ptr = fetch_result(packet); if (result_ptr.is_error()) { return on_error(id, result_ptr.move_as_error()); } auto ptr = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for EditGroupCallMemberQuery: " << to_string(ptr); + LOG(INFO) << "Receive result for EditGroupCallParticipantQuery: " << to_string(ptr); td->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); } @@ -806,6 +814,7 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i if (result.is_ok()) { td_->contacts_manager_->on_get_users(std::move(result.ok_ref()->users_), "finish_get_group_call"); + td_->contacts_manager_->on_get_chats(std::move(result.ok_ref()->chats_), "finish_get_group_call"); if (update_group_call(result.ok()->call_, DialogId()) != input_group_call_id) { LOG(ERROR) << "Expected " << input_group_call_id << ", but received " << to_string(result.ok()); @@ -884,6 +893,7 @@ void GroupCallManager::on_get_group_call_participants( CHECK(participants != nullptr); td_->contacts_manager_->on_get_users(std::move(participants->users_), "on_get_group_call_participants"); + td_->contacts_manager_->on_get_chats(std::move(participants->chats_), "on_get_group_call_participants"); if (!need_group_call_participants(input_group_call_id)) { return; @@ -2027,7 +2037,7 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ send_closure(actor_id, &GroupCallManager::on_toggle_group_call_participant_is_muted, input_group_call_id, user_id, generation, std::move(promise)); }); - td_->create_handler(std::move(query_promise)) + td_->create_handler(std::move(query_promise)) ->send(input_group_call_id, user_id, is_muted, 0); } @@ -2119,7 +2129,7 @@ void GroupCallManager::set_group_call_participant_volume_level(GroupCallId group send_closure(actor_id, &GroupCallManager::on_set_group_call_participant_volume_level, input_group_call_id, user_id, generation, std::move(promise)); }); - td_->create_handler(std::move(query_promise)) + td_->create_handler(std::move(query_promise)) ->send(input_group_call_id, user_id, false, volume_level); } @@ -2510,8 +2520,10 @@ void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, send_closure(actor_id, &GroupCallManager::on_user_speaking_in_group_call, group_call_id, user_id, date, true); } }); + vector> input_peers; + input_peers.push_back(MessagesManager::get_input_peer_force(DialogId(user_id))); td_->create_handler(std::move(query_promise)) - ->send(input_group_call_id, {user_id.get()}, {}); + ->send(input_group_call_id, std::move(input_peers), {}); } return; } diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index 6403f248e..c6e62609e 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -14,7 +14,11 @@ namespace td { GroupCallParticipant::GroupCallParticipant(const tl_object_ptr &participant) { CHECK(participant != nullptr); - user_id = UserId(participant->user_id_); + DialogId dialog_id(participant->peer_); + if (dialog_id.get_type() != DialogType::User) { + return; + } + user_id = dialog_id.get_user_id(); audio_source = participant->source_; server_is_muted_by_themselves = participant->can_self_unmute_; server_is_muted_by_admin = participant->muted_ && !participant->can_self_unmute_; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 156624a5d..e8a51dc5e 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -4619,8 +4619,9 @@ class RequestUrlAuthQuery : public Td::ResultHandler { dialog_id_ = dialog_id; auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); CHECK(input_peer != nullptr); + int32 flags = telegram_api::messages_requestUrlAuth::PEER_MASK; send_query(G()->net_query_creator().create(telegram_api::messages_requestUrlAuth( - std::move(input_peer), message_id.get_server_message_id().get(), button_id))); + flags, std::move(input_peer), message_id.get_server_message_id().get(), button_id, string()))); } void on_result(uint64 id, BufferSlice packet) override { @@ -4679,12 +4680,13 @@ class AcceptUrlAuthQuery : public Td::ResultHandler { dialog_id_ = dialog_id; auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); CHECK(input_peer != nullptr); - int32 flags = 0; + int32 flags = telegram_api::messages_acceptUrlAuth::PEER_MASK; if (allow_write_access) { flags |= telegram_api::messages_acceptUrlAuth::WRITE_ALLOWED_MASK; } - send_query(G()->net_query_creator().create(telegram_api::messages_acceptUrlAuth( - flags, false /*ignored*/, std::move(input_peer), message_id.get_server_message_id().get(), button_id))); + send_query(G()->net_query_creator().create( + telegram_api::messages_acceptUrlAuth(flags, false /*ignored*/, std::move(input_peer), + message_id.get_server_message_id().get(), button_id, string()))); } void on_result(uint64 id, BufferSlice packet) override { @@ -7194,9 +7196,10 @@ void MessagesManager::on_update_delete_scheduled_messages(DialogId dialog_id, send_update_chat_has_scheduled_messages(d, true); } -void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, UserId user_id, - DialogAction action, int32 date, MessageContentType message_content_type) { - if (td_->auth_manager_->is_bot() || !user_id.is_valid() || is_broadcast_channel(dialog_id)) { +void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, + DialogId typing_dialog_id, DialogAction action, int32 date, + MessageContentType message_content_type) { + if (td_->auth_manager_->is_bot() || !typing_dialog_id.is_valid() || is_broadcast_channel(dialog_id)) { return; } if (top_thread_message_id != MessageId() && !top_thread_message_id.is_valid()) { @@ -7204,6 +7207,11 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th return; } + if (typing_dialog_id.get_type() != DialogType::User) { + return; + } + auto user_id = typing_dialog_id.get_user_id(); + auto dialog_type = dialog_id.get_type(); if (action == DialogAction::get_speaking_action()) { if ((dialog_type != DialogType::Chat && dialog_type != DialogType::Channel) || top_thread_message_id.is_valid()) { @@ -7317,7 +7325,8 @@ void MessagesManager::cancel_user_dialog_action(DialogId dialog_id, const Messag return; } - on_user_dialog_action(dialog_id, MessageId(), m->sender_user_id, DialogAction(), m->date, m->content->get_type()); + on_user_dialog_action(dialog_id, MessageId(), DialogId(m->sender_user_id), DialogAction(), m->date, + m->content->get_type()); } void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_ptr &&update, @@ -30474,8 +30483,8 @@ void MessagesManager::on_active_dialog_action_timeout(DialogId dialog_id) { while (actions_it->second[0].start_time + DIALOG_ACTION_TIMEOUT < now + 0.1) { CHECK(actions_it->second[0].user_id != prev_user_id); prev_user_id = actions_it->second[0].user_id; - on_user_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, actions_it->second[0].user_id, - DialogAction(), 0); + on_user_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, + DialogId(actions_it->second[0].user_id), DialogAction(), 0); actions_it = active_dialog_actions_.find(dialog_id); if (actions_it == active_dialog_actions_.end()) { @@ -30494,8 +30503,8 @@ void MessagesManager::clear_active_dialog_actions(DialogId dialog_id) { auto actions_it = active_dialog_actions_.find(dialog_id); while (actions_it != active_dialog_actions_.end()) { CHECK(!actions_it->second.empty()); - on_user_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, actions_it->second[0].user_id, - DialogAction(), 0); + on_user_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, + DialogId(actions_it->second[0].user_id), DialogAction(), 0); actions_it = active_dialog_actions_.find(dialog_id); } } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 676a691a9..7d7a6ad65 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -334,8 +334,9 @@ class MessagesManager : public Actor { void on_update_delete_scheduled_messages(DialogId dialog_id, vector &&server_message_ids); - void on_user_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, UserId user_id, DialogAction action, - int32 date, MessageContentType message_content_type = MessageContentType::None); + void on_user_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogId typing_dialog_id, + DialogAction action, int32 date, + MessageContentType message_content_type = MessageContentType::None); void read_history_inbox(DialogId dialog_id, MessageId max_message_id, int32 unread_count, const char *source); diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index e4767cfd9..e703b8d77 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -2516,15 +2516,15 @@ int32 UpdatesManager::get_update_qts(const telegram_api::Update *update) { } void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { - UserId user_id(update->user_id_); - td_->messages_manager_->on_user_dialog_action(DialogId(user_id), MessageId(), user_id, + DialogId dialog_id(UserId(update->user_id_)); + td_->messages_manager_->on_user_dialog_action(dialog_id, MessageId(), dialog_id, DialogAction(std::move(update->action_)), get_short_update_date()); promise.set_value(Unit()); } void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { td_->messages_manager_->on_user_dialog_action(DialogId(ChatId(update->chat_id_)), MessageId(), - UserId(update->user_id_), DialogAction(std::move(update->action_)), + DialogId(update->from_id_), DialogAction(std::move(update->action_)), get_short_update_date()); promise.set_value(Unit()); } @@ -2535,7 +2535,7 @@ void UpdatesManager::on_update(tl_object_ptrtop_msg_id_)); } td_->messages_manager_->on_user_dialog_action(DialogId(ChannelId(update->channel_id_)), top_thread_message_id, - UserId(update->user_id_), DialogAction(std::move(update->action_)), + DialogId(update->from_id_), DialogAction(std::move(update->action_)), get_short_update_date()); promise.set_value(Unit()); } @@ -2543,7 +2543,7 @@ void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { SecretChatId secret_chat_id(update->chat_id_); UserId user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id); - td_->messages_manager_->on_user_dialog_action(DialogId(secret_chat_id), MessageId(), user_id, + td_->messages_manager_->on_user_dialog_action(DialogId(secret_chat_id), MessageId(), DialogId(user_id), DialogAction::get_typing_action(), get_short_update_date()); promise.set_value(Unit()); } diff --git a/td/telegram/Version.h b/td/telegram/Version.h index 11d98bf11..86bbcc059 100644 --- a/td/telegram/Version.h +++ b/td/telegram/Version.h @@ -8,7 +8,7 @@ namespace td { -constexpr int32 MTPROTO_LAYER = 124; +constexpr int32 MTPROTO_LAYER = 125; enum class Version : int32 { Initial, // 0 From 1f4e7aeb611415bc68df081b86cc88bad0b90ee2 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 2 Mar 2021 18:00:54 +0300 Subject: [PATCH 002/281] Add groupCall.title. --- td/generate/scheme/td_api.tl | 3 ++- td/telegram/GroupCallManager.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 9a2bc5444..10881b70f 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2106,6 +2106,7 @@ groupCallRecentSpeaker user_id:int32 is_speaking:Bool = GroupCallRecentSpeaker; //@description Describes a group call //@id Group call identifier +//@title Group call title //@is_active True, if the call is active //@is_joined True, if the call is joined //@need_rejoin True, if user was kicked from the call because of network loss and the call needs to be rejoined @@ -2117,7 +2118,7 @@ groupCallRecentSpeaker user_id:int32 is_speaking:Bool = GroupCallRecentSpeaker; //@mute_new_participants True, if only group call administrators can unmute new participants //@can_change_mute_new_participants True, if the current user can enable or disable mute_new_participants setting //@duration Call duration; for ended calls only -groupCall id:int32 is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector mute_new_participants:Bool can_change_mute_new_participants:Bool duration:int32 = GroupCall; +groupCall id:int32 title:string is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector mute_new_participants:Bool can_change_mute_new_participants:Bool duration:int32 = GroupCall; //@description Describes a payload fingerprint for interaction with tgcalls @hash Value of the field hash @setup Value of the field setup @fingerprint Value of the field fingerprint groupCallPayloadFingerprint hash:string setup:string fingerprint:string = GroupCallPayloadFingerprint; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 086d58302..ef79e650b 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -418,6 +418,7 @@ class DiscardGroupCallQuery : public Td::ResultHandler { struct GroupCallManager::GroupCall { GroupCallId group_call_id; DialogId dialog_id; + string title; bool is_inited = false; bool is_active = false; bool is_joined = false; @@ -2330,6 +2331,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptr(group_call_ptr.get()); input_group_call_id = InputGroupCallId(group_call->id_, group_call->access_hash_); call.is_active = true; + call.title = std::move(group_call->title_); call.mute_new_participants = group_call->join_muted_; call.allowed_change_mute_new_participants = group_call->can_change_join_muted_; call.participant_count = group_call->participants_count_; @@ -2409,6 +2411,10 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrtitle && call.version >= group_call->version) { + group_call->title = std::move(call.title); + need_update = true; + } if (call.can_be_managed != group_call->can_be_managed) { group_call->can_be_managed = call.can_be_managed; need_update = true; @@ -2703,8 +2709,8 @@ tl_object_ptr GroupCallManager::get_group_call_object( bool can_change_mute_new_participants = group_call->is_active && group_call->can_be_managed && group_call->allowed_change_mute_new_participants; return td_api::make_object( - group_call->group_call_id.get(), group_call->is_active, is_joined, group_call->need_rejoin, can_self_unmute, - group_call->can_be_managed, group_call->participant_count, group_call->loaded_all_participants, + group_call->group_call_id.get(), group_call->title, group_call->is_active, is_joined, group_call->need_rejoin, + can_self_unmute, group_call->can_be_managed, group_call->participant_count, group_call->loaded_all_participants, std::move(recent_speakers), mute_new_participants, can_change_mute_new_participants, group_call->duration); } From 882d837d2441a303b594f45cf123df8a9c84303d Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 2 Mar 2021 19:44:57 +0300 Subject: [PATCH 003/281] Add td_api::setGroupCallTitle. --- td/generate/scheme/td_api.tl | 3 + td/telegram/GroupCallManager.cpp | 113 +++++++++++++++++++++++++++++-- td/telegram/GroupCallManager.h | 8 +++ td/telegram/Td.cpp | 8 +++ td/telegram/Td.h | 2 + td/telegram/cli.cpp | 5 ++ 6 files changed, 132 insertions(+), 7 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 10881b70f..958fb1afe 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4554,6 +4554,9 @@ getGroupCall group_call_id:int32 = GroupCall; //@description Joins a group call @group_call_id Group call identifier @payload Group join payload, received from tgcalls. Use null to cancel previous joinGroupCall request @source Caller synchronization source identifier; received from tgcalls @is_muted True, if the user's microphone is muted joinGroupCall group_call_id:int32 payload:groupCallPayload source:int32 is_muted:Bool = GroupCallJoinResponse; +//@description Sets group call title. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title New group call title; 1-128 characters +setGroupCallTitle group_call_id:int32 title:string = Ok; + //@description Toggles whether new participants of a group call can be unmuted only by administrators of the group call. Requires groupCall.can_change_mute_new_participants group call flag //@group_call_id Group call identifier @mute_new_participants New value of the mute_new_participants setting toggleGroupCallMuteNewParticipants group_call_id:int32 mute_new_participants:Bool = Ok; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index ef79e650b..4c2fbb0af 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -227,6 +227,38 @@ class JoinGroupCallQuery : public Td::ResultHandler { } }; +class EditGroupCallTitleQuery : public Td::ResultHandler { + Promise promise_; + + public: + explicit EditGroupCallTitleQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(InputGroupCallId input_group_call_id, const string &title) { + send_query(G()->net_query_creator().create( + telegram_api::phone_editGroupCallTitle(input_group_call_id.get_input_group_call(), title))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for EditGroupCallTitleQuery: " << to_string(ptr); + td->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); + } + + void on_error(uint64 id, Status status) override { + if (status.message() == "GROUPCALL_NOT_MODIFIED") { + promise_.set_value(Unit()); + return; + } + promise_.set_error(std::move(status)); + } +}; + class ToggleGroupCallSettingsQuery : public Td::ResultHandler { Promise promise_; @@ -440,6 +472,7 @@ struct GroupCallManager::GroupCall { bool have_pending_mute_new_participants = false; bool pending_mute_new_participants = false; + string pending_title; }; struct GroupCallManager::GroupCallParticipants { @@ -867,7 +900,13 @@ void GroupCallManager::finish_check_group_call_is_joined(InputGroupCallId input_ check_group_call_is_joined_timeout_.set_timeout_in(group_call->group_call_id.get(), next_timeout); } +const string &GroupCallManager::get_group_call_title(const GroupCall *group_call) { + CHECK(group_call != nullptr); + return group_call->pending_title.empty() ? group_call->title : group_call->pending_title; +} + bool GroupCallManager::get_group_call_mute_new_participants(const GroupCall *group_call) { + CHECK(group_call != nullptr); return group_call->have_pending_mute_new_participants ? group_call->pending_mute_new_participants : group_call->mute_new_participants; } @@ -1793,6 +1832,63 @@ void GroupCallManager::process_group_call_after_join_requests(InputGroupCallId i } } +void GroupCallManager::set_group_call_title(GroupCallId group_call_id, string title, Promise &&promise) { + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || !group_call->can_be_managed) { + return promise.set_error(Status::Error(400, "Can't change group call title")); + } + + if (title == get_group_call_title(group_call)) { + return promise.set_value(Unit()); + } + + // there is no reason to save promise; we will send an update with actual value anyway + + if (group_call->pending_title.empty()) { + send_edit_group_call_title_query(input_group_call_id, title); + } + group_call->pending_title = std::move(title); + send_update_group_call(group_call, "set_group_call_title"); + promise.set_value(Unit()); +} + +void GroupCallManager::send_edit_group_call_title_query(InputGroupCallId input_group_call_id, const string &title) { + auto promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, title](Result result) { + send_closure(actor_id, &GroupCallManager::on_edit_group_call_title, input_group_call_id, title, std::move(result)); + }); + td_->create_handler(std::move(promise))->send(input_group_call_id, title); +} + +void GroupCallManager::on_edit_group_call_title(InputGroupCallId input_group_call_id, const string &title, + Result &&result) { + if (G()->close_flag()) { + return; + } + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active) { + return; + } + + if (group_call->pending_title != title && group_call->can_be_managed) { + // need to send another request + send_edit_group_call_title_query(input_group_call_id, group_call->pending_title); + return; + } + + bool is_different = group_call->pending_title != group_call->title; + if (is_different && group_call->can_be_managed) { + LOG(ERROR) << "Failed to set title to " << group_call->pending_title << " in " << input_group_call_id << ": " + << result.error(); + } + group_call->pending_title.clear(); + if (is_different) { + send_update_group_call(group_call, "on_set_group_call_title failed"); + } +} + void GroupCallManager::toggle_group_call_mute_new_participants(GroupCallId group_call_id, bool mute_new_participants, Promise &&promise) { TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); @@ -1837,18 +1933,17 @@ void GroupCallManager::on_toggle_group_call_mute_new_participants(InputGroupCall } auto *group_call = get_group_call(input_group_call_id); - if (group_call == nullptr || !group_call->is_inited || !group_call->is_active) { + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || + !group_call->have_pending_mute_new_participants) { return; } - CHECK(group_call->have_pending_mute_new_participants); if (result.is_error()) { group_call->have_pending_mute_new_participants = false; if (group_call->can_be_managed && group_call->allowed_change_mute_new_participants) { LOG(ERROR) << "Failed to set mute_new_participants to " << mute_new_participants << " in " << input_group_call_id << ": " << result.error(); } - group_call->have_pending_mute_new_participants = false; if (group_call->pending_mute_new_participants != group_call->mute_new_participants) { send_update_group_call(group_call, "on_toggle_group_call_mute_new_participants failed"); } @@ -2412,8 +2507,11 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrtitle && call.version >= group_call->version) { + string old_group_call_title = get_group_call_title(group_call); group_call->title = std::move(call.title); - need_update = true; + if (old_group_call_title != get_group_call_title(group_call)) { + need_update = true; + } } if (call.can_be_managed != group_call->can_be_managed) { group_call->can_be_managed = call.can_be_managed; @@ -2709,9 +2807,10 @@ tl_object_ptr GroupCallManager::get_group_call_object( bool can_change_mute_new_participants = group_call->is_active && group_call->can_be_managed && group_call->allowed_change_mute_new_participants; return td_api::make_object( - group_call->group_call_id.get(), group_call->title, group_call->is_active, is_joined, group_call->need_rejoin, - can_self_unmute, group_call->can_be_managed, group_call->participant_count, group_call->loaded_all_participants, - std::move(recent_speakers), mute_new_participants, can_change_mute_new_participants, group_call->duration); + group_call->group_call_id.get(), get_group_call_title(group_call), group_call->is_active, is_joined, + group_call->need_rejoin, can_self_unmute, group_call->can_be_managed, group_call->participant_count, + group_call->loaded_all_participants, std::move(recent_speakers), mute_new_participants, + can_change_mute_new_participants, group_call->duration); } tl_object_ptr GroupCallManager::get_update_group_call_object( diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 316b1cbab..a44b51fc5 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -52,6 +52,8 @@ class GroupCallManager : public Actor { int32 audio_source, bool is_muted, Promise> &&promise); + void set_group_call_title(GroupCallId group_call_id, string title, Promise &&promise); + void toggle_group_call_mute_new_participants(GroupCallId group_call_id, bool mute_new_participants, Promise &&promise); @@ -135,6 +137,8 @@ class GroupCallManager : public Actor { void finish_check_group_call_is_joined(InputGroupCallId input_group_call_id, int32 audio_source, Result &&result); + static const string &get_group_call_title(const GroupCall *group_call); + static bool get_group_call_mute_new_participants(const GroupCall *group_call); bool need_group_call_participants(InputGroupCallId input_group_call_id) const; @@ -180,6 +184,10 @@ class GroupCallManager : public Actor { static GroupCallParticipant *get_group_call_participant(GroupCallParticipants *group_call_participants, UserId user_id); + void send_edit_group_call_title_query(InputGroupCallId input_group_call_id, const string &title); + + void on_edit_group_call_title(InputGroupCallId input_group_call_id, const string &title, Result &&result); + void send_toggle_group_call_mute_new_participants_query(InputGroupCallId input_group_call_id, bool mute_new_participants); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 201cad534..7545cf83b 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5989,6 +5989,14 @@ void Td::on_request(uint64 id, td_api::joinGroupCall &request) { request.source_, request.is_muted_, std::move(promise)); } +void Td::on_request(uint64 id, td_api::setGroupCallTitle &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.title_); + CREATE_OK_REQUEST_PROMISE(); + group_call_manager_->set_group_call_title(GroupCallId(request.group_call_id_), std::move(request.title_), + std::move(promise)); +} + void Td::on_request(uint64 id, const td_api::toggleGroupCallMuteNewParticipants &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 829ece5f5..c60301b92 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -705,6 +705,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::joinGroupCall &request); + void on_request(uint64 id, td_api::setGroupCallTitle &request); + void on_request(uint64 id, const td_api::toggleGroupCallMuteNewParticipants &request); void on_request(uint64 id, const td_api::inviteGroupCallParticipants &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index e5ca054b2..9bf52e084 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2679,6 +2679,11 @@ class CliClient final : public Actor { true)); } else if (op == "jgcc") { send_request(td_api::make_object(as_group_call_id(args), nullptr, 0, true)); + } else if (op == "sgct") { + string chat_id; + string title; + get_args(args, chat_id, title); + send_request(td_api::make_object(as_group_call_id(chat_id), title)); } else if (op == "tgcmnp" || op == "tgcmnpe") { send_request( td_api::make_object(as_group_call_id(args), op == "tgcmnpe")); From 13319350d385282a38d52122d4f1cb2c3cda9065 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 5 Mar 2021 11:36:44 +0300 Subject: [PATCH 004/281] Support zero audio_source. --- td/telegram/GroupCallManager.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 4c2fbb0af..bc0456fdd 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -366,6 +366,7 @@ class CheckGroupCallQuery : public Td::ResultHandler { } void send(InputGroupCallId input_group_call_id, int32 audio_source) { + CHECK(audio_source != 0); send_query(G()->net_query_creator().create( telegram_api::phone_checkGroupCall(input_group_call_id.get_input_group_call(), audio_source))); } @@ -542,12 +543,12 @@ void GroupCallManager::on_check_group_call_is_joined_timeout(GroupCallId group_c auto *group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); + auto audio_source = group_call->audio_source; if (!group_call->is_joined || pending_join_requests_.count(input_group_call_id) != 0 || - check_group_call_is_joined_timeout_.has_timeout(group_call_id.get())) { + check_group_call_is_joined_timeout_.has_timeout(group_call_id.get()) || audio_source == 0) { return; } - auto audio_source = group_call->audio_source; auto promise = PromiseCreator::lambda( [actor_id = actor_id(this), input_group_call_id, audio_source](Result &&result) mutable { if (result.is_error() && result.error().message() == "GROUPCALL_JOIN_MISSING") { @@ -890,6 +891,7 @@ void GroupCallManager::finish_check_group_call_is_joined(InputGroupCallId input_ auto *group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); + CHECK(audio_source != 0); if (!group_call->is_joined || pending_join_requests_.count(input_group_call_id) != 0 || check_group_call_is_joined_timeout_.has_timeout(group_call->group_call_id.get()) || group_call->audio_source != audio_source) { @@ -1055,12 +1057,6 @@ void GroupCallManager::on_update_group_call_participants( auto group_call = get_group_call(input_group_call_id); for (auto &group_call_participant : participants) { GroupCallParticipant participant(group_call_participant); - if (participant.user_id == td_->contacts_manager_->get_my_id() && group_call != nullptr && - group_call->is_inited && group_call->is_joined && - (participant.joined_date == 0) == (participant.audio_source == group_call->audio_source)) { - on_group_call_left_impl(group_call, participant.joined_date == 0); - need_update = true; - } if (participant.joined_date == 0) { diff--; remove_recent_group_call_speaker(input_group_call_id, participant.user_id); @@ -1783,8 +1779,10 @@ bool GroupCallManager::on_join_group_call_response(InputGroupCallId input_group_ group_call->joined_date = G()->unix_time(); group_call->audio_source = it->second->audio_source; it->second->promise.set_value(result.move_as_ok()); - check_group_call_is_joined_timeout_.set_timeout_in(group_call->group_call_id.get(), - CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); + if (group_call->audio_source != 0) { + check_group_call_is_joined_timeout_.set_timeout_in(group_call->group_call_id.get(), + CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); + } need_update = true; } pending_join_requests_.erase(it); @@ -2019,6 +2017,9 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ } if (audio_source == 0) { audio_source = group_call->audio_source; + if (audio_source == 0) { + return promise.set_error(Status::Error(400, "Can't speak without joining the group call")); + } } bool recursive = false; @@ -2027,7 +2028,7 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ } else { recursive = true; } - if (audio_source != group_call->audio_source && !recursive && is_speaking && + if (group_call->audio_source != 0 && audio_source != group_call->audio_source && !recursive && is_speaking && check_group_call_is_joined_timeout_.has_timeout(group_call_id.get())) { check_group_call_is_joined_timeout_.set_timeout_in(group_call_id.get(), CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); } @@ -2710,6 +2711,7 @@ void GroupCallManager::on_group_call_recent_speakers_updated(const GroupCall *gr UserId GroupCallManager::set_group_call_participant_is_speaking_by_source(InputGroupCallId input_group_call_id, int32 audio_source, bool is_speaking, int32 date) { + CHECK(audio_source != 0); auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it == group_call_participants_.end()) { return UserId(); From 48eaccdf60d0cc27feddc2664db0b3874604285e Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 5 Mar 2021 12:39:57 +0300 Subject: [PATCH 005/281] Add flag GroupCallParticipant.is_self. --- td/telegram/GroupCallManager.cpp | 23 +++++++++++------------ td/telegram/GroupCallParticipant.cpp | 15 ++++++++++----- td/telegram/GroupCallParticipant.h | 5 +++-- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index bc0456fdd..a0fd33b8f 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1162,10 +1162,10 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup auto my_participant = get_group_call_participant(participants_it->second.get(), my_user_id); for (auto &participant : participants) { on_participant_speaking_in_group_call(input_group_call_id, participant); - if (participant.user_id == my_user_id && (my_participant == nullptr || my_participant->is_fake || - my_participant->joined_date < participant.joined_date || - (my_participant->joined_date <= participant.joined_date && - my_participant->audio_source != participant.audio_source))) { + if (participant.is_self && (my_participant == nullptr || my_participant->is_fake || + my_participant->joined_date < participant.joined_date || + (my_participant->joined_date <= participant.joined_date && + my_participant->audio_source != participant.audio_source))) { process_group_call_participant(input_group_call_id, std::move(participant)); } } @@ -1179,7 +1179,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup group_call->version = version; for (auto &participant : participants) { GroupCallParticipant group_call_participant(participant); - if (group_call_participant.user_id == td_->contacts_manager_->get_my_id() && group_call->is_joined && + if (group_call_participant.is_self && group_call->is_joined && (group_call_participant.joined_date == 0) == (group_call_participant.audio_source == group_call->audio_source)) { is_left = true; @@ -1282,7 +1282,7 @@ void GroupCallManager::on_sync_group_call_participants_failed(InputGroupCallId i int64 GroupCallManager::get_real_participant_order(const GroupCallParticipant &participant, int64 min_order) const { auto real_order = participant.get_real_order(); - if (real_order < min_order && participant.user_id == td_->contacts_manager_->get_my_id()) { + if (real_order < min_order && participant.is_self) { return min_order; } if (real_order >= min_order) { @@ -1358,7 +1358,7 @@ void GroupCallManager::process_group_call_participants( // not synced user, needs to be deleted if (participant.order != 0) { CHECK(participant.order >= participants_it->second->min_order); - if (participant.user_id == td_->contacts_manager_->get_my_id()) { + if (participant.is_self) { if (participant.order != min_order) { participant.order = min_order; send_update_group_call_participant(input_group_call_id, participant); @@ -1400,9 +1400,8 @@ void GroupCallManager::process_group_call_participants( bool GroupCallManager::update_group_call_participant_can_be_muted(bool can_manage, const GroupCallParticipants *participants, GroupCallParticipant &participant) { - bool is_self = participant.user_id == td_->contacts_manager_->get_my_id(); bool is_admin = td::contains(participants->administrator_user_ids, participant.user_id); - return participant.update_can_be_muted(can_manage, is_self, is_admin); + return participant.update_can_be_muted(can_manage, is_admin); } void GroupCallManager::update_group_call_participants_can_be_muted(InputGroupCallId input_group_call_id, @@ -1429,7 +1428,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou LOG(INFO) << "Process " << participant << " in " << input_group_call_id; - if (participant.user_id == td_->contacts_manager_->get_my_id()) { + if (participant.is_self) { auto *group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); if (group_call->is_joined && group_call->is_active) { @@ -1596,6 +1595,7 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, if (group_call->is_inited && td_->contacts_manager_->have_user_force(td_->contacts_manager_->get_my_id())) { GroupCallParticipant group_call_participant; + group_call_participant.is_self = true; group_call_participant.user_id = td_->contacts_manager_->get_my_id(); group_call_participant.audio_source = audio_source; group_call_participant.joined_date = G()->unix_time(); @@ -2107,12 +2107,11 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ return promise.set_error(Status::Error(400, "Can't find group call participant")); } - bool is_self = user_id == td_->contacts_manager_->get_my_id(); bool can_manage = can_manage_group_call(input_group_call_id); bool is_admin = td::contains(participants->administrator_user_ids, user_id); auto participant_copy = *participant; - if (!participant_copy.set_pending_is_muted(is_muted, can_manage, is_self, is_admin)) { + if (!participant_copy.set_pending_is_muted(is_muted, can_manage, is_admin)) { return promise.set_error(Status::Error(400, PSLICE() << "Can't " << (is_muted ? "" : "un") << "mute user")); } if (participant_copy == *participant) { diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index c6e62609e..22e0484a6 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -23,6 +23,7 @@ GroupCallParticipant::GroupCallParticipant(const tl_object_ptrcan_self_unmute_; server_is_muted_by_admin = participant->muted_ && !participant->can_self_unmute_; server_is_muted_locally = participant->muted_by_you_; + is_self = participant->self_; if ((participant->flags_ & telegram_api::groupCallParticipant::VOLUME_MASK) != 0) { volume_level = participant->volume_; if (volume_level < MIN_VOLUME_LEVEL || volume_level > MAX_VOLUME_LEVEL) { @@ -43,7 +44,7 @@ GroupCallParticipant::GroupCallParticipant(const tl_object_ptrjust_joined_; - is_min = (participant->flags_ & telegram_api::groupCallParticipant::MIN_MASK) != 0; + is_min = participant->min_; } bool GroupCallParticipant::is_versioned_update(const tl_object_ptr &participant) { @@ -88,6 +89,10 @@ void GroupCallParticipant::update_from(const GroupCallParticipant &old_participa is_volume_level_local = true; volume_level = old_participant.volume_level; } + + if (audio_source == old_participant.audio_source) { + is_self = old_participant.is_self; + } } is_min = false; @@ -101,7 +106,7 @@ void GroupCallParticipant::update_from(const GroupCallParticipant &old_participa pending_is_muted_generation = old_participant.pending_is_muted_generation; } -bool GroupCallParticipant::update_can_be_muted(bool can_manage, bool is_self, bool is_admin) { +bool GroupCallParticipant::update_can_be_muted(bool can_manage, bool is_admin) { bool is_muted_by_admin = get_is_muted_by_admin(); bool is_muted_by_themselves = get_is_muted_by_themselves(); bool is_muted_locally = get_is_muted_locally(); @@ -145,8 +150,8 @@ bool GroupCallParticipant::update_can_be_muted(bool can_manage, bool is_self, bo return false; } -bool GroupCallParticipant::set_pending_is_muted(bool is_muted, bool can_manage, bool is_self, bool is_admin) { - update_can_be_muted(can_manage, is_self, is_admin); +bool GroupCallParticipant::set_pending_is_muted(bool is_muted, bool can_manage, bool is_admin) { + update_can_be_muted(can_manage, is_admin); if (is_muted) { if (!can_be_muted_for_all_users && !can_be_muted_only_for_self) { return false; @@ -201,7 +206,7 @@ bool GroupCallParticipant::set_pending_is_muted(bool is_muted, bool can_manage, } have_pending_is_muted = true; - update_can_be_muted(can_manage, is_self, is_admin); + update_can_be_muted(can_manage, is_admin); return true; } diff --git a/td/telegram/GroupCallParticipant.h b/td/telegram/GroupCallParticipant.h index 3d665d8d4..3496da73f 100644 --- a/td/telegram/GroupCallParticipant.h +++ b/td/telegram/GroupCallParticipant.h @@ -27,6 +27,7 @@ struct GroupCallParticipant { bool server_is_muted_by_themselves = false; bool server_is_muted_by_admin = false; bool server_is_muted_locally = false; + bool is_self = false; bool can_be_muted_for_all_users = false; bool can_be_unmuted_for_all_users = false; @@ -60,9 +61,9 @@ struct GroupCallParticipant { void update_from(const GroupCallParticipant &old_participant); - bool update_can_be_muted(bool can_manage, bool is_self, bool is_admin); + bool update_can_be_muted(bool can_manage, bool is_admin); - bool set_pending_is_muted(bool is_muted, bool can_manage, bool is_self, bool is_admin); + bool set_pending_is_muted(bool is_muted, bool can_manage, bool is_admin); int64 get_real_order() const { return (static_cast(max(active_date, local_active_date)) << 32) + joined_date; From e660e12a614030d89948b8fb2781258cd0dfe7c7 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 5 Mar 2021 12:50:39 +0300 Subject: [PATCH 006/281] Pass Td to get_group_call_participant_object. --- td/telegram/GroupCallManager.cpp | 4 ++-- td/telegram/GroupCallParticipant.cpp | 8 ++++---- td/telegram/GroupCallParticipant.h | 5 ++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index a0fd33b8f..6e72aa5ae 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -2821,8 +2821,8 @@ tl_object_ptr GroupCallManager::get_update_group_call_o tl_object_ptr GroupCallManager::get_update_group_call_participant_object( GroupCallId group_call_id, const GroupCallParticipant &participant) { - return td_api::make_object( - group_call_id.get(), participant.get_group_call_participant_object(td_->contacts_manager_.get())); + return td_api::make_object(group_call_id.get(), + participant.get_group_call_participant_object(td_)); } void GroupCallManager::send_update_group_call(const GroupCall *group_call, const char *source) { diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index 22e0484a6..068d3c9c7 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -7,6 +7,7 @@ #include "td/telegram/GroupCallParticipant.h" #include "td/telegram/ContactsManager.h" +#include "td/telegram/Td.h" #include "td/utils/logging.h" @@ -210,15 +211,14 @@ bool GroupCallParticipant::set_pending_is_muted(bool is_muted, bool can_manage, return true; } -td_api::object_ptr GroupCallParticipant::get_group_call_participant_object( - ContactsManager *contacts_manager) const { +td_api::object_ptr GroupCallParticipant::get_group_call_participant_object(Td *td) const { if (!is_valid()) { return nullptr; } return td_api::make_object( - contacts_manager->get_user_id_object(user_id, "get_group_call_participant_object"), audio_source, is_speaking, - can_be_muted_for_all_users, can_be_unmuted_for_all_users, can_be_muted_only_for_self, + td->contacts_manager_->get_user_id_object(user_id, "get_group_call_participant_object"), audio_source, + is_speaking, can_be_muted_for_all_users, can_be_unmuted_for_all_users, can_be_muted_only_for_self, can_be_unmuted_only_for_self, get_is_muted_for_all_users(), get_is_muted_locally(), get_is_muted_by_themselves(), get_volume_level(), order); } diff --git a/td/telegram/GroupCallParticipant.h b/td/telegram/GroupCallParticipant.h index 3496da73f..9395b118a 100644 --- a/td/telegram/GroupCallParticipant.h +++ b/td/telegram/GroupCallParticipant.h @@ -15,7 +15,7 @@ namespace td { -class ContactsManager; +class Td; struct GroupCallParticipant { UserId user_id; @@ -83,8 +83,7 @@ struct GroupCallParticipant { int32 get_volume_level() const; - td_api::object_ptr get_group_call_participant_object( - ContactsManager *contacts_manager) const; + td_api::object_ptr get_group_call_participant_object(Td *td) const; }; bool operator==(const GroupCallParticipant &lhs, const GroupCallParticipant &rhs); From af3070d5723785eeb6b6a6cef3171eae4e0e23b1 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 5 Mar 2021 13:43:21 +0300 Subject: [PATCH 007/281] Improve self-check. --- td/telegram/GroupCallManager.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 6e72aa5ae..b8513d514 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1158,8 +1158,8 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup auto version = it->first; auto &participants = it->second; if (version <= group_call->version) { - auto my_user_id = td_->contacts_manager_->get_my_id(); - auto my_participant = get_group_call_participant(participants_it->second.get(), my_user_id); + auto my_participant = + get_group_call_participant(participants_it->second.get(), td_->contacts_manager_->get_my_id()); for (auto &participant : participants) { on_participant_speaking_in_group_call(input_group_call_id, participant); if (participant.is_self && (my_participant == nullptr || my_participant->is_fake || @@ -2197,15 +2197,15 @@ void GroupCallManager::set_group_call_participant_volume_level(GroupCallId group return promise.set_error(Status::Error(400, "Have no access to the user")); } - if (user_id == td_->contacts_manager_->get_my_id()) { - return promise.set_error(Status::Error(400, "Can't change self volume level")); - } - auto participant = get_group_call_participant(input_group_call_id, user_id); if (participant == nullptr) { return promise.set_error(Status::Error(400, "Can't find group call participant")); } + if (participant->is_self) { + return promise.set_error(Status::Error(400, "Can't change self volume level")); + } + if (participant->get_volume_level() == volume_level) { return promise.set_value(Unit()); } From a93189daded569c026ac4a5f6b21530e055d1589 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 5 Mar 2021 14:40:54 +0300 Subject: [PATCH 008/281] Support chats as group call participants. --- td/generate/scheme/td_api.tl | 16 +-- td/telegram/GroupCallManager.cpp | 181 +++++++++++++-------------- td/telegram/GroupCallManager.h | 21 ++-- td/telegram/GroupCallParticipant.cpp | 16 +-- td/telegram/GroupCallParticipant.h | 6 +- td/telegram/MessagesManager.cpp | 9 +- td/telegram/MessagesManager.h | 6 +- td/telegram/Td.cpp | 7 +- 8 files changed, 129 insertions(+), 133 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 958fb1afe..e815f1b09 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2101,8 +2101,8 @@ callStateDiscarded reason:CallDiscardReason need_rating:Bool need_debug_informat callStateError error:error = CallState; -//@description Describes a recently speaking user in a group call @user_id User identifier @is_speaking True, is the user has spoken recently -groupCallRecentSpeaker user_id:int32 is_speaking:Bool = GroupCallRecentSpeaker; +//@description Describes a recently speaking participant in a group call @speaker Speaking participantt @is_speaking True, is the user has spoken recently +groupCallRecentSpeaker speaker:MessageSender is_speaking:Bool = GroupCallRecentSpeaker; //@description Describes a group call //@id Group call identifier @@ -2135,7 +2135,7 @@ groupCallJoinResponseCandidate port:string protocol:string network:string genera groupCallJoinResponse payload:groupCallPayload candidates:vector = GroupCallJoinResponse; //@description Represents a group call participant -//@user_id Identifier of the user +//@participant Identifier of the group call participant //@source User's synchronization source //@is_speaking True, if the participant is speaking as set by setGroupCallParticipantIsSpeaking //@can_be_muted_for_all_users True, if the current user can mute the participant for all other group call participants @@ -2147,7 +2147,7 @@ groupCallJoinResponse payload:groupCallPayload candidates:vector &&promise) : promise_(std::move(promise)) { } - void send(InputGroupCallId input_group_call_id, vector> input_peers, - vector audio_sources) { + void send(InputGroupCallId input_group_call_id, vector> &&input_peers, + vector &&audio_sources) { input_group_call_id_ = input_group_call_id; auto limit = narrow_cast(max(input_peers.size(), audio_sources.size())); send_query(G()->net_query_creator().create( @@ -326,8 +326,8 @@ class EditGroupCallParticipantQuery : public Td::ResultHandler { explicit EditGroupCallParticipantQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(InputGroupCallId input_group_call_id, UserId user_id, bool is_muted, int32 volume_level) { - auto input_peer = MessagesManager::get_input_peer_force(DialogId(user_id)); + void send(InputGroupCallId input_group_call_id, DialogId dialog_id, bool is_muted, int32 volume_level) { + auto input_peer = MessagesManager::get_input_peer_force(dialog_id); CHECK(input_peer != nullptr); int32 flags = 0; @@ -489,9 +489,9 @@ struct GroupCallManager::GroupCallParticipants { }; struct GroupCallManager::GroupCallRecentSpeakers { - vector> users; // user + time; sorted by time + vector> users; // participant + time; sorted by time bool is_changed = false; - vector> last_sent_users; + vector> last_sent_users; }; struct GroupCallManager::PendingJoinRequest { @@ -587,7 +587,7 @@ void GroupCallManager::on_send_speaking_action_timeout(GroupCallId group_call_id return; } - on_user_speaking_in_group_call(group_call_id, td_->contacts_manager_->get_my_id(), G()->unix_time()); + on_user_speaking_in_group_call(group_call_id, DialogId(td_->contacts_manager_->get_my_id()), G()->unix_time()); pending_send_speaking_action_timeout_.add_timeout_in(group_call_id.get(), 4.0); @@ -1034,14 +1034,14 @@ GroupCallManager::GroupCallParticipants *GroupCallManager::add_group_call_partic } GroupCallParticipant *GroupCallManager::get_group_call_participant(InputGroupCallId input_group_call_id, - UserId user_id) { - return get_group_call_participant(add_group_call_participants(input_group_call_id), user_id); + DialogId dialog_id) { + return get_group_call_participant(add_group_call_participants(input_group_call_id), dialog_id); } GroupCallParticipant *GroupCallManager::get_group_call_participant(GroupCallParticipants *group_call_participants, - UserId user_id) { + DialogId dialog_id) { for (auto &group_call_participant : group_call_participants->participants) { - if (group_call_participant.user_id == user_id) { + if (group_call_participant.dialog_id == dialog_id) { return &group_call_participant; } } @@ -1059,7 +1059,7 @@ void GroupCallManager::on_update_group_call_participants( GroupCallParticipant participant(group_call_participant); if (participant.joined_date == 0) { diff--; - remove_recent_group_call_speaker(input_group_call_id, participant.user_id); + remove_recent_group_call_speaker(input_group_call_id, participant.dialog_id); } else { if (participant.is_just_joined) { diff++; @@ -1103,9 +1103,9 @@ void GroupCallManager::on_update_group_call_participants( for (auto &group_call_participant : participants) { GroupCallParticipant participant(group_call_participant); if (participant.is_min && participant.joined_date != 0) { - auto old_participant = get_group_call_participant(group_call_participants, participant.user_id); + auto old_participant = get_group_call_participant(group_call_participants, participant.dialog_id); if (old_participant == nullptr) { - LOG(INFO) << "Can't apply min update about " << participant.user_id << " in " << input_group_call_id; + LOG(INFO) << "Can't apply min update about " << participant.dialog_id << " in " << input_group_call_id; // TODO instead of synchronization, such participants can be received through GetGroupCallParticipantQuery on_receive_group_call_version(input_group_call_id, version, true); return; @@ -1159,7 +1159,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup auto &participants = it->second; if (version <= group_call->version) { auto my_participant = - get_group_call_participant(participants_it->second.get(), td_->contacts_manager_->get_my_id()); + get_group_call_participant(participants_it->second.get(), DialogId(td_->contacts_manager_->get_my_id())); for (auto &participant : participants) { on_participant_speaking_in_group_call(input_group_call_id, participant); if (participant.is_self && (my_participant == nullptr || my_participant->is_fake || @@ -1307,13 +1307,13 @@ void GroupCallManager::process_group_call_participants( return; } - std::unordered_set old_participant_user_ids; + std::unordered_set old_participant_dialog_ids; if (is_sync) { auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it != group_call_participants_.end()) { CHECK(participants_it->second != nullptr); for (auto &participant : participants_it->second->participants) { - old_participant_user_ids.insert(participant.user_id); + old_participant_dialog_ids.insert(participant.dialog_id); } } } @@ -1338,7 +1338,7 @@ void GroupCallManager::process_group_call_participants( min_order = real_order; } if (is_sync) { - old_participant_user_ids.erase(group_call_participant.user_id); + old_participant_dialog_ids.erase(group_call_participant.dialog_id); } process_group_call_participant(input_group_call_id, std::move(group_call_participant)); } @@ -1349,7 +1349,7 @@ void GroupCallManager::process_group_call_participants( auto &group_participants = participants_it->second->participants; for (auto participant_it = group_participants.begin(); participant_it != group_participants.end();) { auto &participant = *participant_it; - if (old_participant_user_ids.count(participant.user_id) == 0) { + if (old_participant_dialog_ids.count(participant.dialog_id) == 0) { CHECK(participant.order == 0 || participant.order >= min_order); ++participant_it; continue; @@ -1400,7 +1400,8 @@ void GroupCallManager::process_group_call_participants( bool GroupCallManager::update_group_call_participant_can_be_muted(bool can_manage, const GroupCallParticipants *participants, GroupCallParticipant &participant) { - bool is_admin = td::contains(participants->administrator_user_ids, participant.user_id); + bool is_admin = participant.dialog_id.get_type() == DialogType::User && + td::contains(participants->administrator_user_ids, participant.dialog_id.get_user_id()); return participant.update_can_be_muted(can_manage, is_admin); } @@ -1444,13 +1445,13 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou auto *participants = add_group_call_participants(input_group_call_id); for (size_t i = 0; i < participants->participants.size(); i++) { auto &old_participant = participants->participants[i]; - if (old_participant.user_id == participant.user_id) { + if (old_participant.dialog_id == participant.dialog_id) { if (participant.joined_date == 0) { LOG(INFO) << "Remove " << old_participant; if (old_participant.order != 0) { send_update_group_call_participant(input_group_call_id, participant); } - remove_recent_group_call_speaker(input_group_call_id, participant.user_id); + remove_recent_group_call_speaker(input_group_call_id, participant.dialog_id); participants->participants.erase(participants->participants.begin() + i); return -1; } @@ -1473,7 +1474,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (participant.joined_date == 0) { LOG(INFO) << "Remove unknown " << participant; - remove_recent_group_call_speaker(input_group_call_id, participant.user_id); + remove_recent_group_call_speaker(input_group_call_id, participant.dialog_id); return -1; } @@ -1596,7 +1597,7 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, if (group_call->is_inited && td_->contacts_manager_->have_user_force(td_->contacts_manager_->get_my_id())) { GroupCallParticipant group_call_participant; group_call_participant.is_self = true; - group_call_participant.user_id = td_->contacts_manager_->get_my_id(); + group_call_participant.dialog_id = DialogId(td_->contacts_manager_->get_my_id()); group_call_participant.audio_source = audio_source; group_call_participant.joined_date = G()->unix_time(); // if can_self_unmute has never been inited from self-participant, @@ -2032,9 +2033,9 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ check_group_call_is_joined_timeout_.has_timeout(group_call_id.get())) { check_group_call_is_joined_timeout_.set_timeout_in(group_call_id.get(), CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); } - UserId user_id = + DialogId dialog_id = set_group_call_participant_is_speaking_by_source(input_group_call_id, audio_source, is_speaking, date); - if (!user_id.is_valid()) { + if (!dialog_id.is_valid()) { if (!recursive) { auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, audio_source, is_speaking, promise = std::move(promise), date](Result &&result) mutable { @@ -2059,7 +2060,7 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ } if (is_speaking) { - on_user_speaking_in_group_call(group_call_id, user_id, date, recursive); + on_user_speaking_in_group_call(group_call_id, dialog_id, date, recursive); } if (group_call->audio_source == audio_source && group_call->dialog_id.is_valid() && @@ -2073,8 +2074,8 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ promise.set_value(Unit()); } -void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_call_id, UserId user_id, bool is_muted, - Promise &&promise) { +void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_call_id, DialogId dialog_id, + bool is_muted, Promise &&promise) { TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); auto *group_call = get_group_call(input_group_call_id); @@ -2084,31 +2085,29 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ if (!group_call->is_joined) { if (pending_join_requests_.count(input_group_call_id) || group_call->need_rejoin) { group_call->after_join.push_back( - PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, user_id, is_muted, + PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, dialog_id, is_muted, promise = std::move(promise)](Result &&result) mutable { if (result.is_error()) { promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); } else { - send_closure(actor_id, &GroupCallManager::toggle_group_call_participant_is_muted, group_call_id, user_id, - is_muted, std::move(promise)); + send_closure(actor_id, &GroupCallManager::toggle_group_call_participant_is_muted, group_call_id, + dialog_id, is_muted, std::move(promise)); } })); return; } return promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); } - if (!td_->contacts_manager_->have_input_user(user_id)) { - return promise.set_error(Status::Error(400, "Have no access to the user")); - } auto participants = add_group_call_participants(input_group_call_id); - auto participant = get_group_call_participant(participants, user_id); + auto participant = get_group_call_participant(participants, dialog_id); if (participant == nullptr) { return promise.set_error(Status::Error(400, "Can't find group call participant")); } bool can_manage = can_manage_group_call(input_group_call_id); - bool is_admin = td::contains(participants->administrator_user_ids, user_id); + bool is_admin = dialog_id.get_type() == DialogType::User && + td::contains(participants->administrator_user_ids, dialog_id.get_user_id()); auto participant_copy = *participant; if (!participant_copy.set_pending_is_muted(is_muted, can_manage, is_admin)) { @@ -2124,21 +2123,22 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ send_update_group_call_participant(input_group_call_id, *participant); } - auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, user_id, + auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, dialog_id, generation = participant->pending_is_muted_generation, promise = std::move(promise)](Result &&result) mutable { if (result.is_error()) { promise.set_error(result.move_as_error()); } - send_closure(actor_id, &GroupCallManager::on_toggle_group_call_participant_is_muted, input_group_call_id, user_id, + send_closure(actor_id, &GroupCallManager::on_toggle_group_call_participant_is_muted, input_group_call_id, dialog_id, generation, std::move(promise)); }); td_->create_handler(std::move(query_promise)) - ->send(input_group_call_id, user_id, is_muted, 0); + ->send(input_group_call_id, dialog_id, is_muted, 0); } -void GroupCallManager::on_toggle_group_call_participant_is_muted(InputGroupCallId input_group_call_id, UserId user_id, - uint64 generation, Promise &&promise) { +void GroupCallManager::on_toggle_group_call_participant_is_muted(InputGroupCallId input_group_call_id, + DialogId dialog_id, uint64 generation, + Promise &&promise) { if (G()->close_flag()) { return promise.set_value(Unit()); } @@ -2148,7 +2148,7 @@ void GroupCallManager::on_toggle_group_call_participant_is_muted(InputGroupCallI return promise.set_value(Unit()); } - auto participant = get_group_call_participant(input_group_call_id, user_id); + auto participant = get_group_call_participant(input_group_call_id, dialog_id); if (participant == nullptr || participant->pending_is_muted_generation != generation) { return promise.set_value(Unit()); } @@ -2158,7 +2158,7 @@ void GroupCallManager::on_toggle_group_call_participant_is_muted(InputGroupCallI if (participant->server_is_muted_by_themselves != participant->pending_is_muted_by_themselves || participant->server_is_muted_by_admin != participant->pending_is_muted_by_admin || participant->server_is_muted_locally != participant->pending_is_muted_locally) { - LOG(ERROR) << "Failed to mute/unmute " << user_id << " in " << input_group_call_id; + LOG(ERROR) << "Failed to mute/unmute " << dialog_id << " in " << input_group_call_id; if (participant->order != 0) { send_update_group_call_participant(input_group_call_id, *participant); } @@ -2166,7 +2166,7 @@ void GroupCallManager::on_toggle_group_call_participant_is_muted(InputGroupCallI promise.set_value(Unit()); } -void GroupCallManager::set_group_call_participant_volume_level(GroupCallId group_call_id, UserId user_id, +void GroupCallManager::set_group_call_participant_volume_level(GroupCallId group_call_id, DialogId dialog_id, int32 volume_level, Promise &&promise) { TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); if (volume_level < GroupCallParticipant::MIN_VOLUME_LEVEL || volume_level > GroupCallParticipant::MAX_VOLUME_LEVEL) { @@ -2180,24 +2180,21 @@ void GroupCallManager::set_group_call_participant_volume_level(GroupCallId group if (!group_call->is_joined) { if (pending_join_requests_.count(input_group_call_id) || group_call->need_rejoin) { group_call->after_join.push_back( - PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, user_id, volume_level, + PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, dialog_id, volume_level, promise = std::move(promise)](Result &&result) mutable { if (result.is_error()) { promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); } else { - send_closure(actor_id, &GroupCallManager::set_group_call_participant_volume_level, group_call_id, user_id, - volume_level, std::move(promise)); + send_closure(actor_id, &GroupCallManager::set_group_call_participant_volume_level, group_call_id, + dialog_id, volume_level, std::move(promise)); } })); return; } return promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); } - if (!td_->contacts_manager_->have_input_user(user_id)) { - return promise.set_error(Status::Error(400, "Have no access to the user")); - } - auto participant = get_group_call_participant(input_group_call_id, user_id); + auto participant = get_group_call_participant(input_group_call_id, dialog_id); if (participant == nullptr) { return promise.set_error(Status::Error(400, "Can't find group call participant")); } @@ -2216,21 +2213,22 @@ void GroupCallManager::set_group_call_participant_volume_level(GroupCallId group send_update_group_call_participant(input_group_call_id, *participant); } - auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, user_id, + auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, dialog_id, generation = participant->pending_volume_level_generation, promise = std::move(promise)](Result &&result) mutable { if (result.is_error()) { promise.set_error(result.move_as_error()); } - send_closure(actor_id, &GroupCallManager::on_set_group_call_participant_volume_level, input_group_call_id, user_id, - generation, std::move(promise)); + send_closure(actor_id, &GroupCallManager::on_set_group_call_participant_volume_level, input_group_call_id, + dialog_id, generation, std::move(promise)); }); td_->create_handler(std::move(query_promise)) - ->send(input_group_call_id, user_id, false, volume_level); + ->send(input_group_call_id, dialog_id, false, volume_level); } -void GroupCallManager::on_set_group_call_participant_volume_level(InputGroupCallId input_group_call_id, UserId user_id, - uint64 generation, Promise &&promise) { +void GroupCallManager::on_set_group_call_participant_volume_level(InputGroupCallId input_group_call_id, + DialogId dialog_id, uint64 generation, + Promise &&promise) { if (G()->close_flag()) { return promise.set_value(Unit()); } @@ -2240,14 +2238,14 @@ void GroupCallManager::on_set_group_call_participant_volume_level(InputGroupCall return promise.set_value(Unit()); } - auto participant = get_group_call_participant(input_group_call_id, user_id); + auto participant = get_group_call_participant(input_group_call_id, dialog_id); if (participant == nullptr || participant->pending_volume_level_generation != generation) { return promise.set_value(Unit()); } CHECK(participant->pending_volume_level != 0); if (participant->volume_level != participant->pending_volume_level) { - LOG(ERROR) << "Failed to set volume level of " << user_id << " in " << input_group_call_id; + LOG(ERROR) << "Failed to set volume level of " << dialog_id << " in " << input_group_call_id; participant->pending_volume_level = 0; if (participant->order != 0) { send_update_group_call_participant(input_group_call_id, *participant); @@ -2383,7 +2381,7 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ return; } - remove_recent_group_call_speaker(input_group_call_id, td_->contacts_manager_->get_my_id()); + remove_recent_group_call_speaker(input_group_call_id, DialogId(td_->contacts_manager_->get_my_id())); auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it == group_call_participants_.end()) { @@ -2593,10 +2591,10 @@ void GroupCallManager::on_participant_speaking_in_group_call(InputGroupCallId in return; } - on_user_speaking_in_group_call(group_call->group_call_id, participant.user_id, active_date, true); + on_user_speaking_in_group_call(group_call->group_call_id, participant.dialog_id, active_date, true); } -void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, UserId user_id, int32 date, +void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, DialogId dialog_id, int32 date, bool recursive) { if (G()->close_flag()) { return; @@ -2612,34 +2610,35 @@ void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, return; } - if (!td_->contacts_manager_->have_user_force(user_id) || + if (!td_->messages_manager_->have_dialog_info_force(dialog_id) || (!recursive && need_group_call_participants(input_group_call_id, group_call) && - get_group_call_participant(input_group_call_id, user_id) == nullptr)) { - if (recursive) { - LOG(ERROR) << "Failed to find speaking " << user_id << " from " << input_group_call_id; + get_group_call_participant(input_group_call_id, dialog_id) == nullptr)) { + if (recursive || dialog_id.get_type() != DialogType::User) { + LOG(ERROR) << "Failed to find speaking " << dialog_id << " from " << input_group_call_id; } else { - auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, user_id, - date](Result &&result) { - if (!G()->close_flag() && result.is_ok()) { - send_closure(actor_id, &GroupCallManager::on_user_speaking_in_group_call, group_call_id, user_id, date, true); - } - }); + auto query_promise = + PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, dialog_id, date](Result &&result) { + if (!G()->close_flag() && result.is_ok()) { + send_closure(actor_id, &GroupCallManager::on_user_speaking_in_group_call, group_call_id, dialog_id, date, + true); + } + }); vector> input_peers; - input_peers.push_back(MessagesManager::get_input_peer_force(DialogId(user_id))); + input_peers.push_back(MessagesManager::get_input_peer_force(dialog_id)); td_->create_handler(std::move(query_promise)) ->send(input_group_call_id, std::move(input_peers), {}); } return; } - LOG(INFO) << "Add " << user_id << " as recent speaker at " << date << " in " << input_group_call_id; + LOG(INFO) << "Add " << dialog_id << " as recent speaker at " << date << " in " << input_group_call_id; auto &recent_speakers = group_call_recent_speakers_[group_call_id]; if (recent_speakers == nullptr) { recent_speakers = make_unique(); } for (size_t i = 0; i < recent_speakers->users.size(); i++) { - if (recent_speakers->users[i].first == user_id) { + if (recent_speakers->users[i].first == dialog_id) { if (recent_speakers->users[i].second >= date) { LOG(INFO) << "Ignore outdated speaking information"; return; @@ -2656,7 +2655,7 @@ void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, for (size_t i = 0; i <= recent_speakers->users.size(); i++) { if (i == recent_speakers->users.size() || recent_speakers->users[i].second <= date) { - recent_speakers->users.insert(recent_speakers->users.begin() + i, {user_id, date}); + recent_speakers->users.insert(recent_speakers->users.begin() + i, {dialog_id, date}); break; } } @@ -2668,7 +2667,7 @@ void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, on_group_call_recent_speakers_updated(group_call, recent_speakers.get()); } -void GroupCallManager::remove_recent_group_call_speaker(InputGroupCallId input_group_call_id, UserId user_id) { +void GroupCallManager::remove_recent_group_call_speaker(InputGroupCallId input_group_call_id, DialogId dialog_id) { auto *group_call = get_group_call(input_group_call_id); if (group_call == nullptr) { return; @@ -2681,8 +2680,8 @@ void GroupCallManager::remove_recent_group_call_speaker(InputGroupCallId input_g auto &recent_speakers = recent_speakers_it->second; CHECK(recent_speakers != nullptr); for (size_t i = 0; i < recent_speakers->users.size(); i++) { - if (recent_speakers->users[i].first == user_id) { - LOG(INFO) << "Remove " << user_id << " from recent speakers in " << input_group_call_id << " from " + if (recent_speakers->users[i].first == dialog_id) { + LOG(INFO) << "Remove " << dialog_id << " from recent speakers in " << input_group_call_id << " from " << group_call->dialog_id; recent_speakers->users.erase(recent_speakers->users.begin() + i); on_group_call_recent_speakers_updated(group_call, recent_speakers.get()); @@ -2707,13 +2706,13 @@ void GroupCallManager::on_group_call_recent_speakers_updated(const GroupCall *gr recent_speaker_update_timeout_.set_timeout_in(group_call->group_call_id.get(), MAX_RECENT_SPEAKER_UPDATE_DELAY); } -UserId GroupCallManager::set_group_call_participant_is_speaking_by_source(InputGroupCallId input_group_call_id, - int32 audio_source, bool is_speaking, - int32 date) { +DialogId GroupCallManager::set_group_call_participant_is_speaking_by_source(InputGroupCallId input_group_call_id, + int32 audio_source, bool is_speaking, + int32 date) { CHECK(audio_source != 0); auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it == group_call_participants_.end()) { - return UserId(); + return DialogId(); } for (auto &participant : participants_it->second->participants) { @@ -2729,10 +2728,10 @@ UserId GroupCallManager::set_group_call_participant_is_speaking_by_source(InputG } } - return participant.user_id; + return participant.dialog_id; } } - return UserId(); + return DialogId(); } void GroupCallManager::update_group_call_dialog(const GroupCall *group_call, const char *source) { @@ -2762,7 +2761,7 @@ vector> GroupCallManager::get recent_speakers->users.pop_back(); } - vector> recent_speaker_users; + vector> recent_speaker_users; for (auto &recent_speaker : recent_speakers->users) { recent_speaker_users.emplace_back(recent_speaker.first, recent_speaker.second > now - 8); } @@ -2779,10 +2778,10 @@ vector> GroupCallManager::get recent_speaker_update_timeout_.add_timeout_in(group_call->group_call_id.get(), next_timeout); } - auto get_result = [recent_speaker_users] { - return transform(recent_speaker_users, [](const std::pair &recent_speaker_user) { - return td_api::make_object(recent_speaker_user.first.get(), - recent_speaker_user.second); + auto get_result = [recent_speaker_users, messages_manager = td_->messages_manager_.get()] { + return transform(recent_speaker_users, [messages_manager](const std::pair &recent_speaker_user) { + return td_api::make_object( + messages_manager->get_message_sender_object(recent_speaker_user.first), recent_speaker_user.second); }); }; if (recent_speakers->last_sent_users != recent_speaker_users) { diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index a44b51fc5..661fb7327 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -62,10 +62,10 @@ class GroupCallManager : public Actor { void set_group_call_participant_is_speaking(GroupCallId group_call_id, int32 audio_source, bool is_speaking, Promise &&promise, int32 date = 0); - void toggle_group_call_participant_is_muted(GroupCallId group_call_id, UserId user_id, bool is_muted, + void toggle_group_call_participant_is_muted(GroupCallId group_call_id, DialogId dialog_id, bool is_muted, Promise &&promise); - void set_group_call_participant_volume_level(GroupCallId group_call_id, UserId user_id, int32 volume_level, + void set_group_call_participant_volume_level(GroupCallId group_call_id, DialogId dialog_id, int32 volume_level, Promise &&promise); void load_group_call_participants(GroupCallId group_call_id, int32 limit, Promise &&promise); @@ -76,7 +76,8 @@ class GroupCallManager : public Actor { void on_update_group_call(tl_object_ptr group_call_ptr, DialogId dialog_id); - void on_user_speaking_in_group_call(GroupCallId group_call_id, UserId user_id, int32 date, bool recursive = false); + void on_user_speaking_in_group_call(GroupCallId group_call_id, DialogId dialog_id, int32 date, + bool recursive = false); void on_get_group_call_participants(InputGroupCallId input_group_call_id, tl_object_ptr &&participants, bool is_load, @@ -179,10 +180,10 @@ class GroupCallManager : public Actor { GroupCallParticipants *add_group_call_participants(InputGroupCallId input_group_call_id); - GroupCallParticipant *get_group_call_participant(InputGroupCallId input_group_call_id, UserId user_id); + GroupCallParticipant *get_group_call_participant(InputGroupCallId input_group_call_id, DialogId dialog_id); static GroupCallParticipant *get_group_call_participant(GroupCallParticipants *group_call_participants, - UserId user_id); + DialogId dialog_id); void send_edit_group_call_title_query(InputGroupCallId input_group_call_id, const string &title); @@ -194,10 +195,10 @@ class GroupCallManager : public Actor { void on_toggle_group_call_mute_new_participants(InputGroupCallId input_group_call_id, bool mute_new_participants, Result &&result); - void on_toggle_group_call_participant_is_muted(InputGroupCallId input_group_call_id, UserId user_id, + void on_toggle_group_call_participant_is_muted(InputGroupCallId input_group_call_id, DialogId dialog_id, uint64 generation, Promise &&promise); - void on_set_group_call_participant_volume_level(InputGroupCallId input_group_call_id, UserId user_id, + void on_set_group_call_participant_volume_level(InputGroupCallId input_group_call_id, DialogId dialog_id, uint64 generation, Promise &&promise); void on_group_call_left(InputGroupCallId input_group_call_id, int32 audio_source, bool need_rejoin); @@ -211,12 +212,12 @@ class GroupCallManager : public Actor { void on_participant_speaking_in_group_call(InputGroupCallId input_group_call_id, const GroupCallParticipant &participant); - void remove_recent_group_call_speaker(InputGroupCallId input_group_call_id, UserId user_id); + void remove_recent_group_call_speaker(InputGroupCallId input_group_call_id, DialogId dialog_id); void on_group_call_recent_speakers_updated(const GroupCall *group_call, GroupCallRecentSpeakers *recent_speakers); - UserId set_group_call_participant_is_speaking_by_source(InputGroupCallId input_group_call_id, int32 audio_source, - bool is_speaking, int32 date); + DialogId set_group_call_participant_is_speaking_by_source(InputGroupCallId input_group_call_id, int32 audio_source, + bool is_speaking, int32 date); static Result> get_group_call_join_response_object( string json_response); diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index 068d3c9c7..ed94dca9b 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -6,7 +6,7 @@ // #include "td/telegram/GroupCallParticipant.h" -#include "td/telegram/ContactsManager.h" +#include "td/telegram/MessagesManager.h" #include "td/telegram/Td.h" #include "td/utils/logging.h" @@ -15,11 +15,7 @@ namespace td { GroupCallParticipant::GroupCallParticipant(const tl_object_ptr &participant) { CHECK(participant != nullptr); - DialogId dialog_id(participant->peer_); - if (dialog_id.get_type() != DialogType::User) { - return; - } - user_id = dialog_id.get_user_id(); + dialog_id = DialogId(participant->peer_); audio_source = participant->source_; server_is_muted_by_themselves = participant->can_self_unmute_; server_is_muted_by_admin = participant->muted_ && !participant->can_self_unmute_; @@ -217,14 +213,14 @@ td_api::object_ptr GroupCallParticipant::get_group } return td_api::make_object( - td->contacts_manager_->get_user_id_object(user_id, "get_group_call_participant_object"), audio_source, - is_speaking, can_be_muted_for_all_users, can_be_unmuted_for_all_users, can_be_muted_only_for_self, + td->messages_manager_->get_message_sender_object(dialog_id), audio_source, is_speaking, + can_be_muted_for_all_users, can_be_unmuted_for_all_users, can_be_muted_only_for_self, can_be_unmuted_only_for_self, get_is_muted_for_all_users(), get_is_muted_locally(), get_is_muted_by_themselves(), get_volume_level(), order); } bool operator==(const GroupCallParticipant &lhs, const GroupCallParticipant &rhs) { - return lhs.user_id == rhs.user_id && lhs.audio_source == rhs.audio_source && + return lhs.dialog_id == rhs.dialog_id && lhs.audio_source == rhs.audio_source && lhs.can_be_muted_for_all_users == rhs.can_be_muted_for_all_users && lhs.can_be_unmuted_for_all_users == rhs.can_be_unmuted_for_all_users && lhs.can_be_muted_only_for_self == rhs.can_be_muted_only_for_self && @@ -240,7 +236,7 @@ bool operator!=(const GroupCallParticipant &lhs, const GroupCallParticipant &rhs } StringBuilder &operator<<(StringBuilder &string_builder, const GroupCallParticipant &group_call_participant) { - return string_builder << '[' << group_call_participant.user_id << " with source " + return string_builder << '[' << group_call_participant.dialog_id << " with source " << group_call_participant.audio_source << " and order " << group_call_participant.order << ']'; } diff --git a/td/telegram/GroupCallParticipant.h b/td/telegram/GroupCallParticipant.h index 9395b118a..70af94f7c 100644 --- a/td/telegram/GroupCallParticipant.h +++ b/td/telegram/GroupCallParticipant.h @@ -6,9 +6,9 @@ // #pragma once +#include "td/telegram/DialogId.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" -#include "td/telegram/UserId.h" #include "td/utils/common.h" #include "td/utils/StringBuilder.h" @@ -18,7 +18,7 @@ namespace td { class Td; struct GroupCallParticipant { - UserId user_id; + DialogId dialog_id; int32 audio_source = 0; int32 joined_date = 0; int32 active_date = 0; @@ -70,7 +70,7 @@ struct GroupCallParticipant { } bool is_valid() const { - return user_id.is_valid(); + return dialog_id.is_valid(); } bool get_is_muted_by_themselves() const; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index e8a51dc5e..c15cc2f87 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -7221,7 +7221,7 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th const Dialog *d = get_dialog_force(dialog_id); if (d != nullptr && d->active_group_call_id.is_valid()) { auto group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, dialog_id); - td_->group_call_manager_->on_user_speaking_in_group_call(group_call_id, user_id, date); + td_->group_call_manager_->on_user_speaking_in_group_call(group_call_id, DialogId(user_id), date); } return; } @@ -31474,7 +31474,7 @@ tl_object_ptr MessagesManager::get_chat_event_action_ob return nullptr; } return make_tl_object( - td_->contacts_manager_->get_user_id_object(participant.user_id, "LogEventActionParticipantMute"), true); + get_message_sender_object(participant.dialog_id), true); } case telegram_api::channelAdminLogEventActionParticipantUnmute::ID: { auto action = move_tl_object_as(action_ptr); @@ -31483,7 +31483,7 @@ tl_object_ptr MessagesManager::get_chat_event_action_ob return nullptr; } return make_tl_object( - td_->contacts_manager_->get_user_id_object(participant.user_id, "LogEventActionParticipantUnmute"), false); + get_message_sender_object(participant.dialog_id), false); } case telegram_api::channelAdminLogEventActionParticipantVolume::ID: { auto action = move_tl_object_as(action_ptr); @@ -31492,8 +31492,7 @@ tl_object_ptr MessagesManager::get_chat_event_action_ob return nullptr; } return make_tl_object( - td_->contacts_manager_->get_user_id_object(participant.user_id, "LogEventActionParticipantVolume"), - participant.volume_level); + get_message_sender_object(participant.dialog_id), participant.volume_level); } case telegram_api::channelAdminLogEventActionToggleGroupCallSetting::ID: { auto action = move_tl_object_as(action_ptr); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 7d7a6ad65..c809d4102 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -499,6 +499,9 @@ class MessagesManager : public Actor { bool have_dialog(DialogId dialog_id) const; bool have_dialog_force(DialogId dialog_id); + bool have_dialog_info(DialogId dialog_id) const; + bool have_dialog_info_force(DialogId dialog_id) const; + bool load_dialog(DialogId dialog_id, int left_tries, Promise &&promise); void load_dialogs(vector dialog_ids, Promise &&promise); @@ -2411,9 +2414,6 @@ class MessagesManager : public Actor { td_api::object_ptr get_chat_object(const Dialog *d) const; - bool have_dialog_info(DialogId dialog_id) const; - bool have_dialog_info_force(DialogId dialog_id) const; - Dialog *get_dialog(DialogId dialog_id); const Dialog *get_dialog(DialogId dialog_id) const; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 7545cf83b..559f1fba7 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6026,14 +6026,15 @@ void Td::on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted & CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); group_call_manager_->toggle_group_call_participant_is_muted( - GroupCallId(request.group_call_id_), UserId(request.user_id_), request.is_muted_, std::move(promise)); + GroupCallId(request.group_call_id_), DialogId(UserId(request.user_id_)), request.is_muted_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::setGroupCallParticipantVolumeLevel &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->set_group_call_participant_volume_level( - GroupCallId(request.group_call_id_), UserId(request.user_id_), request.volume_level_, std::move(promise)); + group_call_manager_->set_group_call_participant_volume_level(GroupCallId(request.group_call_id_), + DialogId(UserId(request.user_id_)), + request.volume_level_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::loadGroupCallParticipants &request) { From 3d08e0e18f14b46c909262935123f0df2b11e022 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 5 Mar 2021 15:27:52 +0300 Subject: [PATCH 009/281] Add groupCallParticipant.bio. --- td/generate/scheme/td_api.tl | 3 ++- td/telegram/GroupCallParticipant.cpp | 5 +++-- td/telegram/GroupCallParticipant.h | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index e815f1b09..05076097b 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2137,6 +2137,7 @@ groupCallJoinResponse payload:groupCallPayload candidates:vector &participant) { CHECK(participant != nullptr); dialog_id = DialogId(participant->peer_); + about = std::move(participant->about_); audio_source = participant->source_; server_is_muted_by_themselves = participant->can_self_unmute_; server_is_muted_by_admin = participant->muted_ && !participant->can_self_unmute_; @@ -213,14 +214,14 @@ td_api::object_ptr GroupCallParticipant::get_group } return td_api::make_object( - td->messages_manager_->get_message_sender_object(dialog_id), audio_source, is_speaking, + td->messages_manager_->get_message_sender_object(dialog_id), audio_source, about, is_speaking, can_be_muted_for_all_users, can_be_unmuted_for_all_users, can_be_muted_only_for_self, can_be_unmuted_only_for_self, get_is_muted_for_all_users(), get_is_muted_locally(), get_is_muted_by_themselves(), get_volume_level(), order); } bool operator==(const GroupCallParticipant &lhs, const GroupCallParticipant &rhs) { - return lhs.dialog_id == rhs.dialog_id && lhs.audio_source == rhs.audio_source && + return lhs.dialog_id == rhs.dialog_id && lhs.audio_source == rhs.audio_source && lhs.about == rhs.about && lhs.can_be_muted_for_all_users == rhs.can_be_muted_for_all_users && lhs.can_be_unmuted_for_all_users == rhs.can_be_unmuted_for_all_users && lhs.can_be_muted_only_for_self == rhs.can_be_muted_only_for_self && diff --git a/td/telegram/GroupCallParticipant.h b/td/telegram/GroupCallParticipant.h index 70af94f7c..4dcc498a5 100644 --- a/td/telegram/GroupCallParticipant.h +++ b/td/telegram/GroupCallParticipant.h @@ -19,6 +19,7 @@ class Td; struct GroupCallParticipant { DialogId dialog_id; + string about; int32 audio_source = 0; int32 joined_date = 0; int32 active_date = 0; From 3bac31cc16fca0f286ccffec782161a7b3ddafb0 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 5 Mar 2021 16:03:49 +0300 Subject: [PATCH 010/281] Allow to edit chat group call participants. --- td/generate/scheme/td_api.tl | 8 ++++---- td/telegram/GroupCallManager.cpp | 26 ++++++++++++++++++++++++++ td/telegram/GroupCallManager.h | 2 ++ td/telegram/Td.cpp | 9 +++++---- td/telegram/cli.cpp | 16 ++++++++-------- 5 files changed, 45 insertions(+), 16 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 05076097b..22084f42d 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4571,12 +4571,12 @@ inviteGroupCallParticipants group_call_id:int32 user_ids:vector = Ok; setGroupCallParticipantIsSpeaking group_call_id:int32 source:int32 is_speaking:Bool = Ok; //@description Toggles whether a group call participant is muted, unmuted, or allowed to unmute themself -//@group_call_id Group call identifier @user_id User identifier @is_muted Pass true if the user must be muted and false otherwise -toggleGroupCallParticipantIsMuted group_call_id:int32 user_id:int32 is_muted:Bool = Ok; +//@group_call_id Group call identifier @participant Participant identifier @is_muted Pass true if the user must be muted and false otherwise +toggleGroupCallParticipantIsMuted group_call_id:int32 participant:MessageSender is_muted:Bool = Ok; //@description Changes a group call participant's volume level. If the current user can manage the group call, then the participant's volume level will be changed for all users with default volume level -//@group_call_id Group call identifier @user_id User identifier @volume_level New participant's volume level; 1-20000 in hundreds of percents -setGroupCallParticipantVolumeLevel group_call_id:int32 user_id:int32 volume_level:int32 = Ok; +//@group_call_id Group call identifier @participant Participant identifier @volume_level New participant's volume level; 1-20000 in hundreds of percents +setGroupCallParticipantVolumeLevel group_call_id:int32 participant:MessageSender volume_level:int32 = Ok; //@description Loads more group call participants. The loaded participants will be received through updates. Use the field groupCall.loaded_all_participants to check whether all participants has already been loaded //@group_call_id Group call identifier. The group call must be previously received through getGroupCall and must be joined or being joined diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index d1acbdb4f..b8f8a01da 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -640,6 +640,32 @@ void GroupCallManager::on_sync_participants_timeout(GroupCallId group_call_id) { sync_group_call_participants(input_group_call_id); } +DialogId GroupCallManager::get_group_call_participant_id( + const td_api::object_ptr &message_sender) { + if (message_sender == nullptr) { + return DialogId(); + } + switch (message_sender->get_id()) { + case td_api::messageSenderUser::ID: { + UserId user_id(static_cast(message_sender.get())->user_id_); + if (td_->contacts_manager_->have_user_force(user_id)) { + return DialogId(user_id); + } + break; + } + case td_api::messageSenderChat::ID: { + DialogId dialog_id(static_cast(message_sender.get())->chat_id_); + if (td_->messages_manager_->have_dialog_force(dialog_id)) { + return dialog_id; + } + break; + } + default: + UNREACHABLE(); + } + return DialogId(); +} + GroupCallId GroupCallManager::get_group_call_id(InputGroupCallId input_group_call_id, DialogId dialog_id) { if (td_->auth_manager_->is_bot() || !input_group_call_id.is_valid()) { return GroupCallId(); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 661fb7327..07011d559 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -37,6 +37,8 @@ class GroupCallManager : public Actor { GroupCallManager &operator=(GroupCallManager &&) = delete; ~GroupCallManager() override; + DialogId get_group_call_participant_id(const td_api::object_ptr &message_sender); + GroupCallId get_group_call_id(InputGroupCallId input_group_call_id, DialogId dialog_id); void create_voice_chat(DialogId dialog_id, Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 559f1fba7..8ddbe7172 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6026,15 +6026,16 @@ void Td::on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted & CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); group_call_manager_->toggle_group_call_participant_is_muted( - GroupCallId(request.group_call_id_), DialogId(UserId(request.user_id_)), request.is_muted_, std::move(promise)); + GroupCallId(request.group_call_id_), group_call_manager_->get_group_call_participant_id(request.participant_), + request.is_muted_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::setGroupCallParticipantVolumeLevel &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->set_group_call_participant_volume_level(GroupCallId(request.group_call_id_), - DialogId(UserId(request.user_id_)), - request.volume_level_, std::move(promise)); + group_call_manager_->set_group_call_participant_volume_level( + GroupCallId(request.group_call_id_), group_call_manager_->get_group_call_participant_id(request.participant_), + request.volume_level_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::loadGroupCallParticipants &request) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 9bf52e084..50c3b629a 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2702,18 +2702,18 @@ class CliClient final : public Actor { as_user_ids(user_ids))); } else if (op == "tgcpim") { string group_call_id; - string user_id; + string participant_id; bool is_muted; - get_args(args, group_call_id, user_id, is_muted); - send_request(td_api::make_object(as_group_call_id(group_call_id), - as_user_id(user_id), is_muted)); + get_args(args, group_call_id, participant_id, is_muted); + send_request(td_api::make_object( + as_group_call_id(group_call_id), as_message_sender(participant_id), is_muted)); } else if (op == "sgcpvl") { string group_call_id; - string user_id; + string participant_id; int32 volume_level; - get_args(args, group_call_id, user_id, volume_level); - send_request(td_api::make_object(as_group_call_id(group_call_id), - as_user_id(user_id), volume_level)); + get_args(args, group_call_id, participant_id, volume_level); + send_request(td_api::make_object( + as_group_call_id(group_call_id), as_message_sender(participant_id), volume_level)); } else if (op == "lgcp") { string group_call_id; string limit; From 5e5aa950606c7b0a8b28d995699ce4a92768c0b2 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 5 Mar 2021 16:44:43 +0300 Subject: [PATCH 011/281] Add groupCallParticipant.is_hand_raised. --- td/generate/scheme/td_api.tl | 3 ++- td/telegram/GroupCallParticipant.cpp | 16 ++++++++++++++-- td/telegram/GroupCallParticipant.h | 7 +++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 22084f42d..cab850466 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2139,6 +2139,7 @@ groupCallJoinResponse payload:groupCallPayload candidates:vectorflags_ & telegram_api::groupCallParticipant::RAISE_HAND_RATING_MASK) != 0) { + raise_hand_rating = participant->raise_hand_rating_; + } } is_just_joined = participant->just_joined_; is_min = participant->min_; @@ -69,6 +72,10 @@ int32 GroupCallParticipant::get_volume_level() const { return pending_volume_level != 0 ? pending_volume_level : volume_level; } +bool GroupCallParticipant::get_is_hand_raised() const { + return have_pending_is_hand_raised ? pending_is_hand_raised : raise_hand_rating != 0; +} + void GroupCallParticipant::update_from(const GroupCallParticipant &old_participant) { CHECK(!old_participant.is_min); if (joined_date < old_participant.joined_date) { @@ -102,6 +109,10 @@ void GroupCallParticipant::update_from(const GroupCallParticipant &old_participa pending_is_muted_by_admin = old_participant.pending_is_muted_by_admin; pending_is_muted_locally = old_participant.pending_is_muted_locally; pending_is_muted_generation = old_participant.pending_is_muted_generation; + + have_pending_is_hand_raised = old_participant.have_pending_is_hand_raised; + pending_is_hand_raised = old_participant.pending_is_hand_raised; + pending_is_hand_raised_generation = old_participant.pending_is_hand_raised_generation; } bool GroupCallParticipant::update_can_be_muted(bool can_manage, bool is_admin) { @@ -215,20 +226,21 @@ td_api::object_ptr GroupCallParticipant::get_group return td_api::make_object( td->messages_manager_->get_message_sender_object(dialog_id), audio_source, about, is_speaking, - can_be_muted_for_all_users, can_be_unmuted_for_all_users, can_be_muted_only_for_self, + get_is_hand_raised(), can_be_muted_for_all_users, can_be_unmuted_for_all_users, can_be_muted_only_for_self, can_be_unmuted_only_for_self, get_is_muted_for_all_users(), get_is_muted_locally(), get_is_muted_by_themselves(), get_volume_level(), order); } bool operator==(const GroupCallParticipant &lhs, const GroupCallParticipant &rhs) { return lhs.dialog_id == rhs.dialog_id && lhs.audio_source == rhs.audio_source && lhs.about == rhs.about && + lhs.is_speaking == rhs.is_speaking && lhs.get_is_hand_raised() == rhs.get_is_hand_raised() && lhs.can_be_muted_for_all_users == rhs.can_be_muted_for_all_users && lhs.can_be_unmuted_for_all_users == rhs.can_be_unmuted_for_all_users && lhs.can_be_muted_only_for_self == rhs.can_be_muted_only_for_self && lhs.can_be_unmuted_only_for_self == rhs.can_be_unmuted_only_for_self && lhs.get_is_muted_for_all_users() == rhs.get_is_muted_for_all_users() && lhs.get_is_muted_locally() == rhs.get_is_muted_locally() && - lhs.get_is_muted_by_themselves() == rhs.get_is_muted_by_themselves() && lhs.is_speaking == rhs.is_speaking && + lhs.get_is_muted_by_themselves() == rhs.get_is_muted_by_themselves() && lhs.get_volume_level() == rhs.get_volume_level() && lhs.order == rhs.order; } diff --git a/td/telegram/GroupCallParticipant.h b/td/telegram/GroupCallParticipant.h index 4dcc498a5..36fcd89ee 100644 --- a/td/telegram/GroupCallParticipant.h +++ b/td/telegram/GroupCallParticipant.h @@ -24,6 +24,7 @@ struct GroupCallParticipant { int32 joined_date = 0; int32 active_date = 0; int32 volume_level = 10000; + int64 raise_hand_rating = 0; bool is_volume_level_local = false; bool server_is_muted_by_themselves = false; bool server_is_muted_by_admin = false; @@ -51,6 +52,10 @@ struct GroupCallParticipant { bool pending_is_muted_locally = false; uint64 pending_is_muted_generation = 0; + bool have_pending_is_hand_raised = false; + bool pending_is_hand_raised = false; + uint64 pending_is_hand_raised_generation = 0; + static constexpr int32 MIN_VOLUME_LEVEL = 1; static constexpr int32 MAX_VOLUME_LEVEL = 20000; @@ -84,6 +89,8 @@ struct GroupCallParticipant { int32 get_volume_level() const; + bool get_is_hand_raised() const; + td_api::object_ptr get_group_call_participant_object(Td *td) const; }; From 8ede5f736fdf93030d0e65efd802ce0aa4de0710 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 5 Mar 2021 18:49:02 +0300 Subject: [PATCH 012/281] Support speaking typings by chats. --- td/telegram/MessagesManager.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index c15cc2f87..b58fb794f 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -7203,15 +7203,10 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th return; } if (top_thread_message_id != MessageId() && !top_thread_message_id.is_valid()) { - LOG(ERROR) << "Ignore typing in the message thread of " << top_thread_message_id; + LOG(ERROR) << "Ignore " << action << " in the message thread of " << top_thread_message_id; return; } - if (typing_dialog_id.get_type() != DialogType::User) { - return; - } - auto user_id = typing_dialog_id.get_user_id(); - auto dialog_type = dialog_id.get_type(); if (action == DialogAction::get_speaking_action()) { if ((dialog_type != DialogType::Chat && dialog_type != DialogType::Channel) || top_thread_message_id.is_valid()) { @@ -7221,10 +7216,17 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th const Dialog *d = get_dialog_force(dialog_id); if (d != nullptr && d->active_group_call_id.is_valid()) { auto group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, dialog_id); - td_->group_call_manager_->on_user_speaking_in_group_call(group_call_id, DialogId(user_id), date); + td_->group_call_manager_->on_user_speaking_in_group_call(group_call_id, dialog_id, date); } return; } + + if (typing_dialog_id.get_type() != DialogType::User) { + LOG(ERROR) << "Ignore " << action << " of " << typing_dialog_id << " in " << dialog_id; + return; + } + auto user_id = typing_dialog_id.get_user_id(); + { auto message_import_progress = action.get_importing_messages_action_progress(); if (message_import_progress >= 0) { @@ -7234,11 +7236,11 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th } if (!td_->contacts_manager_->have_min_user(user_id)) { - LOG(DEBUG) << "Ignore typing of unknown " << user_id; + LOG(DEBUG) << "Ignore " << action << " of unknown " << user_id; return; } if (!have_dialog(dialog_id)) { - LOG(DEBUG) << "Ignore typing in unknown " << dialog_id; + LOG(DEBUG) << "Ignore " << action << " in unknown " << dialog_id; return; } From 16ab28f2307f2ee93d5ba16c80f6234cb08e0252 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 5 Mar 2021 20:06:37 +0300 Subject: [PATCH 013/281] Allow to send speaking actions in read-only chats. --- td/telegram/MessagesManager.cpp | 35 ++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index b58fb794f..522ab3349 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -3825,9 +3825,9 @@ class SetTypingQuery : public Td::ResultHandler { explicit SetTypingQuery(Promise &&promise) : promise_(std::move(promise)) { } - NetQueryRef send(DialogId dialog_id, MessageId message_id, tl_object_ptr &&action) { + NetQueryRef send(DialogId dialog_id, tl_object_ptr &&input_peer, MessageId message_id, + tl_object_ptr &&action) { dialog_id_ = dialog_id; - auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Write); CHECK(input_peer != nullptr); int32 flags = 0; @@ -30388,16 +30388,26 @@ void MessagesManager::send_dialog_action(DialogId dialog_id, MessageId top_threa return promise.set_error(Status::Error(5, "Invalid message thread specified")); } - auto can_send_status = can_send_message(dialog_id); - if (can_send_status.is_error()) { - if (td_->auth_manager_->is_bot()) { - return promise.set_error(can_send_status.move_as_error()); + tl_object_ptr input_peer; + if (action == DialogAction::get_speaking_action()) { + input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + if (input_peer == nullptr) { + return promise.set_error(Status::Error(400, "Have no access to the chat")); + } + } else { + auto can_send_status = can_send_message(dialog_id); + if (can_send_status.is_error()) { + if (td_->auth_manager_->is_bot()) { + return promise.set_error(can_send_status.move_as_error()); + } + return promise.set_value(Unit()); } - return promise.set_value(Unit()); - } - if (is_dialog_action_unneeded(dialog_id)) { - return promise.set_value(Unit()); + if (is_dialog_action_unneeded(dialog_id)) { + return promise.set_value(Unit()); + } + + input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write); } if (dialog_id.get_type() == DialogType::SecretChat) { @@ -30412,8 +30422,9 @@ void MessagesManager::send_dialog_action(DialogId dialog_id, MessageId top_threa LOG(INFO) << "Cancel previous send chat action query"; cancel_query(query_ref); } - query_ref = td_->create_handler(std::move(promise)) - ->send(dialog_id, top_thread_message_id, action.get_input_send_message_action()); + query_ref = + td_->create_handler(std::move(promise)) + ->send(dialog_id, std::move(input_peer), top_thread_message_id, action.get_input_send_message_action()); } void MessagesManager::on_send_dialog_action_timeout(DialogId dialog_id) { From 7a19e5dbe589b7cbc5d0aa74b5266d6c4fa89dc5 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 6 Mar 2021 02:26:13 +0300 Subject: [PATCH 014/281] Support voice chat creation in channels. --- td/generate/scheme/td_api.tl | 4 ++-- td/telegram/ContactsManager.cpp | 4 ---- td/telegram/GroupCallManager.cpp | 12 ------------ 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index cab850466..4147284e4 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -464,7 +464,7 @@ chatMemberStatusCreator custom_title:string is_anonymous:Bool is_member:Bool = C //@can_restrict_members True, if the administrator can restrict, ban, or unban chat members //@can_pin_messages True, if the administrator can pin messages; applicable to basic groups and supergroups only //@can_promote_members True, if the administrator can add new administrators with a subset of their own privileges or demote administrators that were directly or indirectly promoted by them -//@can_manage_voice_chats True, if the administrator can manage voice chats; applicable to basic groups and supergroups only +//@can_manage_voice_chats True, if the administrator can manage voice chats //@is_anonymous True, if the administrator isn't shown in the chat member list and sends messages anonymously; applicable to supergroups only chatMemberStatusAdministrator custom_title:string can_be_edited:Bool can_manage_chat:Bool can_change_info:Bool can_post_messages:Bool can_edit_messages:Bool can_delete_messages:Bool can_invite_users:Bool can_restrict_members:Bool can_pin_messages:Bool can_promote_members:Bool can_manage_voice_chats:Bool is_anonymous:Bool = ChatMemberStatus; @@ -4547,7 +4547,7 @@ sendCallRating call_id:int32 rating:int32 comment:string problems:vector &&c InputGroupCallId input_group_call_id; if (channel->call_ != nullptr) { input_group_call_id = InputGroupCallId(channel->call_); - if (input_group_call_id.is_valid() && !c->is_megagroup) { - LOG(ERROR) << "Receive " << input_group_call_id << " in " << channel_id; - input_group_call_id = InputGroupCallId(); - } } td_->messages_manager_->on_update_dialog_group_call_id(DialogId(channel_id), input_group_call_id); } diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index b8f8a01da..fec63f9fe 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -736,18 +736,6 @@ Status GroupCallManager::can_manage_group_calls(DialogId dialog_id) const { } case DialogType::Channel: { auto channel_id = dialog_id.get_channel_id(); - switch (td_->contacts_manager_->get_channel_type(channel_id)) { - case ChannelType::Unknown: - return Status::Error(400, "Chat info not found"); - case ChannelType::Megagroup: - // OK - break; - case ChannelType::Broadcast: - return Status::Error(400, "Chat is not a group"); - default: - UNREACHABLE(); - break; - } if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_manage_calls()) { return Status::Error(400, "Not enough rights in the chat"); } From c611553ecedf487e27c5ff823ad945845e5756c3 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 6 Mar 2021 23:21:22 +0300 Subject: [PATCH 015/281] Allow to join group call as a chat. --- td/generate/scheme/td_api.tl | 4 ++-- td/telegram/GroupCallManager.cpp | 38 ++++++++++++++++++++++++++------ td/telegram/GroupCallManager.h | 4 ++-- td/telegram/Td.cpp | 5 +++-- td/telegram/cli.cpp | 7 ++++-- 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 4147284e4..de02d6d8a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4553,8 +4553,8 @@ createVoiceChat chat_id:int53 = GroupCallId; //@description Returns information about a group call @group_call_id Group call identifier getGroupCall group_call_id:int32 = GroupCall; -//@description Joins a group call @group_call_id Group call identifier @payload Group join payload, received from tgcalls. Use null to cancel previous joinGroupCall request @source Caller synchronization source identifier; received from tgcalls @is_muted True, if the user's microphone is muted -joinGroupCall group_call_id:int32 payload:groupCallPayload source:int32 is_muted:Bool = GroupCallJoinResponse; +//@description Joins a group call @group_call_id Group call identifier @as_chat_id If not 0, identifier of the chat, which will be used to join the call @payload Group join payload, received from tgcalls. Use null to cancel previous joinGroupCall request @source Caller synchronization source identifier; received from tgcalls @is_muted True, if the user's microphone is muted +joinGroupCall group_call_id:int32 as_chat_id:int53 payload:groupCallPayload source:int32 is_muted:Bool = GroupCallJoinResponse; //@description Sets group call title. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title New group call title; 1-128 characters setGroupCallTitle group_call_id:int32 title:string = Ok; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index fec63f9fe..1ebbd9e99 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -184,18 +184,25 @@ class GetGroupCallParticipantsQuery : public Td::ResultHandler { class JoinGroupCallQuery : public Td::ResultHandler { Promise promise_; InputGroupCallId input_group_call_id_; + DialogId as_dialog_id_; uint64 generation_ = 0; public: explicit JoinGroupCallQuery(Promise &&promise) : promise_(std::move(promise)) { } - NetQueryRef send(InputGroupCallId input_group_call_id, const string &payload, bool is_muted, uint64 generation) { + NetQueryRef send(InputGroupCallId input_group_call_id, DialogId as_dialog_id, const string &payload, bool is_muted, + uint64 generation) { input_group_call_id_ = input_group_call_id; + as_dialog_id_ = as_dialog_id; generation_ = generation; - auto join_as_input_peer = - td->messages_manager_->get_input_peer(DialogId(td->contacts_manager_->get_my_id()), AccessRights::Read); + tl_object_ptr join_as_input_peer; + if (as_dialog_id.is_valid()) { + join_as_input_peer = td->messages_manager_->get_input_peer(as_dialog_id, AccessRights::Read); + } else { + join_as_input_peer = make_tl_object(); + } CHECK(join_as_input_peer != nullptr); int32 flags = 0; @@ -1526,7 +1533,7 @@ int32 GroupCallManager::cancel_join_group_call_request(InputGroupCallId input_gr return audio_source; } -void GroupCallManager::join_group_call(GroupCallId group_call_id, +void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, td_api::object_ptr &&payload, int32 audio_source, bool is_muted, Promise> &&promise) { @@ -1546,6 +1553,15 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, cancel_join_group_call_request(input_group_call_id); + if (as_dialog_id != DialogId()) { + if (!td_->messages_manager_->have_dialog_force(as_dialog_id)) { + return promise.set_error(Status::Error(400, "Chat not found")); + } + if (!td_->messages_manager_->have_input_peer(as_dialog_id, AccessRights::Read)) { + return promise.set_error(Status::Error(400, "Can't access the chat")); + } + } + if (audio_source == 0) { return promise.set_error(Status::Error(400, "Audio source must be non-zero")); } @@ -1606,12 +1622,20 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, result.move_as_error()); }); request->query_ref = td_->create_handler(std::move(query_promise)) - ->send(input_group_call_id, json_payload, is_muted, generation); + ->send(input_group_call_id, as_dialog_id, json_payload, is_muted, generation); - if (group_call->is_inited && td_->contacts_manager_->have_user_force(td_->contacts_manager_->get_my_id())) { + if (group_call->is_inited) { GroupCallParticipant group_call_participant; group_call_participant.is_self = true; - group_call_participant.dialog_id = DialogId(td_->contacts_manager_->get_my_id()); + if (as_dialog_id.is_valid()) { + // dialog already exists + group_call_participant.dialog_id = as_dialog_id; + } else { + // create dialog with self + DialogId my_dialog_id(td_->contacts_manager_->get_my_id()); + td_->messages_manager_->force_create_dialog(my_dialog_id, "join_group_call"); + group_call_participant.dialog_id = my_dialog_id; + } group_call_participant.audio_source = audio_source; group_call_participant.joined_date = G()->unix_time(); // if can_self_unmute has never been inited from self-participant, diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 07011d559..7ef87bbf2 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -50,8 +50,8 @@ class GroupCallManager : public Actor { void reload_group_call(InputGroupCallId input_group_call_id, Promise> &&promise); - void join_group_call(GroupCallId group_call_id, td_api::object_ptr &&payload, - int32 audio_source, bool is_muted, + void join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, + td_api::object_ptr &&payload, int32 audio_source, bool is_muted, Promise> &&promise); void set_group_call_title(GroupCallId group_call_id, string title, Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 8ddbe7172..ce4f0bcb3 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5985,8 +5985,9 @@ void Td::on_request(uint64 id, const td_api::getGroupCall &request) { void Td::on_request(uint64 id, td_api::joinGroupCall &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - group_call_manager_->join_group_call(GroupCallId(request.group_call_id_), std::move(request.payload_), - request.source_, request.is_muted_, std::move(promise)); + group_call_manager_->join_group_call(GroupCallId(request.group_call_id_), DialogId(request.as_chat_id_), + std::move(request.payload_), request.source_, request.is_muted_, + std::move(promise)); } void Td::on_request(uint64 id, td_api::setGroupCallTitle &request) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 50c3b629a..3378316ba 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2670,15 +2670,18 @@ class CliClient final : public Actor { } else if (op == "ggc") { send_request(td_api::make_object(as_group_call_id(args))); } else if (op == "jgc") { + string group_call_id; + string chat_id; + get_args(args, group_call_id, chat_id); vector> fingerprints; fingerprints.push_back(td_api::make_object("hash", "setup", "fingerprint")); fingerprints.push_back(td_api::make_object("h2", "s2", "fingerprint2")); send_request(td_api::make_object( - as_group_call_id(args), + as_group_call_id(group_call_id), as_chat_id(chat_id), td_api::make_object("ufrag", "pwd", std::move(fingerprints)), group_call_source_, true)); } else if (op == "jgcc") { - send_request(td_api::make_object(as_group_call_id(args), nullptr, 0, true)); + send_request(td_api::make_object(as_group_call_id(args), 0, nullptr, 0, true)); } else if (op == "sgct") { string chat_id; string title; From 0615d1f61dda230c725c7e1d51c2c448637100d9 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 7 Mar 2021 01:06:51 +0300 Subject: [PATCH 016/281] Prevent voice chat data updating during join. --- td/telegram/GroupCallManager.cpp | 28 ++++++++++++++++------------ td/telegram/GroupCallManager.h | 4 +++- td/telegram/MessagesManager.cpp | 13 ++++++------- td/telegram/MessagesManager.h | 2 +- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 1ebbd9e99..643c67703 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -551,7 +551,7 @@ void GroupCallManager::on_check_group_call_is_joined_timeout(GroupCallId group_c auto *group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); auto audio_source = group_call->audio_source; - if (!group_call->is_joined || pending_join_requests_.count(input_group_call_id) != 0 || + if (!group_call->is_joined || is_group_call_being_joined(input_group_call_id) || check_group_call_is_joined_timeout_.has_timeout(group_call_id.get()) || audio_source == 0) { return; } @@ -673,6 +673,10 @@ DialogId GroupCallManager::get_group_call_participant_id( return DialogId(); } +bool GroupCallManager::is_group_call_being_joined(InputGroupCallId input_group_call_id) const { + return pending_join_requests_.count(input_group_call_id) != 0; +} + GroupCallId GroupCallManager::get_group_call_id(InputGroupCallId input_group_call_id, DialogId dialog_id) { if (td_->auth_manager_->is_bot() || !input_group_call_id.is_valid()) { return GroupCallId(); @@ -913,7 +917,7 @@ void GroupCallManager::finish_check_group_call_is_joined(InputGroupCallId input_ auto *group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); CHECK(audio_source != 0); - if (!group_call->is_joined || pending_join_requests_.count(input_group_call_id) != 0 || + if (!group_call->is_joined || is_group_call_being_joined(input_group_call_id) || check_group_call_is_joined_timeout_.has_timeout(group_call->group_call_id.get()) || group_call->audio_source != audio_source) { return; @@ -943,7 +947,7 @@ bool GroupCallManager::need_group_call_participants(InputGroupCallId input_group if (group_call == nullptr || !group_call->is_inited || !group_call->is_active) { return false; } - if (group_call->is_joined || group_call->need_rejoin || pending_join_requests_.count(input_group_call_id) != 0) { + if (group_call->is_joined || group_call->need_rejoin || is_group_call_being_joined(input_group_call_id)) { return true; } return false; @@ -1650,7 +1654,7 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di CHECK(diff == 1); group_call->participant_count++; need_update = true; - update_group_call_dialog(group_call, "join_group_call"); + update_group_call_dialog(group_call, "join_group_call", true); } } @@ -1847,8 +1851,8 @@ void GroupCallManager::process_group_call_after_join_requests(InputGroupCallId i if (group_call == nullptr || !group_call->is_inited) { return; } - if (pending_join_requests_.count(input_group_call_id) != 0 || group_call->need_rejoin) { - LOG(ERROR) << "Failed to process after-join requests: " << pending_join_requests_.count(input_group_call_id) << " " + if (is_group_call_being_joined(input_group_call_id) || group_call->need_rejoin) { + LOG(ERROR) << "Failed to process after-join requests: " << is_group_call_being_joined(input_group_call_id) << " " << group_call->need_rejoin; return; } @@ -2039,7 +2043,7 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ return promise.set_value(Unit()); } if (!group_call->is_joined) { - if (pending_join_requests_.count(input_group_call_id) || group_call->need_rejoin) { + if (is_group_call_being_joined(input_group_call_id) || group_call->need_rejoin) { group_call->after_join.push_back( PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, audio_source, is_speaking, promise = std::move(promise), date](Result &&result) mutable { @@ -2121,7 +2125,7 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ return promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); } if (!group_call->is_joined) { - if (pending_join_requests_.count(input_group_call_id) || group_call->need_rejoin) { + if (is_group_call_being_joined(input_group_call_id) || group_call->need_rejoin) { group_call->after_join.push_back( PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, dialog_id, is_muted, promise = std::move(promise)](Result &&result) mutable { @@ -2216,7 +2220,7 @@ void GroupCallManager::set_group_call_participant_volume_level(GroupCallId group return promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); } if (!group_call->is_joined) { - if (pending_join_requests_.count(input_group_call_id) || group_call->need_rejoin) { + if (is_group_call_being_joined(input_group_call_id) || group_call->need_rejoin) { group_call->after_join.push_back( PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, dialog_id, volume_level, promise = std::move(promise)](Result &&result) mutable { @@ -2575,13 +2579,13 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptris_active && group_call_recent_speakers_.erase(group_call->group_call_id) != 0) { need_update = true; } if (!join_params.empty()) { need_update |= on_join_group_call_response(input_group_call_id, std::move(join_params)); } + update_group_call_dialog(group_call, "update_group_call"); // must be after join response is processed if (need_update) { send_update_group_call(group_call, "update_group_call"); } @@ -2772,13 +2776,13 @@ DialogId GroupCallManager::set_group_call_participant_is_speaking_by_source(Inpu return DialogId(); } -void GroupCallManager::update_group_call_dialog(const GroupCall *group_call, const char *source) { +void GroupCallManager::update_group_call_dialog(const GroupCall *group_call, const char *source, bool force) { if (!group_call->dialog_id.is_valid()) { return; } td_->messages_manager_->on_update_dialog_group_call(group_call->dialog_id, group_call->is_active, - group_call->participant_count == 0, source); + group_call->participant_count == 0, source, force); } vector> GroupCallManager::get_recent_speakers( diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 7ef87bbf2..2e7afefee 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -39,6 +39,8 @@ class GroupCallManager : public Actor { DialogId get_group_call_participant_id(const td_api::object_ptr &message_sender); + bool is_group_call_being_joined(InputGroupCallId input_group_call_id) const; + GroupCallId get_group_call_id(InputGroupCallId input_group_call_id, DialogId dialog_id); void create_voice_chat(DialogId dialog_id, Promise &&promise); @@ -226,7 +228,7 @@ class GroupCallManager : public Actor { void try_clear_group_call_participants(InputGroupCallId input_group_call_id); - void update_group_call_dialog(const GroupCall *group_call, const char *source); + void update_group_call_dialog(const GroupCall *group_call, const char *source, bool force = false); vector> get_recent_speakers(const GroupCall *group_call, bool for_update); diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 522ab3349..300e2f1b6 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -11063,10 +11063,6 @@ void MessagesManager::on_dialog_deleted(DialogId dialog_id, Promise &&prom } void MessagesManager::on_update_dialog_group_call_rights(DialogId dialog_id) { - if (td_->auth_manager_->is_bot()) { - return; - } - auto d = get_dialog(dialog_id); if (d == nullptr) { // nothing to do @@ -29712,12 +29708,11 @@ void MessagesManager::do_set_dialog_folder_id(Dialog *d, FolderId folder_id) { } void MessagesManager::on_update_dialog_group_call(DialogId dialog_id, bool has_active_group_call, - bool is_group_call_empty, const char *source) { + bool is_group_call_empty, const char *source, bool force) { LOG(INFO) << "Update voice chat in " << dialog_id << " with has_active_voice_chat = " << has_active_group_call << " and is_voice_chat_empty = " << is_group_call_empty << " from " << source; - CHECK(dialog_id.is_valid()); - Dialog *d = get_dialog(dialog_id); // must not create the Dialog, because is called from on_get_chat + Dialog *d = get_dialog(dialog_id); // must not create the Dialog, because it is called from on_get_chat if (d == nullptr) { LOG(INFO) << "Can't find " << dialog_id; pending_dialog_group_call_updates_[dialog_id] = {has_active_group_call, is_group_call_empty}; @@ -29730,6 +29725,10 @@ void MessagesManager::on_update_dialog_group_call(DialogId dialog_id, bool has_a if (d->has_active_group_call == has_active_group_call && d->is_group_call_empty == is_group_call_empty) { return; } + if (!force && d->active_group_call_id.is_valid() && + td_->group_call_manager_->is_group_call_being_joined(d->active_group_call_id)) { + return; + } if (d->has_active_group_call && !has_active_group_call && d->active_group_call_id.is_valid()) { d->active_group_call_id = InputGroupCallId(); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index c809d4102..ef8cf9d4c 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -286,7 +286,7 @@ class MessagesManager : public Actor { void on_update_dialog_folder_id(DialogId dialog_id, FolderId folder_id); void on_update_dialog_group_call(DialogId dialog_id, bool has_active_group_call, bool is_group_call_empty, - const char *source); + const char *source, bool force = false); void on_update_dialog_group_call_id(DialogId dialog_id, InputGroupCallId input_group_call_id); From dd4aac2f57f423829ab57e0b1e1e2d619c429b7c Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 7 Mar 2021 01:54:45 +0300 Subject: [PATCH 017/281] Init bio in fake updateGroupCallParticipant when joining call. --- td/telegram/ContactsManager.cpp | 37 ++++++++++++++++++++++++++++++++ td/telegram/ContactsManager.h | 2 ++ td/telegram/GroupCallManager.cpp | 4 ++++ 3 files changed, 43 insertions(+) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 98df530a1..0d3e872c0 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -4769,6 +4769,43 @@ RestrictedRights ContactsManager::get_secret_chat_default_permissions(SecretChat return RestrictedRights(true, true, true, true, true, true, true, true, false, false, false); } +string ContactsManager::get_dialog_about(DialogId dialog_id) { + switch (dialog_id.get_type()) { + case DialogType::User: { + auto user_full = get_user_full_force(dialog_id.get_user_id()); + if (user_full != nullptr) { + return user_full->about; + } + break; + } + case DialogType::Chat: { + auto chat_full = get_chat_full_force(dialog_id.get_chat_id(), "get_dialog_about"); + if (chat_full != nullptr) { + return chat_full->description; + } + break; + } + case DialogType::Channel: { + auto channel_full = get_channel_full_force(dialog_id.get_channel_id(), "get_dialog_about"); + if (channel_full != nullptr) { + return channel_full->description; + } + break; + } + case DialogType::SecretChat: { + auto user_full = get_user_full_force(get_secret_chat_user_id(dialog_id.get_secret_chat_id())); + if (user_full != nullptr) { + return user_full->about; + } + break; + } + case DialogType::None: + default: + UNREACHABLE(); + } + return string(); +} + int32 ContactsManager::get_secret_chat_date(SecretChatId secret_chat_id) const { auto c = get_secret_chat(secret_chat_id); if (c == nullptr) { diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 749eaba3e..86694d116 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -128,6 +128,8 @@ class ContactsManager : public Actor { RestrictedRights get_channel_default_permissions(ChannelId channel_id) const; RestrictedRights get_secret_chat_default_permissions(SecretChatId secret_chat_id) const; + string get_dialog_about(DialogId dialog_id); + bool is_update_about_username_change_received(UserId user_id) const; void for_each_secret_chat_with_user(UserId user_id, std::function f); diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 643c67703..9f32d5fe8 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1564,6 +1564,9 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di if (!td_->messages_manager_->have_input_peer(as_dialog_id, AccessRights::Read)) { return promise.set_error(Status::Error(400, "Can't access the chat")); } + if (as_dialog_id.get_type() == DialogType::SecretChat) { + return promise.set_error(Status::Error(400, "Can't join voice chat as a secret chat")); + } } if (audio_source == 0) { @@ -1640,6 +1643,7 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di td_->messages_manager_->force_create_dialog(my_dialog_id, "join_group_call"); group_call_participant.dialog_id = my_dialog_id; } + group_call_participant.about = td_->contacts_manager_->get_dialog_about(group_call_participant.dialog_id); group_call_participant.audio_source = audio_source; group_call_participant.joined_date = G()->unix_time(); // if can_self_unmute has never been inited from self-participant, From caa1db85abacbe58ef1110f1b698d47ebdb18563 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 7 Mar 2021 02:21:08 +0300 Subject: [PATCH 018/281] Prevent race in updating of joined voice chat. --- td/telegram/GroupCallManager.cpp | 8 ++++++++ td/telegram/GroupCallManager.h | 2 ++ td/telegram/MessagesManager.cpp | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 9f32d5fe8..ddb439665 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -677,6 +677,14 @@ bool GroupCallManager::is_group_call_being_joined(InputGroupCallId input_group_c return pending_join_requests_.count(input_group_call_id) != 0; } +bool GroupCallManager::is_group_call_joined(InputGroupCallId input_group_call_id) const { + auto group_call = get_group_call(input_group_call_id); + if (group_call == nullptr) { + return false; + } + return group_call->is_joined && !group_call->is_being_left; +} + GroupCallId GroupCallManager::get_group_call_id(InputGroupCallId input_group_call_id, DialogId dialog_id) { if (td_->auth_manager_->is_bot() || !input_group_call_id.is_valid()) { return GroupCallId(); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 2e7afefee..7f04205e9 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -41,6 +41,8 @@ class GroupCallManager : public Actor { bool is_group_call_being_joined(InputGroupCallId input_group_call_id) const; + bool is_group_call_joined(InputGroupCallId input_group_call_id) const; + GroupCallId get_group_call_id(InputGroupCallId input_group_call_id, DialogId dialog_id); void create_voice_chat(DialogId dialog_id, Promise &&promise); diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 300e2f1b6..52a31bf36 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -29722,11 +29722,18 @@ void MessagesManager::on_update_dialog_group_call(DialogId dialog_id, bool has_a if (!has_active_group_call) { is_group_call_empty = false; } + if (d->active_group_call_id.is_valid() && has_active_group_call && is_group_call_empty && + (td_->group_call_manager_->is_group_call_being_joined(d->active_group_call_id) || + td_->group_call_manager_->is_group_call_joined(d->active_group_call_id))) { + LOG(INFO) << "Fix is_group_call_empty to false"; + is_group_call_empty = false; + } if (d->has_active_group_call == has_active_group_call && d->is_group_call_empty == is_group_call_empty) { return; } if (!force && d->active_group_call_id.is_valid() && td_->group_call_manager_->is_group_call_being_joined(d->active_group_call_id)) { + LOG(INFO) << "Ignore update in a being joined group call"; return; } From f4ce6c9de9fbe90a0efdfdfe01ac09f5e6a46185 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 7 Mar 2021 13:06:34 +0300 Subject: [PATCH 019/281] Update bio of group call participants when it is changed. --- td/telegram/ContactsManager.cpp | 30 ++++++++++++++++++++--- td/telegram/GroupCallManager.cpp | 42 ++++++++++++++++++++++++++++++++ td/telegram/GroupCallManager.h | 7 ++++++ 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 0d3e872c0..5ec074a99 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -22,6 +22,7 @@ #include "td/telegram/files/FileType.h" #include "td/telegram/FolderId.h" #include "td/telegram/Global.h" +#include "td/telegram/GroupCallManager.h" #include "td/telegram/InlineQueriesManager.h" #include "td/telegram/InputGroupCallId.h" #include "td/telegram/logevent/LogEvent.h" @@ -6143,6 +6144,7 @@ void ContactsManager::on_update_profile_success(int32 flags, const string &first user_full->about = about; user_full->is_changed = true; update_user_full(user_full, my_user_id); + td_->group_call_manager_->on_update_dialog_about(DialogId(my_user_id), user_full->about, true); } } } @@ -9249,6 +9251,8 @@ void ContactsManager::on_load_user_full_from_database(UserId user_id, string val register_user_photo(u, user_id, user_full->photo); } + td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, false); + update_user_full(user_full, user_id, true); if (is_user_deleted(user_id)) { @@ -9438,6 +9442,9 @@ void ContactsManager::on_load_chat_full_from_database(ChatId chat_id, string val reload_chat_full(chat_id, Auto()); } } + + td_->group_call_manager_->on_update_dialog_about(DialogId(chat_id), chat_full->description, false); + on_update_chat_full_photo(chat_full, chat_id, std::move(chat_full->photo)); update_chat_full(chat_full, chat_id, true); @@ -9548,6 +9555,8 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s } } + td_->group_call_manager_->on_update_dialog_about(DialogId(channel_id), channel_full->description, false); + td_->messages_manager_->on_dialog_bots_updated(DialogId(channel_id), channel_full->bot_user_ids, true); update_channel_full(channel_full, channel_id, true); @@ -10079,14 +10088,18 @@ void ContactsManager::on_get_user_full(tl_object_ptr &&u bool supports_video_calls = user->video_calls_available_ && !user->phone_calls_private_; bool has_private_calls = user->phone_calls_private_; if (user_full->can_be_called != can_be_called || user_full->supports_video_calls != supports_video_calls || - user_full->has_private_calls != has_private_calls || user_full->about != user->about_) { + user_full->has_private_calls != has_private_calls) { user_full->can_be_called = can_be_called; user_full->supports_video_calls = supports_video_calls; user_full->has_private_calls = has_private_calls; - user_full->about = std::move(user->about_); user_full->is_changed = true; } + if (user_full->about != user->about_) { + user_full->about = std::move(user->about_); + user_full->is_changed = true; + td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, true); + } auto photo = get_photo(td_->file_manager_.get(), std::move(user->profile_photo_), DialogId(user_id)); if (photo != user_full->photo) { @@ -10335,6 +10348,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c if (chat_full->description != chat->about_) { chat_full->description = std::move(chat->about_); chat_full->is_changed = true; + td_->group_call_manager_->on_update_dialog_about(DialogId(chat_id), chat_full->description, true); } if (chat_full->can_set_username != chat->can_set_username_) { chat_full->can_set_username = chat->can_set_username_; @@ -10428,7 +10442,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c channel_full->repair_request_version = 0; channel_full->expires_at = Time::now() + CHANNEL_FULL_EXPIRE_TIME; - if (channel_full->description != channel->about_ || channel_full->participant_count != participant_count || + if (channel_full->participant_count != participant_count || channel_full->administrator_count != administrator_count || channel_full->restricted_count != restricted_count || channel_full->banned_count != banned_count || channel_full->can_get_participants != can_get_participants || @@ -10438,7 +10452,6 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c channel_full->can_view_statistics != can_view_statistics || channel_full->stats_dc_id != stats_dc_id || channel_full->sticker_set_id != sticker_set_id || channel_full->is_all_history_available != is_all_history_available) { - channel_full->description = std::move(channel->about_); channel_full->participant_count = participant_count; channel_full->administrator_count = administrator_count; channel_full->restricted_count = restricted_count; @@ -10454,6 +10467,12 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c channel_full->is_changed = true; } + if (channel_full->description != channel->about_) { + channel_full->description = std::move(channel->about_); + channel_full->is_changed = true; + td_->group_call_manager_->on_update_dialog_about(DialogId(channel_id), channel_full->description, true); + } + if (have_participant_count && c->participant_count != participant_count) { c->participant_count = participant_count; c->is_changed = true; @@ -11219,6 +11238,7 @@ void ContactsManager::drop_user_full(UserId user_id) { user_full->is_changed = true; update_user_full(user_full, user_id); + td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, true); } void ContactsManager::update_user_online_member_count(User *u) { @@ -12749,6 +12769,7 @@ void ContactsManager::on_update_chat_description(ChatId chat_id, string &&descri chat_full->description = std::move(description); chat_full->is_changed = true; update_chat_full(chat_full, chat_id); + td_->group_call_manager_->on_update_dialog_about(DialogId(chat_id), chat_full->description, true); } } @@ -12949,6 +12970,7 @@ void ContactsManager::on_update_channel_description(ChannelId channel_id, string channel_full->description = std::move(description); channel_full->is_changed = true; update_channel_full(channel_full, channel_id); + td_->group_call_manager_->on_update_dialog_about(DialogId(channel_id), channel_full->description, true); } } diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index ddb439665..ccb672d88 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1484,6 +1484,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (old_participant.order != 0) { send_update_group_call_participant(input_group_call_id, participant); } + on_remove_group_call_participant(input_group_call_id, participant.dialog_id); remove_recent_group_call_speaker(input_group_call_id, participant.dialog_id); participants->participants.erase(participants->participants.begin() + i); return -1; @@ -1525,10 +1526,46 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (participants->participants.back().order != 0) { send_update_group_call_participant(input_group_call_id, participants->participants.back()); } + on_add_group_call_participant(input_group_call_id, participants->participants.back().dialog_id); on_participant_speaking_in_group_call(input_group_call_id, participants->participants.back()); return diff; } +void GroupCallManager::on_add_group_call_participant(InputGroupCallId input_group_call_id, + DialogId participant_dialog_id) { + participant_id_to_group_call_id_[participant_dialog_id].push_back(input_group_call_id); +} + +void GroupCallManager::on_remove_group_call_participant(InputGroupCallId input_group_call_id, + DialogId participant_dialog_id) { + auto it = participant_id_to_group_call_id_.find(participant_dialog_id); + CHECK(it != participant_id_to_group_call_id_.end()); + bool is_removed = td::remove(it->second, input_group_call_id); + CHECK(is_removed); + if (it->second.empty()) { + participant_id_to_group_call_id_.erase(it); + } +} + +void GroupCallManager::on_update_dialog_about(DialogId dialog_id, const string &about, bool from_server) { + auto it = participant_id_to_group_call_id_.find(dialog_id); + if (it == participant_id_to_group_call_id_.end()) { + return; + } + CHECK(!it->second.empty()); + + for (auto input_group_call_id : it->second) { + auto participant = get_group_call_participant(input_group_call_id, dialog_id); + CHECK(participant != nullptr); + if ((from_server || participant->is_fake) && participant->about != about) { + participant->about = about; + if (participant->order != 0) { + send_update_group_call_participant(input_group_call_id, *participant); + } + } + } +} + int32 GroupCallManager::cancel_join_group_call_request(InputGroupCallId input_group_call_id) { auto it = pending_join_requests_.find(input_group_call_id); if (it == pending_join_requests_.end()) { @@ -2461,6 +2498,11 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ participant.order = 0; send_update_group_call_participant(input_group_call_id, participant); } + on_remove_group_call_participant(input_group_call_id, participant.dialog_id); + } + + if (group_call_participants_.empty()) { + CHECK(participant_id_to_group_call_id_.empty()); } } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 7f04205e9..9f6ffc1f5 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -80,6 +80,8 @@ class GroupCallManager : public Actor { void discard_group_call(GroupCallId group_call_id, Promise &&promise); + void on_update_dialog_about(DialogId dialog_id, const string &about, bool from_server); + void on_update_group_call(tl_object_ptr group_call_ptr, DialogId dialog_id); void on_user_speaking_in_group_call(GroupCallId group_call_id, DialogId dialog_id, int32 date, @@ -172,6 +174,10 @@ class GroupCallManager : public Actor { int process_group_call_participant(InputGroupCallId group_call_id, GroupCallParticipant &&participant); + void on_add_group_call_participant(InputGroupCallId input_group_call_id, DialogId participant_dialog_id); + + void on_remove_group_call_participant(InputGroupCallId input_group_call_id, DialogId participant_dialog_id); + void try_load_group_call_administrators(InputGroupCallId input_group_call_id, DialogId dialog_id); void finish_load_group_call_administrators(InputGroupCallId input_group_call_id, Result &&result); @@ -262,6 +268,7 @@ class GroupCallManager : public Actor { std::unordered_map, InputGroupCallIdHash> group_call_participants_; + std::unordered_map, DialogIdHash> participant_id_to_group_call_id_; std::unordered_map, GroupCallIdHash> group_call_recent_speakers_; From 4eab57cd7b87774a19eeffb5ec06036a0bf40bd3 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 8 Mar 2021 15:13:36 +0300 Subject: [PATCH 020/281] Add chat.default_join_voice_chat_as_chat_id. --- td/generate/scheme/td_api.tl | 7 ++- td/telegram/ContactsManager.cpp | 20 +++++++ td/telegram/GroupCallManager.cpp | 24 +++++--- td/telegram/MessagesManager.cpp | 96 ++++++++++++++++++++++++++------ td/telegram/MessagesManager.h | 12 +++- 5 files changed, 127 insertions(+), 32 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index de02d6d8a..af32e683f 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -915,10 +915,11 @@ chatPosition list:ChatList order:int64 is_pinned:Bool source:ChatSource = ChatPo //@action_bar Describes actions which should be possible to do through a chat action bar; may be null //@voice_chat_group_call_id Group call identifier of an active voice chat; 0 if none or unknown. The voice chat can be received through the method getGroupCall //@is_voice_chat_empty True, if an active voice chat is empty +//@default_join_voice_chat_as_chat_id Chat identifier of a chat, under which name to join voice chat by default; 0 if none or unknown //@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat //@draft_message A draft of a message in the chat; may be null //@client_data Contains application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used -chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 action_bar:ChatActionBar voice_chat_group_call_id:int32 is_voice_chat_empty:Bool reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; +chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 action_bar:ChatActionBar voice_chat_group_call_id:int32 is_voice_chat_empty:Bool default_join_voice_chat_as_chat_id:int53 reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; //@description Represents a list of chats @total_count Approximate total count of chats found @chat_ids List of chat identifiers chats total_count:int32 chat_ids:vector = Chats; @@ -3387,8 +3388,8 @@ updateChatIsBlocked chat_id:int53 is_blocked:Bool = Update; //@description A chat's has_scheduled_messages field has changed @chat_id Chat identifier @has_scheduled_messages New value of has_scheduled_messages updateChatHasScheduledMessages chat_id:int53 has_scheduled_messages:Bool = Update; -//@description A chat voice chat state has changed @chat_id Chat identifier @voice_chat_group_call_id New value of voice_chat_group_call_id @is_voice_chat_empty New value of is_voice_chat_empty -updateChatVoiceChat chat_id:int53 voice_chat_group_call_id:int32 is_voice_chat_empty:Bool = Update; +//@description A chat voice chat state has changed @chat_id Chat identifier @voice_chat_group_call_id New value of voice_chat_group_call_id @is_voice_chat_empty New value of is_voice_chat_empty @default_join_voice_chat_as_chat_id Chat identifier of a chat, under which name to join voice chat by default; 0 if none or unknown +updateChatVoiceChat chat_id:int53 voice_chat_group_call_id:int32 is_voice_chat_empty:Bool default_join_voice_chat_as_chat_id:int53 = Update; //@description The value of the default disable_notification parameter, used when a message is sent to the chat, was changed @chat_id Chat identifier @default_disable_notification The new default_disable_notification value updateChatDefaultDisableNotification chat_id:int53 default_disable_notification:Bool = Update; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 5ec074a99..c360f0893 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -10326,6 +10326,16 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c } td_->messages_manager_->on_update_dialog_group_call_id(DialogId(chat_id), input_group_call_id); } + { + DialogId default_join_group_call_as_dialog_id; + if (chat->groupcall_default_join_as_ != nullptr) { + default_join_group_call_as_dialog_id = DialogId(chat->groupcall_default_join_as_); + } + // use send closure later to not crete synchronously default_join_group_call_as_dialog_id + send_closure_later(G()->messages_manager(), + &MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id, DialogId(chat_id), + default_join_group_call_as_dialog_id); + } { MessageTtlSetting message_ttl_setting; if ((chat->flags_ & CHAT_FULL_FLAG_HAS_MESSAGE_TTL) != 0) { @@ -10525,6 +10535,16 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c } td_->messages_manager_->on_update_dialog_group_call_id(DialogId(channel_id), input_group_call_id); } + { + DialogId default_join_group_call_as_dialog_id; + if (channel->groupcall_default_join_as_ != nullptr) { + default_join_group_call_as_dialog_id = DialogId(channel->groupcall_default_join_as_); + } + // use send closure later to not crete synchronously default_join_group_call_as_dialog_id + send_closure_later(G()->messages_manager(), + &MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id, DialogId(channel_id), + default_join_group_call_as_dialog_id); + } if (participant_count >= 190) { int32 online_member_count = 0; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index ccb672d88..6306144f6 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1676,18 +1676,18 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di request->query_ref = td_->create_handler(std::move(query_promise)) ->send(input_group_call_id, as_dialog_id, json_payload, is_muted, generation); + if (!as_dialog_id.is_valid()) { + as_dialog_id = DialogId(td_->contacts_manager_->get_my_id()); + } + if (group_call->dialog_id.is_valid()) { + td_->messages_manager_->on_update_dialog_default_join_group_call_as_dialog_id(group_call->dialog_id, as_dialog_id); + } else { + td_->messages_manager_->force_create_dialog(as_dialog_id, "join_group_call"); + } if (group_call->is_inited) { GroupCallParticipant group_call_participant; group_call_participant.is_self = true; - if (as_dialog_id.is_valid()) { - // dialog already exists - group_call_participant.dialog_id = as_dialog_id; - } else { - // create dialog with self - DialogId my_dialog_id(td_->contacts_manager_->get_my_id()); - td_->messages_manager_->force_create_dialog(my_dialog_id, "join_group_call"); - group_call_participant.dialog_id = my_dialog_id; - } + group_call_participant.dialog_id = as_dialog_id; group_call_participant.about = td_->contacts_manager_->get_dialog_about(group_call_participant.dialog_id); group_call_participant.audio_source = audio_source; group_call_participant.joined_date = G()->unix_time(); @@ -1893,6 +1893,12 @@ void GroupCallManager::finish_join_group_call(InputGroupCallId input_group_call_ pending_join_requests_.erase(it); try_clear_group_call_participants(input_group_call_id); process_group_call_after_join_requests(input_group_call_id); + + GroupCall *group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr); + if (group_call->dialog_id.is_valid()) { + td_->messages_manager_->reload_dialog_info_full(group_call->dialog_id); + } } void GroupCallManager::process_group_call_after_join_requests(InputGroupCallId input_group_call_id) { diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 52a31bf36..9eddbe3cc 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -5442,6 +5442,7 @@ void MessagesManager::Dialog::store(StorerT &storer) const { bool has_last_yet_unsent_message = last_message_id.is_valid() && last_message_id.is_yet_unsent(); bool has_active_group_call_id = active_group_call_id.is_valid(); bool has_message_ttl_setting = !message_ttl_setting.is_empty(); + bool has_default_join_group_call_as_dialog_id = default_join_group_call_as_dialog_id.is_valid(); BEGIN_STORE_FLAGS(); STORE_FLAG(has_draft_message); STORE_FLAG(has_last_database_message); @@ -5503,6 +5504,7 @@ void MessagesManager::Dialog::store(StorerT &storer) const { STORE_FLAG(can_invite_members); STORE_FLAG(has_message_ttl_setting); STORE_FLAG(is_message_ttl_setting_inited); + STORE_FLAG(has_default_join_group_call_as_dialog_id); END_STORE_FLAGS(); } @@ -5593,6 +5595,9 @@ void MessagesManager::Dialog::store(StorerT &storer) const { if (has_message_ttl_setting) { store(message_ttl_setting, storer); } + if (has_default_join_group_call_as_dialog_id) { + store(default_join_group_call_as_dialog_id, storer); + } } // do not forget to resolve dialog dependencies including dependencies of last_message @@ -5624,6 +5629,7 @@ void MessagesManager::Dialog::parse(ParserT &parser) { bool has_distance = false; bool has_active_group_call_id = false; bool has_message_ttl_setting = false; + bool has_default_join_group_call_as_dialog_id = false; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_draft_message); PARSE_FLAG(has_last_database_message); @@ -5685,6 +5691,7 @@ void MessagesManager::Dialog::parse(ParserT &parser) { PARSE_FLAG(can_invite_members); PARSE_FLAG(has_message_ttl_setting); PARSE_FLAG(is_message_ttl_setting_inited); + PARSE_FLAG(has_default_join_group_call_as_dialog_id); END_PARSE_FLAGS(); } else { is_folder_id_inited = false; @@ -5827,6 +5834,9 @@ void MessagesManager::Dialog::parse(ParserT &parser) { if (has_message_ttl_setting) { parse(message_ttl_setting, parser); } + if (has_default_join_group_call_as_dialog_id) { + parse(default_join_group_call_as_dialog_id, parser); + } } template @@ -19918,7 +19928,8 @@ td_api::object_ptr MessagesManager::get_chat_object(const Dialog * get_chat_notification_settings_object(&d->notification_settings), d->message_ttl_setting.get_message_ttl_setting_object(), get_chat_action_bar_object(d), active_group_call_id.get(), active_group_call_id.is_valid() ? d->is_group_call_empty : true, - d->reply_markup_message_id.get(), std::move(draft_message), d->client_data); + d->default_join_group_call_as_dialog_id.get(), d->reply_markup_message_id.get(), std::move(draft_message), + d->client_data); } tl_object_ptr MessagesManager::get_chat_object(DialogId dialog_id) const { @@ -28547,9 +28558,10 @@ void MessagesManager::send_update_chat_voice_chat(const Dialog *d) { LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_voice_chat"; on_dialog_updated(d->dialog_id, "send_update_chat_voice_chat"); auto group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, d->dialog_id); - send_closure(G()->td(), &Td::send_update, - td_api::make_object(d->dialog_id.get(), group_call_id.get(), - d->is_group_call_empty)); + send_closure( + G()->td(), &Td::send_update, + td_api::make_object(d->dialog_id.get(), group_call_id.get(), d->is_group_call_empty, + d->default_join_group_call_as_dialog_id.get())); } void MessagesManager::send_update_chat_message_ttl_setting(const Dialog *d) { @@ -29778,6 +29790,23 @@ void MessagesManager::on_update_dialog_group_call_id(DialogId dialog_id, InputGr } } +void MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id(DialogId dialog_id, + DialogId default_join_as_dialog_id) { + auto d = get_dialog_force(dialog_id); + if (d == nullptr) { + // nothing to do + return; + } + if (default_join_as_dialog_id.is_valid()) { + force_create_dialog(default_join_as_dialog_id, "on_update_dialog_default_join_group_call_as_dialog_id"); + } + + if (d->default_join_group_call_as_dialog_id != default_join_as_dialog_id) { + d->default_join_group_call_as_dialog_id = default_join_as_dialog_id; + send_update_chat_voice_chat(d); + } +} + void MessagesManager::on_update_dialog_message_ttl_setting(DialogId dialog_id, MessageTtlSetting message_ttl_setting) { auto d = get_dialog_force(dialog_id); if (d == nullptr) { @@ -33810,6 +33839,10 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&d, MessageId last_clear_history_message_id = d->last_clear_history_message_id; d->last_clear_history_date = 0; d->last_clear_history_message_id = MessageId(); + DialogId default_join_group_call_as_dialog_id = d->default_join_group_call_as_dialog_id; + if (default_join_group_call_as_dialog_id != dialog_id && !have_dialog(default_join_group_call_as_dialog_id)) { + d->default_join_group_call_as_dialog_id = DialogId(); + } if (d->message_notification_group.group_id.is_valid()) { notification_group_id_to_dialog_id_.emplace(d->message_notification_group.group_id, d->dialog_id); @@ -33848,14 +33881,15 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&d, send_update_new_chat(dialog); fix_new_dialog(dialog, std::move(last_database_message), last_database_message_id, order, last_clear_history_date, - last_clear_history_message_id, is_loaded_from_database); + last_clear_history_message_id, default_join_group_call_as_dialog_id, is_loaded_from_database); return dialog; } void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_database_message, MessageId last_database_message_id, int64 order, int32 last_clear_history_date, - MessageId last_clear_history_message_id, bool is_loaded_from_database) { + MessageId last_clear_history_message_id, + DialogId default_join_group_call_as_dialog_id, bool is_loaded_from_database) { CHECK(d != nullptr); auto dialog_id = d->dialog_id; auto dialog_type = dialog_id.get_type(); @@ -33959,18 +33993,32 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab } } - auto pending_it = pending_add_dialog_last_database_message_dependent_dialogs_.find(dialog_id); - if (pending_it != pending_add_dialog_last_database_message_dependent_dialogs_.end()) { - auto pending_dialogs = std::move(pending_it->second); - pending_add_dialog_last_database_message_dependent_dialogs_.erase(pending_it); + { + auto it = pending_add_dialog_last_database_message_dependent_dialogs_.find(dialog_id); + if (it != pending_add_dialog_last_database_message_dependent_dialogs_.end()) { + auto pending_dialog_ids = std::move(it->second); + pending_add_dialog_last_database_message_dependent_dialogs_.erase(it); - for (auto &pending_dialog_id : pending_dialogs) { - auto &counter_message = pending_add_dialog_last_database_message_[pending_dialog_id]; - CHECK(counter_message.first > 0); - counter_message.first--; - if (counter_message.first == 0) { - add_dialog_last_database_message(get_dialog(pending_dialog_id), std::move(counter_message.second)); - pending_add_dialog_last_database_message_.erase(pending_dialog_id); + for (auto &pending_dialog_id : pending_dialog_ids) { + auto &counter_message = pending_add_dialog_last_database_message_[pending_dialog_id]; + CHECK(counter_message.first > 0); + counter_message.first--; + if (counter_message.first == 0) { + add_dialog_last_database_message(get_dialog(pending_dialog_id), std::move(counter_message.second)); + pending_add_dialog_last_database_message_.erase(pending_dialog_id); + } + } + } + } + + { + auto it = pending_add_default_join_group_call_as_dialog_id_.find(dialog_id); + if (it != pending_add_default_join_group_call_as_dialog_id_.end()) { + auto pending_dialog_ids = std::move(it->second); + pending_add_default_join_group_call_as_dialog_id_.erase(it); + + for (auto &pending_dialog_id : pending_dialog_ids) { + on_update_dialog_default_join_group_call_as_dialog_id(pending_dialog_id, dialog_id); } } } @@ -34069,6 +34117,17 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab } } + if (default_join_group_call_as_dialog_id != d->default_join_group_call_as_dialog_id) { + CHECK(default_join_group_call_as_dialog_id.is_valid()); + if (!have_dialog(default_join_group_call_as_dialog_id)) { + LOG(INFO) << "Postpone adding of default join voice chat as " << default_join_group_call_as_dialog_id << " in " + << dialog_id; + pending_add_default_join_group_call_as_dialog_id_[default_join_group_call_as_dialog_id].push_back(dialog_id); + } else { + on_update_dialog_default_join_group_call_as_dialog_id(dialog_id, default_join_group_call_as_dialog_id); + } + } + switch (dialog_type) { case DialogType::User: break; @@ -34842,6 +34901,9 @@ unique_ptr MessagesManager::parse_dialog(DialogId dialo Dependencies dependencies; add_dialog_dependencies(dependencies, dialog_id); + if (d->default_join_group_call_as_dialog_id != dialog_id) { + add_dialog_and_dependencies(dependencies, d->default_join_group_call_as_dialog_id); + } if (d->messages != nullptr) { add_message_dependencies(dependencies, dialog_id, d->messages.get()); } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index ef8cf9d4c..c0e3487ba 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -290,6 +290,8 @@ class MessagesManager : public Actor { void on_update_dialog_group_call_id(DialogId dialog_id, InputGroupCallId input_group_call_id); + void on_update_dialog_default_join_group_call_as_dialog_id(DialogId dialog_id, DialogId default_join_as_dialog_id); + void on_update_dialog_message_ttl_setting(DialogId dialog_id, MessageTtlSetting message_ttl_setting); void on_update_dialog_filters(); @@ -502,6 +504,8 @@ class MessagesManager : public Actor { bool have_dialog_info(DialogId dialog_id) const; bool have_dialog_info_force(DialogId dialog_id) const; + void reload_dialog_info_full(DialogId dialog_id); + bool load_dialog(DialogId dialog_id, int left_tries, Promise &&promise); void load_dialogs(vector dialog_ids, Promise &&promise); @@ -1165,6 +1169,7 @@ class MessagesManager : public Actor { std::unordered_set updated_read_history_message_ids; LogEventIdWithGeneration set_folder_id_log_event_id; InputGroupCallId active_group_call_id; + DialogId default_join_group_call_as_dialog_id; FolderId folder_id; vector dialog_list_ids; // TODO replace with mask @@ -2401,7 +2406,7 @@ class MessagesManager : public Actor { void fix_new_dialog(Dialog *d, unique_ptr &&last_database_message, MessageId last_database_message_id, int64 order, int32 last_clear_history_date, MessageId last_clear_history_message_id, - bool is_loaded_from_database); + DialogId default_join_group_call_as_dialog_id, bool is_loaded_from_database); void add_dialog_last_database_message(Dialog *d, unique_ptr &&last_database_message); @@ -2428,8 +2433,6 @@ class MessagesManager : public Actor { void send_search_public_dialogs_query(const string &query, Promise &&promise); - void reload_dialog_info_full(DialogId dialog_id); - vector get_pinned_dialog_ids(DialogListId dialog_list_id) const; void reload_pinned_dialogs(DialogListId dialog_list_id, Promise &&promise); @@ -3285,6 +3288,9 @@ class MessagesManager : public Actor { std::unordered_map>, DialogIdHash> pending_add_dialog_last_database_message_; // dialog -> dependency counter + message + std::unordered_map, DialogIdHash> + pending_add_default_join_group_call_as_dialog_id_; // dialog_id -> dependent dialogs + struct CallsDbState { std::array first_calls_database_message_id_by_index; std::array message_count_by_index; From 159c4f3f003626422b7f7fc12ffd209428043815 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 8 Mar 2021 15:27:47 +0300 Subject: [PATCH 021/281] Remove race in default_join_as updating. --- td/telegram/ContactsManager.cpp | 4 ++-- td/telegram/GroupCallManager.cpp | 3 ++- td/telegram/MessagesManager.cpp | 14 +++++++++++--- td/telegram/MessagesManager.h | 3 ++- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index c360f0893..06abf3f95 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -10334,7 +10334,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c // use send closure later to not crete synchronously default_join_group_call_as_dialog_id send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id, DialogId(chat_id), - default_join_group_call_as_dialog_id); + default_join_group_call_as_dialog_id, false); } { MessageTtlSetting message_ttl_setting; @@ -10543,7 +10543,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c // use send closure later to not crete synchronously default_join_group_call_as_dialog_id send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id, DialogId(channel_id), - default_join_group_call_as_dialog_id); + default_join_group_call_as_dialog_id, false); } if (participant_count >= 190) { diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 6306144f6..63f105100 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1680,7 +1680,8 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di as_dialog_id = DialogId(td_->contacts_manager_->get_my_id()); } if (group_call->dialog_id.is_valid()) { - td_->messages_manager_->on_update_dialog_default_join_group_call_as_dialog_id(group_call->dialog_id, as_dialog_id); + td_->messages_manager_->on_update_dialog_default_join_group_call_as_dialog_id(group_call->dialog_id, as_dialog_id, + true); } else { td_->messages_manager_->force_create_dialog(as_dialog_id, "join_group_call"); } diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 9eddbe3cc..15467475b 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -29791,12 +29791,20 @@ void MessagesManager::on_update_dialog_group_call_id(DialogId dialog_id, InputGr } void MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id(DialogId dialog_id, - DialogId default_join_as_dialog_id) { + DialogId default_join_as_dialog_id, + bool force) { auto d = get_dialog_force(dialog_id); if (d == nullptr) { // nothing to do return; } + + if (!force && d->active_group_call_id.is_valid() && + td_->group_call_manager_->is_group_call_being_joined(d->active_group_call_id)) { + LOG(INFO) << "Ignore default_join_as_dialog_id update in a being joined group call"; + return; + } + if (default_join_as_dialog_id.is_valid()) { force_create_dialog(default_join_as_dialog_id, "on_update_dialog_default_join_group_call_as_dialog_id"); } @@ -34018,7 +34026,7 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab pending_add_default_join_group_call_as_dialog_id_.erase(it); for (auto &pending_dialog_id : pending_dialog_ids) { - on_update_dialog_default_join_group_call_as_dialog_id(pending_dialog_id, dialog_id); + on_update_dialog_default_join_group_call_as_dialog_id(pending_dialog_id, dialog_id, false); } } } @@ -34124,7 +34132,7 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab << dialog_id; pending_add_default_join_group_call_as_dialog_id_[default_join_group_call_as_dialog_id].push_back(dialog_id); } else { - on_update_dialog_default_join_group_call_as_dialog_id(dialog_id, default_join_group_call_as_dialog_id); + on_update_dialog_default_join_group_call_as_dialog_id(dialog_id, default_join_group_call_as_dialog_id, false); } } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index c0e3487ba..8777beb3e 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -290,7 +290,8 @@ class MessagesManager : public Actor { void on_update_dialog_group_call_id(DialogId dialog_id, InputGroupCallId input_group_call_id); - void on_update_dialog_default_join_group_call_as_dialog_id(DialogId dialog_id, DialogId default_join_as_dialog_id); + void on_update_dialog_default_join_group_call_as_dialog_id(DialogId dialog_id, DialogId default_join_as_dialog_id, + bool force); void on_update_dialog_message_ttl_setting(DialogId dialog_id, MessageTtlSetting message_ttl_setting); From f24ca02f37c7521e1d09c1d1a6da7015d1a29977 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 8 Mar 2021 17:00:39 +0300 Subject: [PATCH 022/281] Add td_api::voiceChat class. --- td/generate/scheme/td_api.tl | 17 +++++++++++------ td/telegram/MessagesManager.cpp | 22 +++++++++++----------- td/telegram/MessagesManager.h | 2 ++ 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index af32e683f..20363c82a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -891,6 +891,13 @@ chatSourcePublicServiceAnnouncement type:string text:string = ChatSource; chatPosition list:ChatList order:int64 is_pinned:Bool source:ChatSource = ChatPosition; +//@description Describes a voice chat +//@group_call_id Group call identifier of an active voice chat; 0 if none. Full informationa about the voice chat can be received through the method getGroupCall +//@has_participants True, if the voice chat has participants +//@default_join_as_chat_id Chat identifier of a chat, under which name to join voice chat by default; 0 if none or unknown +voiceChat group_call_id:int32 has_participants:Bool default_join_as_chat_id:int53 = VoiceChat; + + //@description A chat. (Can be a private chat, basic group, supergroup, or secret chat) //@id Chat unique identifier //@type Type of the chat @@ -913,13 +920,11 @@ chatPosition list:ChatList order:int64 is_pinned:Bool source:ChatSource = ChatPo //@notification_settings Notification settings for this chat //@message_ttl_setting Current message Time To Live setting (self-destruct timer) for the chat; 0 if not defined. TTL is counted from the time message or its content is viewed in secret chats and from the send date in other chats //@action_bar Describes actions which should be possible to do through a chat action bar; may be null -//@voice_chat_group_call_id Group call identifier of an active voice chat; 0 if none or unknown. The voice chat can be received through the method getGroupCall -//@is_voice_chat_empty True, if an active voice chat is empty -//@default_join_voice_chat_as_chat_id Chat identifier of a chat, under which name to join voice chat by default; 0 if none or unknown +//@voice_chat Contains information about voice chat of the chat //@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat //@draft_message A draft of a message in the chat; may be null //@client_data Contains application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used -chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 action_bar:ChatActionBar voice_chat_group_call_id:int32 is_voice_chat_empty:Bool default_join_voice_chat_as_chat_id:int53 reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; +chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 action_bar:ChatActionBar voice_chat:voiceChat reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; //@description Represents a list of chats @total_count Approximate total count of chats found @chat_ids List of chat identifiers chats total_count:int32 chat_ids:vector = Chats; @@ -3388,8 +3393,8 @@ updateChatIsBlocked chat_id:int53 is_blocked:Bool = Update; //@description A chat's has_scheduled_messages field has changed @chat_id Chat identifier @has_scheduled_messages New value of has_scheduled_messages updateChatHasScheduledMessages chat_id:int53 has_scheduled_messages:Bool = Update; -//@description A chat voice chat state has changed @chat_id Chat identifier @voice_chat_group_call_id New value of voice_chat_group_call_id @is_voice_chat_empty New value of is_voice_chat_empty @default_join_voice_chat_as_chat_id Chat identifier of a chat, under which name to join voice chat by default; 0 if none or unknown -updateChatVoiceChat chat_id:int53 voice_chat_group_call_id:int32 is_voice_chat_empty:Bool default_join_voice_chat_as_chat_id:int53 = Update; +//@description A chat voice chat state has changed @chat_id Chat identifier @voice_chat New value of voice_chat +updateChatVoiceChat chat_id:int53 voice_chat:voiceChat = Update; //@description The value of the default disable_notification parameter, used when a message is sent to the chat, was changed @chat_id Chat identifier @default_disable_notification The new default_disable_notification value updateChatDefaultDisableNotification chat_id:int53 default_disable_notification:Bool = Update; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 15467475b..a7e7e184d 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -19855,6 +19855,13 @@ td_api::object_ptr MessagesManager::get_chat_action_bar_o return nullptr; } +td_api::object_ptr MessagesManager::get_voice_chat_object(const Dialog *d) const { + auto active_group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, d->dialog_id); + return make_tl_object(active_group_call_id.get(), + active_group_call_id.is_valid() ? !d->is_group_call_empty : false, + d->default_join_group_call_as_dialog_id.get()); +} + td_api::object_ptr MessagesManager::get_chat_object(const Dialog *d) const { CHECK(d != nullptr); @@ -19914,8 +19921,6 @@ td_api::object_ptr MessagesManager::get_chat_object(const Dialog * // TODO hide/show draft message when can_send_message(dialog_id) changes auto draft_message = can_send_message(d->dialog_id).is_ok() ? get_draft_message_object(d->draft_message) : nullptr; - auto active_group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, d->dialog_id); - return make_tl_object( d->dialog_id.get(), get_chat_type_object(d->dialog_id), get_dialog_title(d->dialog_id), get_chat_photo_info_object(td_->file_manager_.get(), get_dialog_photo(d->dialog_id)), @@ -19926,10 +19931,8 @@ td_api::object_ptr MessagesManager::get_chat_object(const Dialog * d->server_unread_count + d->local_unread_count, d->last_read_inbox_message_id.get(), d->last_read_outbox_message_id.get(), d->unread_mention_count, get_chat_notification_settings_object(&d->notification_settings), - d->message_ttl_setting.get_message_ttl_setting_object(), get_chat_action_bar_object(d), - active_group_call_id.get(), active_group_call_id.is_valid() ? d->is_group_call_empty : true, - d->default_join_group_call_as_dialog_id.get(), d->reply_markup_message_id.get(), std::move(draft_message), - d->client_data); + d->message_ttl_setting.get_message_ttl_setting_object(), get_chat_action_bar_object(d), get_voice_chat_object(d), + d->reply_markup_message_id.get(), std::move(draft_message), d->client_data); } tl_object_ptr MessagesManager::get_chat_object(DialogId dialog_id) const { @@ -28557,11 +28560,8 @@ void MessagesManager::send_update_chat_voice_chat(const Dialog *d) { CHECK(d != nullptr); LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_voice_chat"; on_dialog_updated(d->dialog_id, "send_update_chat_voice_chat"); - auto group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, d->dialog_id); - send_closure( - G()->td(), &Td::send_update, - td_api::make_object(d->dialog_id.get(), group_call_id.get(), d->is_group_call_empty, - d->default_join_group_call_as_dialog_id.get())); + send_closure(G()->td(), &Td::send_update, + td_api::make_object(d->dialog_id.get(), get_voice_chat_object(d))); } void MessagesManager::send_update_chat_message_ttl_setting(const Dialog *d) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 8777beb3e..d8a72f0f0 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2418,6 +2418,8 @@ class MessagesManager : public Actor { td_api::object_ptr get_chat_action_bar_object(const Dialog *d, bool hide_unarchive = false) const; + td_api::object_ptr get_voice_chat_object(const Dialog *d) const; + td_api::object_ptr get_chat_object(const Dialog *d) const; Dialog *get_dialog(DialogId dialog_id); From 574884510bab80e5f737c343a80e116f4a9f4ab8 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 8 Mar 2021 18:08:41 +0300 Subject: [PATCH 023/281] Use MessageSender as participant_alias. --- td/generate/scheme/td_api.tl | 13 ++++++++---- td/telegram/GroupCallManager.cpp | 34 ++++++++++++++++++++++---------- td/telegram/MessagesManager.cpp | 19 ++++++++++++++++-- td/telegram/MessagesManager.h | 2 ++ td/telegram/Td.cpp | 3 ++- td/telegram/cli.cpp | 8 ++++---- 6 files changed, 58 insertions(+), 21 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 20363c82a..e1ba68242 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -894,8 +894,8 @@ chatPosition list:ChatList order:int64 is_pinned:Bool source:ChatSource = ChatPo //@description Describes a voice chat //@group_call_id Group call identifier of an active voice chat; 0 if none. Full informationa about the voice chat can be received through the method getGroupCall //@has_participants True, if the voice chat has participants -//@default_join_as_chat_id Chat identifier of a chat, under which name to join voice chat by default; 0 if none or unknown -voiceChat group_call_id:int32 has_participants:Bool default_join_as_chat_id:int53 = VoiceChat; +//@default_participant_alias Default group call participant identifier to join the voice chat; may be null +voiceChat group_call_id:int32 has_participants:Bool default_participant_alias:MessageSender = VoiceChat; //@description A chat. (Can be a private chat, basic group, supergroup, or secret chat) @@ -4559,8 +4559,13 @@ createVoiceChat chat_id:int53 = GroupCallId; //@description Returns information about a group call @group_call_id Group call identifier getGroupCall group_call_id:int32 = GroupCall; -//@description Joins a group call @group_call_id Group call identifier @as_chat_id If not 0, identifier of the chat, which will be used to join the call @payload Group join payload, received from tgcalls. Use null to cancel previous joinGroupCall request @source Caller synchronization source identifier; received from tgcalls @is_muted True, if the user's microphone is muted -joinGroupCall group_call_id:int32 as_chat_id:int53 payload:groupCallPayload source:int32 is_muted:Bool = GroupCallJoinResponse; +//@description Joins a group call +//@group_call_id Group call identifier +//@participant_alias Identifier of the group call participant, which will be used to join the call +//@payload Group join payload; received from tgcalls +//@source Caller synchronization source identifier; received from tgcalls +//@is_muted True, if the user's microphone is muted +joinGroupCall group_call_id:int32 participant_alias:MessageSender payload:groupCallPayload source:int32 is_muted:Bool = GroupCallJoinResponse; //@description Sets group call title. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title New group call title; 1-128 characters setGroupCallTitle group_call_id:int32 title:string = Ok; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 63f105100..609c8f7ed 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1602,14 +1602,29 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di cancel_join_group_call_request(input_group_call_id); - if (as_dialog_id != DialogId()) { - if (!td_->messages_manager_->have_dialog_force(as_dialog_id)) { - return promise.set_error(Status::Error(400, "Chat not found")); + bool have_as_dialog_id = true; + { + auto my_dialog_id = DialogId(td_->contacts_manager_->get_my_id()); + if (!as_dialog_id.is_valid()) { + as_dialog_id = my_dialog_id; + } + auto dialog_type = as_dialog_id.get_type(); + if (dialog_type == DialogType::User) { + if (as_dialog_id != my_dialog_id) { + return promise.set_error(Status::Error(400, "Can't join voice chat as another user")); + } + if (!td_->contacts_manager_->have_user_force(as_dialog_id.get_user_id())) { + have_as_dialog_id = false; + } + } else { + if (!td_->messages_manager_->have_dialog_force(as_dialog_id)) { + return promise.set_error(Status::Error(400, "Alias chat not found")); + } } if (!td_->messages_manager_->have_input_peer(as_dialog_id, AccessRights::Read)) { - return promise.set_error(Status::Error(400, "Can't access the chat")); + return promise.set_error(Status::Error(400, "Can't access the alias participant")); } - if (as_dialog_id.get_type() == DialogType::SecretChat) { + if (dialog_type == DialogType::SecretChat) { return promise.set_error(Status::Error(400, "Can't join voice chat as a secret chat")); } } @@ -1676,16 +1691,15 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di request->query_ref = td_->create_handler(std::move(query_promise)) ->send(input_group_call_id, as_dialog_id, json_payload, is_muted, generation); - if (!as_dialog_id.is_valid()) { - as_dialog_id = DialogId(td_->contacts_manager_->get_my_id()); - } if (group_call->dialog_id.is_valid()) { td_->messages_manager_->on_update_dialog_default_join_group_call_as_dialog_id(group_call->dialog_id, as_dialog_id, true); } else { - td_->messages_manager_->force_create_dialog(as_dialog_id, "join_group_call"); + if (as_dialog_id.get_type() != DialogType::User) { + td_->messages_manager_->force_create_dialog(as_dialog_id, "join_group_call"); + } } - if (group_call->is_inited) { + if (group_call->is_inited && have_as_dialog_id) { GroupCallParticipant group_call_participant; group_call_participant.is_self = true; group_call_participant.dialog_id = as_dialog_id; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index a7e7e184d..bf1e6b2c7 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -6108,6 +6108,13 @@ td_api::object_ptr MessagesManager::get_message_sender_ob return get_message_sender_object_const(user_id, dialog_id); } +td_api::object_ptr MessagesManager::get_message_sender_object_const(DialogId dialog_id) const { + if (dialog_id.get_type() == DialogType::User) { + return get_message_sender_object_const(dialog_id.get_user_id(), DialogId()); + } + return get_message_sender_object_const(UserId(), dialog_id); +} + td_api::object_ptr MessagesManager::get_message_sender_object(DialogId dialog_id) { if (dialog_id.get_type() == DialogType::User) { return get_message_sender_object(dialog_id.get_user_id(), DialogId()); @@ -19857,9 +19864,12 @@ td_api::object_ptr MessagesManager::get_chat_action_bar_o td_api::object_ptr MessagesManager::get_voice_chat_object(const Dialog *d) const { auto active_group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, d->dialog_id); + auto default_participant_alias = d->default_join_group_call_as_dialog_id.is_valid() + ? get_message_sender_object_const(d->default_join_group_call_as_dialog_id) + : nullptr; return make_tl_object(active_group_call_id.get(), active_group_call_id.is_valid() ? !d->is_group_call_empty : false, - d->default_join_group_call_as_dialog_id.get()); + std::move(default_participant_alias)); } td_api::object_ptr MessagesManager::get_chat_object(const Dialog *d) const { @@ -29806,7 +29816,12 @@ void MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id(Dial } if (default_join_as_dialog_id.is_valid()) { - force_create_dialog(default_join_as_dialog_id, "on_update_dialog_default_join_group_call_as_dialog_id"); + if (default_join_as_dialog_id.get_type() != DialogType::User) { + force_create_dialog(default_join_as_dialog_id, "on_update_dialog_default_join_group_call_as_dialog_id"); + } else if (!td_->contacts_manager_->have_user_force(default_join_as_dialog_id.get_user_id()) || + default_join_as_dialog_id != get_my_dialog_id()) { + default_join_as_dialog_id = DialogId(); + } } if (d->default_join_group_call_as_dialog_id != default_join_as_dialog_id) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index d8a72f0f0..c389151c7 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -147,6 +147,8 @@ class MessagesManager : public Actor { td_api::object_ptr get_message_sender_object(UserId user_id, DialogId dialog_id); + td_api::object_ptr get_message_sender_object_const(DialogId dialog_id) const; + td_api::object_ptr get_message_sender_object(DialogId dialog_id); static vector get_message_ids(const vector &input_message_ids); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index ce4f0bcb3..b674d1fd9 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5985,7 +5985,8 @@ void Td::on_request(uint64 id, const td_api::getGroupCall &request) { void Td::on_request(uint64 id, td_api::joinGroupCall &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - group_call_manager_->join_group_call(GroupCallId(request.group_call_id_), DialogId(request.as_chat_id_), + group_call_manager_->join_group_call(GroupCallId(request.group_call_id_), + group_call_manager_->get_group_call_participant_id(request.participant_alias_), std::move(request.payload_), request.source_, request.is_muted_, std::move(promise)); } diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 3378316ba..1dbbb0524 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2671,17 +2671,17 @@ class CliClient final : public Actor { send_request(td_api::make_object(as_group_call_id(args))); } else if (op == "jgc") { string group_call_id; - string chat_id; - get_args(args, group_call_id, chat_id); + string participant_alias; + get_args(args, group_call_id, participant_alias); vector> fingerprints; fingerprints.push_back(td_api::make_object("hash", "setup", "fingerprint")); fingerprints.push_back(td_api::make_object("h2", "s2", "fingerprint2")); send_request(td_api::make_object( - as_group_call_id(group_call_id), as_chat_id(chat_id), + as_group_call_id(group_call_id), as_message_sender(participant_alias), td_api::make_object("ufrag", "pwd", std::move(fingerprints)), group_call_source_, true)); } else if (op == "jgcc") { - send_request(td_api::make_object(as_group_call_id(args), 0, nullptr, 0, true)); + send_request(td_api::make_object(as_group_call_id(args), nullptr, nullptr, 0, true)); } else if (op == "sgct") { string chat_id; string title; From 62cfe3bdd99f439f4593bb2e6cc210569ce73319 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 8 Mar 2021 20:25:56 +0300 Subject: [PATCH 024/281] Add td_api::getAvailableVoiceChatAliases. --- td/generate/scheme/td_api.tl | 5 ++- td/telegram/GroupCallManager.cpp | 69 ++++++++++++++++++++++++++++++++ td/telegram/GroupCallManager.h | 2 + td/telegram/Td.cpp | 6 +++ td/telegram/Td.h | 2 + td/telegram/cli.cpp | 2 + 6 files changed, 85 insertions(+), 1 deletion(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index e1ba68242..46d64e19a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4553,6 +4553,9 @@ sendCallRating call_id:int32 rating:int32 comment:string problems:vector> promise_; + DialogId dialog_id_; + + public: + explicit GetGroupCallJoinAsQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send(DialogId dialog_id) { + dialog_id_ = dialog_id; + + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + CHECK(input_peer != nullptr); + + send_query(G()->net_query_creator().create(telegram_api::phone_getGroupCallJoinAs(std::move(input_peer)))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetGroupCallJoinAsQuery: " << to_string(ptr); + + td->contacts_manager_->on_get_users(std::move(ptr->users_), "GetGroupCallJoinAsQuery"); + td->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetGroupCallJoinAsQuery"); + + vector> participant_aliaces; + for (auto &peer : ptr->peers_) { + DialogId dialog_id(peer); + if (!dialog_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << dialog_id << " as join as peer for " << dialog_id_; + continue; + } + if (dialog_id.get_type() != DialogType::User) { + td->messages_manager_->force_create_dialog(dialog_id, "GetGroupCallJoinAsQuery"); + } + + participant_aliaces.push_back(td->messages_manager_->get_message_sender_object(dialog_id)); + } + + promise_.set_value(td_api::make_object(static_cast(participant_aliaces.size()), + std::move(participant_aliaces))); + } + + void on_error(uint64 id, Status status) override { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetGroupCallJoinAsQuery"); + promise_.set_error(std::move(status)); + } +}; + class CreateGroupCallQuery : public Td::ResultHandler { Promise promise_; DialogId dialog_id_; @@ -780,6 +834,21 @@ bool GroupCallManager::can_manage_group_call(InputGroupCallId input_group_call_i return can_manage_group_calls(group_call->dialog_id).is_ok(); } +void GroupCallManager::get_group_call_join_as(DialogId dialog_id, + Promise> &&promise) { + if (!dialog_id.is_valid()) { + return promise.set_error(Status::Error(400, "Invalid chat identifier specified")); + } + if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + return promise.set_error(Status::Error(400, "Chat not found")); + } + if (!td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) { + return promise.set_error(Status::Error(400, "Can't access chat")); + } + + td_->create_handler(std::move(promise))->send(dialog_id); +} + void GroupCallManager::create_voice_chat(DialogId dialog_id, Promise &&promise) { if (!dialog_id.is_valid()) { return promise.set_error(Status::Error(400, "Invalid chat identifier specified")); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 9f6ffc1f5..491097f5c 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -45,6 +45,8 @@ class GroupCallManager : public Actor { GroupCallId get_group_call_id(InputGroupCallId input_group_call_id, DialogId dialog_id); + void get_group_call_join_as(DialogId dialog_id, Promise> &&promise); + void create_voice_chat(DialogId dialog_id, Promise &&promise); void get_group_call(GroupCallId group_call_id, Promise> &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index b674d1fd9..bc1b04a4b 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5963,6 +5963,12 @@ void Td::on_request(uint64 id, td_api::sendCallDebugInformation &request) { std::move(request.debug_information_), std::move(promise)); } +void Td::on_request(uint64 id, const td_api::getAvailableVoiceChatAliases &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + group_call_manager_->get_group_call_join_as(DialogId(request.chat_id_), std::move(promise)); +} + void Td::on_request(uint64 id, const td_api::createVoiceChat &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index c60301b92..eba92303c 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -699,6 +699,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::sendCallDebugInformation &request); + void on_request(uint64 id, const td_api::getAvailableVoiceChatAliases &request); + void on_request(uint64 id, const td_api::createVoiceChat &request); void on_request(uint64 id, const td_api::getGroupCall &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 1dbbb0524..a84803e86 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2665,6 +2665,8 @@ class CliClient final : public Actor { as_call_id(call_id), rating, "Wow, such good call! (TDLib test)", std::move(problems))); } else if (op == "scdi" || op == "SendCallDebugInformation") { send_request(td_api::make_object(as_call_id(args), "{}")); + } else if (op == "gavca") { + send_request(td_api::make_object(as_chat_id(args))); } else if (op == "cvc") { send_request(td_api::make_object(as_chat_id(args))); } else if (op == "ggc") { From f7f01fd6eecdb6bb765b02ab9385313bbe75baac Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 8 Mar 2021 21:01:40 +0300 Subject: [PATCH 025/281] Add more knowledge about included headers to SplitSource.php. --- SplitSource.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SplitSource.php b/SplitSource.php index 2c5da8fa6..2b65aaa6f 100644 --- a/SplitSource.php +++ b/SplitSource.php @@ -278,12 +278,15 @@ function split_file($file, $chunks, $undo) { 'animations_manager[_(-][^.]|AnimationsManager[^;>]' => "AnimationsManager", 'audios_manager[_(-][^.]|AudiosManager' => "AudiosManager", 'auth_manager[_(-][^.]|AuthManager' => 'AuthManager', + 'background_manager[_(-][^.]|BackgroundManager' => "BackgroundManager", 'ConfigShared|shared_config[(]' => 'ConfigShared', 'contacts_manager[_(-][^.]|ContactsManager([^ ;.]| [^*])' => 'ContactsManager', + 'country_info_manager[_(-][^.]|CountryInfoManager' => 'CountryInfoManager', 'documents_manager[_(-][^.]|DocumentsManager' => "DocumentsManager", 'file_reference_manager[_(-][^.]|FileReferenceManager|file_references[)]' => 'FileReferenceManager', 'file_manager[_(-][^.]|FileManager([^ ;.]| [^*])|update_file[)]' => 'files/FileManager', 'G[(][)]|Global[^A-Za-z]' => 'Global', + 'group_call_manager[_(-][^.]|GroupCallManager' => 'GroupCallManager', 'HashtagHints' => 'HashtagHints', 'inline_queries_manager[_(-][^.]|InlineQueriesManager' => 'InlineQueriesManager', 'language_pack_manager[_(-][^.]|LanguagePackManager' => 'LanguagePackManager', @@ -291,6 +294,8 @@ function split_file($file, $chunks, $undo) { 'MessageCopyOptions' => 'MessageCopyOptions', 'messages_manager[_(-][^.]|MessagesManager' => 'MessagesManager', 'notification_manager[_(-][^.]|NotificationManager|notifications[)]' => 'NotificationManager', + 'phone_number_manager[_(-][^.]|PhoneNumberManager' => "PhoneNumberManager", + 'poll_manager[_(-][^.]|PollManager' => "PollManager", 'PublicDialogType|get_public_dialog_type' => 'PublicDialogType', 'SecretChatActor' => 'SecretChatActor', 'secret_chats_manager[_(-][^.]|SecretChatsManager' => 'SecretChatsManager', From ab614651f3abdf212cf21b478a44ba3a085b2cce Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 8 Mar 2021 22:27:58 +0300 Subject: [PATCH 026/281] Support 7 more HTTP response status codes. --- tdnet/td/net/HttpHeaderCreator.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tdnet/td/net/HttpHeaderCreator.h b/tdnet/td/net/HttpHeaderCreator.h index f79a485fe..a63cf6440 100644 --- a/tdnet/td/net/HttpHeaderCreator.h +++ b/tdnet/td/net/HttpHeaderCreator.h @@ -85,6 +85,8 @@ class HttpHeaderCreator { return CSlice("Not Modified"); case 307: return CSlice("Temporary Redirect"); + case 308: + return CSlice("Permanent Redirect"); case 400: return CSlice("Bad Request"); case 401: @@ -101,16 +103,28 @@ class HttpHeaderCreator { return CSlice("Request Timeout"); case 409: return CSlice("Conflict"); + case 410: + return CSlice("Gone"); case 411: return CSlice("Length Required"); + case 412: + return CSlice("Precondition Failed"); case 413: return CSlice("Request Entity Too Large"); case 414: return CSlice("Request-URI Too Long"); case 415: return CSlice("Unsupported Media Type"); + case 416: + return CSlice("Range Not Satisfiable"); + case 417: + return CSlice("Expectation Failed"); case 418: return CSlice("I'm a teapot"); + case 421: + return CSlice("Misdirected Request"); + case 426: + return CSlice("Upgrade Required"); case 429: return CSlice("Too Many Requests"); case 431: From 45b21b1f3395b59284a7c22386060505807df232 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 8 Mar 2021 22:56:05 +0300 Subject: [PATCH 027/281] Improve log messages. --- td/telegram/MessagesManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index fbeec71ff..156624a5d 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -13328,9 +13328,9 @@ std::pair> MessagesManager::creat bool is_pinned = (flags & MESSAGE_FLAG_IS_PINNED) != 0; LOG_IF(ERROR, is_channel_message != (dialog_type == DialogType::Channel)) - << "is_channel_message is wrong for message received in the " << dialog_id; + << "is_channel_message is wrong for " << message_id << " received in the " << dialog_id; LOG_IF(ERROR, is_channel_post && !is_broadcast_channel(dialog_id)) - << "is_channel_post is true for message received in the " << dialog_id; + << "is_channel_post is true for " << message_id << " received in the " << dialog_id; UserId my_id = td_->contacts_manager_->get_my_id(); DialogId my_dialog_id = DialogId(my_id); From 92d8d1b9fded3ca6ae89ecb6c17502e396f92f15 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 9 Mar 2021 01:06:38 +0300 Subject: [PATCH 028/281] Improve log messages. --- td/telegram/ContactsManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 566e03c51..587cb1733 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -13082,7 +13082,7 @@ void ContactsManager::on_update_chat_participant(ChatId chat_id, UserId user_id, } if (!chat_id.is_valid() || !user_id.is_valid() || date <= 0 || (old_participant == nullptr && new_participant == nullptr)) { - LOG(ERROR) << "Receive invalid updateChatParticipant in " << chat_id << " for " << user_id << " at " << date << ": " + LOG(ERROR) << "Receive invalid updateChatParticipant in " << chat_id << " by " << user_id << " at " << date << ": " << to_string(old_participant) << " -> " << to_string(new_participant); return; } @@ -13127,7 +13127,7 @@ void ContactsManager::on_update_channel_participant(ChannelId channel_id, UserId } if (!channel_id.is_valid() || !user_id.is_valid() || date <= 0 || (old_participant == nullptr && new_participant == nullptr)) { - LOG(ERROR) << "Receive invalid updateChannelParticipant in " << channel_id << " for " << user_id << " at " << date + LOG(ERROR) << "Receive invalid updateChannelParticipant in " << channel_id << " by " << user_id << " at " << date << ": " << to_string(old_participant) << " -> " << to_string(new_participant); return; } From cd2fbc19e6b3094f209528b3e82260e1ae5e6f5b Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 9 Mar 2021 18:12:15 +0300 Subject: [PATCH 029/281] Save group call's stream_dc_id. --- td/telegram/GroupCallManager.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index e3c3aef3f..149d81a39 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -13,6 +13,7 @@ #include "td/telegram/MessageId.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/misc.h" +#include "td/telegram/net/DcId.h" #include "td/telegram/net/NetQuery.h" #include "td/telegram/Td.h" #include "td/telegram/UpdatesManager.h" @@ -530,8 +531,9 @@ struct GroupCallManager::GroupCall { int32 duration = 0; int32 audio_source = 0; int32 joined_date = 0; - vector> after_join; + DcId stream_dc_id; + vector> after_join; bool have_pending_mute_new_participants = false; bool pending_mute_new_participants = false; string pending_title; @@ -2614,6 +2616,13 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrjoin_muted_; call.allowed_change_mute_new_participants = group_call->can_change_join_muted_; call.participant_count = group_call->participants_count_; + if ((group_call->flags_ & telegram_api::groupCall::STREAM_DC_ID_MASK) != 0) { + call.stream_dc_id = DcId::create(group_call->stream_dc_id_); + if (!call.stream_dc_id.is_exact()) { + LOG(ERROR) << "Receive invalid stream DC ID in " << input_group_call_id; + call.stream_dc_id = DcId(); + } + } call.version = group_call->version_; if (group_call->params_ != nullptr) { join_params = std::move(group_call->params_->data_); @@ -2701,6 +2710,9 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrcan_be_managed = call.can_be_managed; need_update = true; } + if (call.stream_dc_id != group_call->stream_dc_id) { + group_call->stream_dc_id = call.stream_dc_id; + } if (call.version > group_call->version) { if (group_call->version != -1) { // if we know group call version, then update participants only by corresponding updates From 67889cdcbc05d76989931966aae183b92a5af39e Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 10 Mar 2021 22:50:14 +0300 Subject: [PATCH 030/281] Add td_api::getGroupCallStreamSegment. --- td/generate/scheme/td_api.tl | 8 ++++- td/telegram/GroupCallManager.cpp | 51 +++++++++++++++++++++++++++++++ td/telegram/GroupCallManager.h | 3 ++ td/telegram/Td.cpp | 16 ++++++++++ td/telegram/Td.h | 2 ++ td/telegram/cli.cpp | 3 ++ td/telegram/files/FileManager.cpp | 4 +-- 7 files changed, 84 insertions(+), 3 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 46d64e19a..c4a542d59 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -455,7 +455,7 @@ chatMemberStatusCreator custom_title:string is_anonymous:Bool is_member:Bool = C //@description The user is a member of a chat and has some additional privileges. In basic groups, administrators can edit and delete messages sent by others, add new members, ban unprivileged members, and manage voice chats. In supergroups and channels, there are more detailed options for administrator privileges //@custom_title A custom title of the administrator; 0-16 characters without emojis; applicable to supergroups only //@can_be_edited True, if the current user can edit the administrator privileges for the called user -//@can_manage_chat True, if the administrator can get chat event log, get chat statistics, get message statistics in channels, get channel members, see anonymous administrators in supergoups and ignore slow mode. Implied by any other privilege; applicable to supergroups and channels only +//@can_manage_chat True, if the administrator can get chat event log, get chat statistics, get message statistics in channels, get channel members, see anonymous administrators in supergroups and ignore slow mode. Implied by any other privilege; applicable to supergroups and channels only //@can_change_info True, if the administrator can change the chat title, photo, and other settings //@can_post_messages True, if the administrator can create channel posts; applicable to channels only //@can_edit_messages True, if the administrator can edit messages of other users and pin messages; applicable to channels only @@ -4604,6 +4604,12 @@ leaveGroupCall group_call_id:int32 = Ok; //@description Discards a group call. Requires groupCall.can_be_managed @group_call_id Group call identifier discardGroupCall group_call_id:int32 = Ok; +//@description Returns a file with a segment of a group call stream in a modified OGG format +//@group_call_id Group call identifier +//@time_offset Point in time when the stream segment begins; Unix timestamp in milliseconds +//@scale Segment duration scale; 0-1. Segment's duration is 1000/(2**scale) milliseconds +getGroupCallStreamSegment group_call_id:int32 time_offset:int53 scale:int32 = FilePart; + //@description Changes the block state of a message sender. Currently, only users and supergroup chats can be blocked @sender Message Sender @is_blocked New value of is_blocked toggleMessageSenderIsBlocked sender:MessageSender is_blocked:Bool = Ok; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 149d81a39..53209ba6f 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -32,6 +32,42 @@ namespace td { +class GetGroupCallStreamQuery : public Td::ResultHandler { + Promise promise_; + + public: + explicit GetGroupCallStreamQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(InputGroupCallId input_group_call_id, DcId stream_dc_id, int64 time_offset, int32 scale) { + auto input_stream = make_tl_object(input_group_call_id.get_input_group_call(), + time_offset, scale); + int32 flags = 0; + send_query(G()->net_query_creator().create( + telegram_api::upload_getFile(flags, false /*ignored*/, false /*ignored*/, std::move(input_stream), 0, 1 << 20), + stream_dc_id, NetQuery::Type::DownloadSmall)); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + if (ptr->get_id() != telegram_api::upload_file::ID) { + return on_error(id, Status::Error(500, "Receive unexpected server response")); + } + + auto file = move_tl_object_as(ptr); + promise_.set_value(file->bytes_.as_slice().str()); + } + + void on_error(uint64 id, Status status) override { + promise_.set_error(std::move(status)); + } +}; + class GetGroupCallJoinAsQuery : public Td::ResultHandler { Promise> promise_; DialogId dialog_id_; @@ -1653,6 +1689,21 @@ int32 GroupCallManager::cancel_join_group_call_request(InputGroupCallId input_gr return audio_source; } +void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id, int64 time_offset, int32 scale, + Promise &&promise) { + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); + + auto *group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr); + + if (!group_call->stream_dc_id.is_exact()) { + return promise.set_error(Status::Error(400, "Group call can't be streamed")); + } + + td_->create_handler(std::move(promise)) + ->send(input_group_call_id, group_call->stream_dc_id, time_offset, scale); +} + void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, td_api::object_ptr &&payload, int32 audio_source, bool is_muted, diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 491097f5c..6f4e32679 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -56,6 +56,9 @@ class GroupCallManager : public Actor { void reload_group_call(InputGroupCallId input_group_call_id, Promise> &&promise); + void get_group_call_stream_segment(GroupCallId group_call_id, int64 time_offset, int32 scale, + Promise &&promise); + void join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, td_api::object_ptr &&payload, int32 audio_source, bool is_muted, Promise> &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index bc1b04a4b..b902b099d 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6065,6 +6065,22 @@ void Td::on_request(uint64 id, const td_api::discardGroupCall &request) { group_call_manager_->discard_group_call(GroupCallId(request.group_call_id_), std::move(promise)); } +void Td::on_request(uint64 id, const td_api::getGroupCallStreamSegment &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + td_api::object_ptr file_part; + file_part->data_ = result.move_as_ok(); + promise.set_value(std::move(file_part)); + } + }); + group_call_manager_->get_group_call_stream_segment(GroupCallId(request.group_call_id_), request.time_offset_, + request.scale_, std::move(query_promise)); +} + void Td::on_request(uint64 id, const td_api::upgradeBasicGroupChatToSupergroupChat &request) { CHECK_IS_USER(); CREATE_REQUEST(UpgradeGroupChatToSupergroupChatRequest, request.chat_id_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index eba92303c..4e0cfdd77 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -725,6 +725,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::discardGroupCall &request); + void on_request(uint64 id, const td_api::getGroupCallStreamSegment &request); + void on_request(uint64 id, const td_api::upgradeBasicGroupChatToSupergroupChat &request); void on_request(uint64 id, const td_api::getChatListsToAddChat &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index a84803e86..a6a5dbb80 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2671,6 +2671,9 @@ class CliClient final : public Actor { send_request(td_api::make_object(as_chat_id(args))); } else if (op == "ggc") { send_request(td_api::make_object(as_group_call_id(args))); + } else if (op == "ggcss") { + send_request(td_api::make_object(as_group_call_id(args), + (std::time(nullptr) - 5) * 1000, 0)); } else if (op == "jgc") { string group_call_id; string participant_alias; diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index fc9c8de5f..fc184db27 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -3167,8 +3167,8 @@ Result FileManager::get_map_thumbnail_file_id(Location location, int32 z x = clamp(x, 0, size - 1); // just in case y = clamp(y, 0, size - 1); // just in case - string conversion = PSTRING() << "#map#" << zoom << "#" << x << "#" << y << "#" << width << "#" << height << "#" - << scale << "#"; + string conversion = PSTRING() << "#map#" << zoom << '#' << x << '#' << y << '#' << width << '#' << height << '#' + << scale << '#'; return register_generate( owner_dialog_id.get_type() == DialogType::SecretChat ? FileType::EncryptedThumbnail : FileType::Thumbnail, FileLocationSource::FromUser, string(), std::move(conversion), owner_dialog_id, 0); From a6544e3068b3c1a83f890c7dd0a15f09fc774e44 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 10 Mar 2021 23:43:21 +0300 Subject: [PATCH 031/281] Use separate versions for different groupCall fields. --- td/telegram/GroupCallManager.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 53209ba6f..ae3496345 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -563,12 +563,16 @@ struct GroupCallManager::GroupCall { bool mute_new_participants = false; bool allowed_change_mute_new_participants = false; int32 participant_count = 0; - int32 version = -1; int32 duration = 0; int32 audio_source = 0; int32 joined_date = 0; DcId stream_dc_id; + int32 version = -1; + int32 title_version = -1; + int32 mute_version = -1; + int32 stream_dc_id_version = -1; + vector> after_join; bool have_pending_mute_new_participants = false; bool pending_mute_new_participants = false; @@ -2675,6 +2679,9 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrversion_; + call.title_version = group_call->version_; + call.mute_version = group_call->version_; + call.stream_dc_id_version = group_call->version_; if (group_call->params_ != nullptr) { join_params = std::move(group_call->params_->data_); } @@ -2717,7 +2724,6 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrmute_new_participants || call.allowed_change_mute_new_participants != group_call->allowed_change_mute_new_participants; - if (mute_flags_changed && call.version >= group_call->version) { + if (mute_flags_changed && call.mute_version >= group_call->mute_version) { auto old_mute_new_participants = get_group_call_mute_new_participants(group_call); need_update |= (call.allowed_change_mute_new_participants && call.can_be_managed) != (group_call->allowed_change_mute_new_participants && group_call->can_be_managed); group_call->mute_new_participants = call.mute_new_participants; group_call->allowed_change_mute_new_participants = call.allowed_change_mute_new_participants; + group_call->mute_version = call.mute_version; if (old_mute_new_participants != get_group_call_mute_new_participants(group_call)) { need_update = true; } } - if (call.title != group_call->title && call.version >= group_call->version) { + if (call.title != group_call->title && call.title_version >= group_call->title_version) { string old_group_call_title = get_group_call_title(group_call); group_call->title = std::move(call.title); + group_call->title_version = call.title_version; if (old_group_call_title != get_group_call_title(group_call)) { need_update = true; } @@ -2761,8 +2769,10 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrcan_be_managed = call.can_be_managed; need_update = true; } - if (call.stream_dc_id != group_call->stream_dc_id) { + if (call.stream_dc_id != group_call->stream_dc_id && + call.stream_dc_id_version >= group_call->stream_dc_id_version) { group_call->stream_dc_id = call.stream_dc_id; + group_call->stream_dc_id_version = call.stream_dc_id_version; } if (call.version > group_call->version) { if (group_call->version != -1) { From 92218450c5e33acc5042dce6a3ccff9c6090ceb8 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 11 Mar 2021 00:55:08 +0300 Subject: [PATCH 032/281] Add groupCall.record_duration. --- td/generate/scheme/td_api.tl | 3 ++- td/telegram/GroupCallManager.cpp | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index c4a542d59..c45870932 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2123,8 +2123,9 @@ groupCallRecentSpeaker speaker:MessageSender is_speaking:Bool = GroupCallRecentS //@recent_speakers Recently speaking users in the group call //@mute_new_participants True, if only group call administrators can unmute new participants //@can_change_mute_new_participants True, if the current user can enable or disable mute_new_participants setting +//@record_duration Duration of the ongoing group call recording, in seconds; 0 if none. An updateGroupCall update is not triggered when value of this field changes, but the same recording goes on //@duration Call duration; for ended calls only -groupCall id:int32 title:string is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector mute_new_participants:Bool can_change_mute_new_participants:Bool duration:int32 = GroupCall; +groupCall id:int32 title:string is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector mute_new_participants:Bool can_change_mute_new_participants:Bool record_duration:int32 duration:int32 = GroupCall; //@description Describes a payload fingerprint for interaction with tgcalls @hash Value of the field hash @setup Value of the field setup @fingerprint Value of the field fingerprint groupCallPayloadFingerprint hash:string setup:string fingerprint:string = GroupCallPayloadFingerprint; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index ae3496345..761628bb4 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -566,12 +566,14 @@ struct GroupCallManager::GroupCall { int32 duration = 0; int32 audio_source = 0; int32 joined_date = 0; + int32 record_start_date = 0; DcId stream_dc_id; int32 version = -1; int32 title_version = -1; int32 mute_version = -1; int32 stream_dc_id_version = -1; + int32 record_start_date_version = -1; vector> after_join; bool have_pending_mute_new_participants = false; @@ -2674,14 +2676,23 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrflags_ & telegram_api::groupCall::STREAM_DC_ID_MASK) != 0) { call.stream_dc_id = DcId::create(group_call->stream_dc_id_); if (!call.stream_dc_id.is_exact()) { - LOG(ERROR) << "Receive invalid stream DC ID in " << input_group_call_id; + LOG(ERROR) << "Receive invalid stream DC ID " << call.stream_dc_id << " in " << input_group_call_id; call.stream_dc_id = DcId(); } } + if ((group_call->flags_ & telegram_api::groupCall::RECORD_START_DATE_MASK) != 0) { + call.record_start_date = group_call->record_start_date_; + if (call.record_start_date <= 0) { + LOG(ERROR) << "Receive invalid record start date " << group_call->record_start_date_ << " in " + << input_group_call_id; + call.record_start_date = 0; + } + } call.version = group_call->version_; call.title_version = group_call->version_; call.mute_version = group_call->version_; call.stream_dc_id_version = group_call->version_; + call.record_start_date_version = group_call->version_; if (group_call->params_ != nullptr) { join_params = std::move(group_call->params_->data_); } @@ -2774,6 +2785,12 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrstream_dc_id = call.stream_dc_id; group_call->stream_dc_id_version = call.stream_dc_id_version; } + if (call.record_start_date != group_call->record_start_date && + call.record_start_date_version >= group_call->record_start_date_version) { + group_call->record_start_date = call.record_start_date; + group_call->record_start_date_version = call.record_start_date_version; + need_update = true; + } if (call.version > group_call->version) { if (group_call->version != -1) { // if we know group call version, then update participants only by corresponding updates @@ -3065,11 +3082,13 @@ tl_object_ptr GroupCallManager::get_group_call_object( bool mute_new_participants = get_group_call_mute_new_participants(group_call); bool can_change_mute_new_participants = group_call->is_active && group_call->can_be_managed && group_call->allowed_change_mute_new_participants; + int32 record_duration = + group_call->record_start_date == 0 ? 0 : max(G()->unix_time() - group_call->record_start_date + 1, 1); return td_api::make_object( group_call->group_call_id.get(), get_group_call_title(group_call), group_call->is_active, is_joined, group_call->need_rejoin, can_self_unmute, group_call->can_be_managed, group_call->participant_count, group_call->loaded_all_participants, std::move(recent_speakers), mute_new_participants, - can_change_mute_new_participants, group_call->duration); + can_change_mute_new_participants, record_duration, group_call->duration); } tl_object_ptr GroupCallManager::get_update_group_call_object( From 0fb6c52cd4a6bd30c09d1c8304c1c8d037958f53 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 11 Mar 2021 22:19:19 +0300 Subject: [PATCH 033/281] Support toggling group call recording. --- td/generate/scheme/td_api.tl | 6 ++ td/telegram/GroupCallManager.cpp | 126 ++++++++++++++++++++++++++++++- td/telegram/GroupCallManager.h | 13 ++++ td/telegram/Td.cpp | 15 ++++ td/telegram/Td.h | 4 + td/telegram/cli.cpp | 8 ++ 6 files changed, 169 insertions(+), 3 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index c45870932..16c31f19a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4582,6 +4582,12 @@ toggleGroupCallMuteNewParticipants group_call_id:int32 mute_new_participants:Boo //@group_call_id Group call identifier @user_ids User identifiers. At most 10 users can be invited simultaneously inviteGroupCallParticipants group_call_id:int32 user_ids:vector = Ok; +//@description Starts recording of a group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title Group call recording title; 0-128 characters +startGroupCallRecording group_call_id:int32 title:string = Ok; + +//@description Ends recording of a group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier +endGroupCallRecording group_call_id:int32 = Ok; + //@description Informs TDLib that a group call participant speaking state has changed @group_call_id Group call identifier //@source Group call participant's synchronization source identifier, or 0 for the current user @is_speaking True, if the user is speaking setGroupCallParticipantIsSpeaking group_call_id:int32 source:int32 is_speaking:Bool = Ok; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 761628bb4..207a33e27 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -417,6 +417,45 @@ class InviteToGroupCallQuery : public Td::ResultHandler { } }; +class ToggleGroupCallRecordQuery : public Td::ResultHandler { + Promise promise_; + + public: + explicit ToggleGroupCallRecordQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(InputGroupCallId input_group_call_id, bool is_enabled, const string &title) { + int32 flags = 0; + if (is_enabled) { + flags |= telegram_api::phone_toggleGroupCallRecord::START_MASK; + } + if (!title.empty()) { + flags |= telegram_api::phone_toggleGroupCallRecord::TITLE_MASK; + } + send_query(G()->net_query_creator().create(telegram_api::phone_toggleGroupCallRecord( + flags, false /*ignored*/, input_group_call_id.get_input_group_call(), title))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for ToggleGroupCallRecordQuery: " << to_string(ptr); + td->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); + } + + void on_error(uint64 id, Status status) override { + if (status.message() == "GROUPCALL_NOT_MODIFIED") { + promise_.set_value(Unit()); + return; + } + promise_.set_error(std::move(status)); + } +}; + class EditGroupCallParticipantQuery : public Td::ResultHandler { Promise promise_; @@ -579,6 +618,10 @@ struct GroupCallManager::GroupCall { bool have_pending_mute_new_participants = false; bool pending_mute_new_participants = false; string pending_title; + bool have_pending_record_start_date = false; + int32 pending_record_start_date = 0; + string pending_record_title; + uint64 toggle_recording_generation = 0; }; struct GroupCallManager::GroupCallParticipants { @@ -1059,6 +1102,17 @@ bool GroupCallManager::get_group_call_mute_new_participants(const GroupCall *gro : group_call->mute_new_participants; } +int32 GroupCallManager::get_group_call_record_start_date(const GroupCall *group_call) { + CHECK(group_call != nullptr); + return group_call->have_pending_record_start_date ? group_call->pending_record_start_date + : group_call->record_start_date; +} + +bool GroupCallManager::get_group_call_has_recording(const GroupCall *group_call) { + CHECK(group_call != nullptr); + return get_group_call_record_start_date(group_call) != 0; +} + bool GroupCallManager::need_group_call_participants(InputGroupCallId input_group_call_id) const { return need_group_call_participants(input_group_call_id, get_group_call(input_group_call_id)); } @@ -2228,6 +2282,69 @@ void GroupCallManager::invite_group_call_participants(GroupCallId group_call_id, td_->create_handler(std::move(promise))->send(input_group_call_id, std::move(input_users)); } +void GroupCallManager::toggle_group_call_recording(GroupCallId group_call_id, bool is_enabled, string title, + Promise &&promise) { + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || !group_call->can_be_managed) { + return promise.set_error(Status::Error(400, "Can't manage group call recording")); + } + + if (is_enabled == get_group_call_has_recording(group_call)) { + return promise.set_value(Unit()); + } + + // there is no reason to save promise; we will send an update with actual value anyway + + if (!group_call->have_pending_record_start_date) { + send_toggle_group_call_recording_query(input_group_call_id, is_enabled, title, toggle_recording_generation_ + 1); + } + group_call->have_pending_record_start_date = true; + group_call->pending_record_start_date = is_enabled ? G()->unix_time() : 0; + group_call->pending_record_title = std::move(title); + group_call->toggle_recording_generation = ++toggle_recording_generation_; + send_update_group_call(group_call, "toggle_group_call_recording"); + promise.set_value(Unit()); +} + +void GroupCallManager::send_toggle_group_call_recording_query(InputGroupCallId input_group_call_id, bool is_enabled, + const string &title, uint64 generation) { + auto promise = + PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, generation](Result result) { + send_closure(actor_id, &GroupCallManager::on_toggle_group_call_recording, input_group_call_id, generation, + std::move(result)); + }); + td_->create_handler(std::move(promise))->send(input_group_call_id, is_enabled, title); +} + +void GroupCallManager::on_toggle_group_call_recording(InputGroupCallId input_group_call_id, uint64 generation, + Result &&result) { + if (G()->close_flag()) { + return; + } + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active) { + return; + } + + CHECK(group_call->have_pending_record_start_date); + + if (group_call->toggle_recording_generation != generation && group_call->can_be_managed) { + // need to send another request + send_toggle_group_call_recording_query(input_group_call_id, group_call->pending_record_start_date != 0, + group_call->pending_record_title, group_call->toggle_recording_generation); + return; + } + + int32 current_record_start_date = get_group_call_record_start_date(group_call); + group_call->have_pending_record_start_date = false; + if (current_record_start_date != get_group_call_record_start_date(group_call)) { + send_update_group_call(group_call, "on_toggle_group_call_recording"); + } +} + void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_call_id, int32 audio_source, bool is_speaking, Promise &&promise, int32 date) { if (G()->close_flag()) { @@ -2787,9 +2904,12 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrrecord_start_date && call.record_start_date_version >= group_call->record_start_date_version) { + int32 old_record_start_date = get_group_call_record_start_date(group_call); group_call->record_start_date = call.record_start_date; group_call->record_start_date_version = call.record_start_date_version; - need_update = true; + if (old_record_start_date != get_group_call_record_start_date(group_call)) { + need_update = true; + } } if (call.version > group_call->version) { if (group_call->version != -1) { @@ -3082,8 +3202,8 @@ tl_object_ptr GroupCallManager::get_group_call_object( bool mute_new_participants = get_group_call_mute_new_participants(group_call); bool can_change_mute_new_participants = group_call->is_active && group_call->can_be_managed && group_call->allowed_change_mute_new_participants; - int32 record_duration = - group_call->record_start_date == 0 ? 0 : max(G()->unix_time() - group_call->record_start_date + 1, 1); + int32 record_start_date = get_group_call_record_start_date(group_call); + int32 record_duration = record_start_date == 0 ? 0 : max(G()->unix_time() - record_start_date + 1, 1); return td_api::make_object( group_call->group_call_id.get(), get_group_call_title(group_call), group_call->is_active, is_joined, group_call->need_rejoin, can_self_unmute, group_call->can_be_managed, group_call->participant_count, diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 6f4e32679..7dfe58d5b 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -70,6 +70,8 @@ class GroupCallManager : public Actor { void invite_group_call_participants(GroupCallId group_call_id, vector &&user_ids, Promise &&promise); + void toggle_group_call_recording(GroupCallId group_call_id, bool is_enabled, string title, Promise &&promise); + void set_group_call_participant_is_speaking(GroupCallId group_call_id, int32 audio_source, bool is_speaking, Promise &&promise, int32 date = 0); @@ -155,6 +157,10 @@ class GroupCallManager : public Actor { static bool get_group_call_mute_new_participants(const GroupCall *group_call); + static int32 get_group_call_record_start_date(const GroupCall *group_call); + + static bool get_group_call_has_recording(const GroupCall *group_call); + bool need_group_call_participants(InputGroupCallId input_group_call_id) const; bool need_group_call_participants(InputGroupCallId input_group_call_id, const GroupCall *group_call) const; @@ -212,6 +218,11 @@ class GroupCallManager : public Actor { void on_toggle_group_call_mute_new_participants(InputGroupCallId input_group_call_id, bool mute_new_participants, Result &&result); + void send_toggle_group_call_recording_query(InputGroupCallId input_group_call_id, bool is_enabled, + const string &title, uint64 generation); + + void on_toggle_group_call_recording(InputGroupCallId input_group_call_id, uint64 generation, Result &&result); + void on_toggle_group_call_participant_is_muted(InputGroupCallId input_group_call_id, DialogId dialog_id, uint64 generation, Promise &&promise); @@ -283,6 +294,8 @@ class GroupCallManager : public Actor { std::unordered_map, InputGroupCallIdHash> pending_join_requests_; uint64 join_group_request_generation_ = 0; + uint64 toggle_recording_generation_ = 0; + uint64 set_volume_level_generation_ = 0; uint64 toggle_is_muted_generation_ = 0; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index b902b099d..51392ede0 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6023,6 +6023,21 @@ void Td::on_request(uint64 id, const td_api::inviteGroupCallParticipants &reques std::move(promise)); } +void Td::on_request(uint64 id, td_api::startGroupCallRecording &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.title_); + CREATE_OK_REQUEST_PROMISE(); + group_call_manager_->toggle_group_call_recording(GroupCallId(request.group_call_id_), true, std::move(request.title_), + std::move(promise)); +} + +void Td::on_request(uint64 id, const td_api::endGroupCallRecording &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + group_call_manager_->toggle_group_call_recording(GroupCallId(request.group_call_id_), false, string(), + std::move(promise)); +} + void Td::on_request(uint64 id, const td_api::setGroupCallParticipantIsSpeaking &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 4e0cfdd77..597c83d3c 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -713,6 +713,10 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::inviteGroupCallParticipants &request); + void on_request(uint64 id, td_api::startGroupCallRecording &request); + + void on_request(uint64 id, const td_api::endGroupCallRecording &request); + void on_request(uint64 id, const td_api::setGroupCallParticipantIsSpeaking &request); void on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index a6a5dbb80..97db631e7 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2708,6 +2708,14 @@ class CliClient final : public Actor { get_args(args, group_call_id, user_ids); send_request(td_api::make_object(as_group_call_id(group_call_id), as_user_ids(user_ids))); + } else if (op == "sgcr") { + string chat_id; + string title; + get_args(args, chat_id, title); + send_request(td_api::make_object(as_group_call_id(chat_id), title)); + } else if (op == "egcr") { + string chat_id = args; + send_request(td_api::make_object(as_group_call_id(chat_id))); } else if (op == "tgcpim") { string group_call_id; string participant_id; From 9bfd98c08d465a3cd6a17393f310f45ea70e0155 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 12 Mar 2021 18:36:55 +0300 Subject: [PATCH 034/281] Add joinGroupCall.invite_hash. --- td/generate/scheme/td_api.tl | 3 ++- td/telegram/GroupCallManager.cpp | 20 +++++++++++++++----- td/telegram/GroupCallManager.h | 3 ++- td/telegram/Td.cpp | 3 ++- td/telegram/cli.cpp | 7 +++---- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 16c31f19a..fdbafe316 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4569,7 +4569,8 @@ getGroupCall group_call_id:int32 = GroupCall; //@payload Group join payload; received from tgcalls //@source Caller synchronization source identifier; received from tgcalls //@is_muted True, if the user's microphone is muted -joinGroupCall group_call_id:int32 participant_alias:MessageSender payload:groupCallPayload source:int32 is_muted:Bool = GroupCallJoinResponse; +//@invite_hash If non-empty, invite hash to be used to join the group call without being muted by administrators +joinGroupCall group_call_id:int32 participant_alias:MessageSender payload:groupCallPayload source:int32 is_muted:Bool invite_hash:string = GroupCallJoinResponse; //@description Sets group call title. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title New group call title; 1-128 characters setGroupCallTitle group_call_id:int32 title:string = Ok; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 207a33e27..e0d973edd 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -283,7 +283,7 @@ class JoinGroupCallQuery : public Td::ResultHandler { } NetQueryRef send(InputGroupCallId input_group_call_id, DialogId as_dialog_id, const string &payload, bool is_muted, - uint64 generation) { + const string &invite_hash, uint64 generation) { input_group_call_id_ = input_group_call_id; as_dialog_id_ = as_dialog_id; generation_ = generation; @@ -300,9 +300,12 @@ class JoinGroupCallQuery : public Td::ResultHandler { if (is_muted) { flags |= telegram_api::phone_joinGroupCall::MUTED_MASK; } + if (!invite_hash.empty()) { + flags |= telegram_api::phone_joinGroupCall::INVITE_HASH_MASK; + } auto query = G()->net_query_creator().create(telegram_api::phone_joinGroupCall( - flags, false /*ignored*/, input_group_call_id.get_input_group_call(), std::move(join_as_input_peer), string(), - make_tl_object(payload))); + flags, false /*ignored*/, input_group_call_id.get_input_group_call(), std::move(join_as_input_peer), + invite_hash, make_tl_object(payload))); auto join_query_ref = query.get_weak(); send_query(std::move(query)); return join_query_ref; @@ -1766,7 +1769,7 @@ void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id, void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, td_api::object_ptr &&payload, int32 audio_source, - bool is_muted, + bool is_muted, const string &invite_hash, Promise> &&promise) { TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); @@ -1871,7 +1874,7 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di result.move_as_error()); }); request->query_ref = td_->create_handler(std::move(query_promise)) - ->send(input_group_call_id, as_dialog_id, json_payload, is_muted, generation); + ->send(input_group_call_id, as_dialog_id, json_payload, is_muted, invite_hash, generation); if (group_call->dialog_id.is_valid()) { td_->messages_manager_->on_update_dialog_default_join_group_call_as_dialog_id(group_call->dialog_id, as_dialog_id, @@ -2133,6 +2136,11 @@ void GroupCallManager::set_group_call_title(GroupCallId group_call_id, string ti return promise.set_error(Status::Error(400, "Can't change group call title")); } + title = clean_name(title, MAX_TITLE_LENGTH); + if (title.empty()) { + return promise.set_error(Status::Error(3, "Title can't be empty")); + } + if (title == get_group_call_title(group_call)) { return promise.set_value(Unit()); } @@ -2291,6 +2299,8 @@ void GroupCallManager::toggle_group_call_recording(GroupCallId group_call_id, bo return promise.set_error(Status::Error(400, "Can't manage group call recording")); } + title = clean_name(title, MAX_TITLE_LENGTH); + if (is_enabled == get_group_call_has_recording(group_call)) { return promise.set_value(Unit()); } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 7dfe58d5b..b048d326c 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -61,7 +61,7 @@ class GroupCallManager : public Actor { void join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, td_api::object_ptr &&payload, int32 audio_source, bool is_muted, - Promise> &&promise); + const string &invite_hash, Promise> &&promise); void set_group_call_title(GroupCallId group_call_id, string title, Promise &&promise); @@ -113,6 +113,7 @@ class GroupCallManager : public Actor { static constexpr int32 RECENT_SPEAKER_TIMEOUT = 60 * 60; static constexpr int32 CHECK_GROUP_CALL_IS_JOINED_TIMEOUT = 10; + static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for group call/group call record title void tear_down() override; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 51392ede0..6b63f81cf 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5990,11 +5990,12 @@ void Td::on_request(uint64 id, const td_api::getGroupCall &request) { void Td::on_request(uint64 id, td_api::joinGroupCall &request) { CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.invite_hash_); CREATE_REQUEST_PROMISE(); group_call_manager_->join_group_call(GroupCallId(request.group_call_id_), group_call_manager_->get_group_call_participant_id(request.participant_alias_), std::move(request.payload_), request.source_, request.is_muted_, - std::move(promise)); + request.invite_hash_, std::move(promise)); } void Td::on_request(uint64 id, td_api::setGroupCallTitle &request) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 97db631e7..1294fd400 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2677,16 +2677,15 @@ class CliClient final : public Actor { } else if (op == "jgc") { string group_call_id; string participant_alias; - get_args(args, group_call_id, participant_alias); + string invite_hash; + get_args(args, group_call_id, participant_alias, invite_hash); vector> fingerprints; fingerprints.push_back(td_api::make_object("hash", "setup", "fingerprint")); fingerprints.push_back(td_api::make_object("h2", "s2", "fingerprint2")); send_request(td_api::make_object( as_group_call_id(group_call_id), as_message_sender(participant_alias), td_api::make_object("ufrag", "pwd", std::move(fingerprints)), group_call_source_, - true)); - } else if (op == "jgcc") { - send_request(td_api::make_object(as_group_call_id(args), nullptr, nullptr, 0, true)); + true, invite_hash)); } else if (op == "sgct") { string chat_id; string title; From 73bed3ed80f87957c41b8a4c0f0c22d8f35925a8 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 12 Mar 2021 18:58:43 +0300 Subject: [PATCH 035/281] Add resetGroupCallInviteHash method. --- td/generate/scheme/td_api.tl | 4 ++++ td/telegram/GroupCallManager.cpp | 12 ++++++++++++ td/telegram/GroupCallManager.h | 2 ++ td/telegram/Td.cpp | 6 ++++++ td/telegram/Td.h | 2 ++ td/telegram/cli.cpp | 2 ++ 6 files changed, 28 insertions(+) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index fdbafe316..7a236d53b 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4579,6 +4579,10 @@ setGroupCallTitle group_call_id:int32 title:string = Ok; //@group_call_id Group call identifier @mute_new_participants New value of the mute_new_participants setting toggleGroupCallMuteNewParticipants group_call_id:int32 mute_new_participants:Bool = Ok; +//@description Resets group call invite hash. Requires groupCall.can_be_managed group call flag +//@group_call_id Group call identifier +resetGroupCallInviteHash group_call_id:int32 = Ok; + //@description Invites users to a group call. Sends a service message of type messageInviteToGroupCall for voice chats //@group_call_id Group call identifier @user_ids User identifiers. At most 10 users can be invited simultaneously inviteGroupCallParticipants group_call_id:int32 user_ids:vector = Ok; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index e0d973edd..abf0c3c6d 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -2264,6 +2264,18 @@ void GroupCallManager::on_toggle_group_call_mute_new_participants(InputGroupCall } } +void GroupCallManager::reset_group_call_invite_hash(GroupCallId group_call_id, Promise &&promise) { + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || !group_call->can_be_managed) { + return promise.set_error(Status::Error(400, "Can't reset invite hash in the group call")); + } + + int32 flags = telegram_api::phone_toggleGroupCallSettings::RESET_INVITE_HASH_MASK; + td_->create_handler(std::move(promise))->send(flags, input_group_call_id, false); +} + void GroupCallManager::invite_group_call_participants(GroupCallId group_call_id, vector &&user_ids, Promise &&promise) { TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index b048d326c..7715d7f31 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -68,6 +68,8 @@ class GroupCallManager : public Actor { void toggle_group_call_mute_new_participants(GroupCallId group_call_id, bool mute_new_participants, Promise &&promise); + void reset_group_call_invite_hash(GroupCallId group_call_id, Promise &&promise); + void invite_group_call_participants(GroupCallId group_call_id, vector &&user_ids, Promise &&promise); void toggle_group_call_recording(GroupCallId group_call_id, bool is_enabled, string title, Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 6b63f81cf..cceec7fde 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6013,6 +6013,12 @@ void Td::on_request(uint64 id, const td_api::toggleGroupCallMuteNewParticipants request.mute_new_participants_, std::move(promise)); } +void Td::on_request(uint64 id, const td_api::resetGroupCallInviteHash &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + group_call_manager_->reset_group_call_invite_hash(GroupCallId(request.group_call_id_), std::move(promise)); +} + void Td::on_request(uint64 id, const td_api::inviteGroupCallParticipants &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 597c83d3c..f842229fe 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -711,6 +711,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::toggleGroupCallMuteNewParticipants &request); + void on_request(uint64 id, const td_api::resetGroupCallInviteHash &request); + void on_request(uint64 id, const td_api::inviteGroupCallParticipants &request); void on_request(uint64 id, td_api::startGroupCallRecording &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 1294fd400..403869763 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2694,6 +2694,8 @@ class CliClient final : public Actor { } else if (op == "tgcmnp" || op == "tgcmnpe") { send_request( td_api::make_object(as_group_call_id(args), op == "tgcmnpe")); + } else if (op == "rgcih") { + send_request(td_api::make_object(as_group_call_id(args))); } else if (op == "sgcpis") { string group_call_id; int32 source; From 0ec4c2084e4b2cdd9bd2c7dcd3edc0ca107ccad7 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 12 Mar 2021 19:29:06 +0300 Subject: [PATCH 036/281] Add td_api::getGroupCallInviteLink. --- td/generate/scheme/td_api.tl | 5 ++++ td/telegram/GroupCallManager.cpp | 47 ++++++++++++++++++++++++++++++++ td/telegram/GroupCallManager.h | 2 ++ td/telegram/Td.cpp | 14 ++++++++++ td/telegram/Td.h | 2 ++ td/telegram/cli.cpp | 6 ++++ 6 files changed, 76 insertions(+) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 7a236d53b..ce5fc2596 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4587,6 +4587,11 @@ resetGroupCallInviteHash group_call_id:int32 = Ok; //@group_call_id Group call identifier @user_ids User identifiers. At most 10 users can be invited simultaneously inviteGroupCallParticipants group_call_id:int32 user_ids:vector = Ok; +//@description Returns invite link to a voice chat in a public chat +//@group_call_id Group call identifier +//@can_self_unmute Pass true if the invite_link should contain an invite hash, passing which to joinGroupCall would allow the invited user to unmute themself. Requires groupCall.can_be_managed group call flag +getGroupCallInviteLink group_call_id:int32 can_self_unmute:Bool = HttpUrl; + //@description Starts recording of a group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title Group call recording title; 0-128 characters startGroupCallRecording group_call_id:int32 title:string = Ok; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index abf0c3c6d..584028a8c 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -420,6 +420,37 @@ class InviteToGroupCallQuery : public Td::ResultHandler { } }; +class ExportGroupCallInviteQuery : public Td::ResultHandler { + Promise promise_; + + public: + explicit ExportGroupCallInviteQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(InputGroupCallId input_group_call_id, bool can_self_unmute) { + int32 flags = 0; + if (can_self_unmute) { + flags |= telegram_api::phone_exportGroupCallInvite::CAN_SELF_UNMUTE_MASK; + } + send_query(G()->net_query_creator().create(telegram_api::phone_exportGroupCallInvite( + flags, false /*ignored*/, input_group_call_id.get_input_group_call()))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + promise_.set_value(std::move(ptr->link_)); + } + + void on_error(uint64 id, Status status) override { + promise_.set_error(std::move(status)); + } +}; + class ToggleGroupCallRecordQuery : public Td::ResultHandler { Promise promise_; @@ -2302,6 +2333,22 @@ void GroupCallManager::invite_group_call_participants(GroupCallId group_call_id, td_->create_handler(std::move(promise))->send(input_group_call_id, std::move(input_users)); } +void GroupCallManager::get_group_call_invite_link(GroupCallId group_call_id, bool can_self_unmute, + Promise &&promise) { + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active) { + return promise.set_error(Status::Error(400, "Can't get group call invite link")); + } + + if (can_self_unmute && !group_call->can_be_managed) { + return promise.set_error(Status::Error(400, "Not enough rights in the group call")); + } + + td_->create_handler(std::move(promise))->send(input_group_call_id, can_self_unmute); +} + void GroupCallManager::toggle_group_call_recording(GroupCallId group_call_id, bool is_enabled, string title, Promise &&promise) { TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 7715d7f31..abe76f6f8 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -72,6 +72,8 @@ class GroupCallManager : public Actor { void invite_group_call_participants(GroupCallId group_call_id, vector &&user_ids, Promise &&promise); + void get_group_call_invite_link(GroupCallId group_call_id, bool can_self_unmute, Promise &&promise); + void toggle_group_call_recording(GroupCallId group_call_id, bool is_enabled, string title, Promise &&promise); void set_group_call_participant_is_speaking(GroupCallId group_call_id, int32 audio_source, bool is_speaking, diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index cceec7fde..23c1d5c12 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6030,6 +6030,20 @@ void Td::on_request(uint64 id, const td_api::inviteGroupCallParticipants &reques std::move(promise)); } +void Td::on_request(uint64 id, const td_api::getGroupCallInviteLink &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(td_api::make_object(result.move_as_ok())); + } + }); + group_call_manager_->get_group_call_invite_link(GroupCallId(request.group_call_id_), request.can_self_unmute_, + std::move(query_promise)); +} + void Td::on_request(uint64 id, td_api::startGroupCallRecording &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.title_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index f842229fe..8b022e1d8 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -715,6 +715,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::inviteGroupCallParticipants &request); + void on_request(uint64 id, const td_api::getGroupCallInviteLink &request); + void on_request(uint64 id, td_api::startGroupCallRecording &request); void on_request(uint64 id, const td_api::endGroupCallRecording &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 403869763..81427b40f 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2709,6 +2709,12 @@ class CliClient final : public Actor { get_args(args, group_call_id, user_ids); send_request(td_api::make_object(as_group_call_id(group_call_id), as_user_ids(user_ids))); + } else if (op == "ggcil") { + string group_call_id; + bool can_self_unmute; + get_args(args, group_call_id, can_self_unmute); + send_request( + td_api::make_object(as_group_call_id(group_call_id), can_self_unmute)); } else if (op == "sgcr") { string chat_id; string title; From a833d5e2921491d902027d9ed93dedc64b7b0536 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 12 Mar 2021 19:31:52 +0300 Subject: [PATCH 037/281] Improve method name. --- td/generate/scheme/td_api.tl | 5 ++--- td/telegram/GroupCallManager.cpp | 2 +- td/telegram/GroupCallManager.h | 2 +- td/telegram/Td.cpp | 4 ++-- td/telegram/Td.h | 2 +- td/telegram/cli.cpp | 4 ++-- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index ce5fc2596..83cb6c325 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4579,9 +4579,8 @@ setGroupCallTitle group_call_id:int32 title:string = Ok; //@group_call_id Group call identifier @mute_new_participants New value of the mute_new_participants setting toggleGroupCallMuteNewParticipants group_call_id:int32 mute_new_participants:Bool = Ok; -//@description Resets group call invite hash. Requires groupCall.can_be_managed group call flag -//@group_call_id Group call identifier -resetGroupCallInviteHash group_call_id:int32 = Ok; +//@description Revokes invite link for a group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier +revokeGroupCallInviteLink group_call_id:int32 = Ok; //@description Invites users to a group call. Sends a service message of type messageInviteToGroupCall for voice chats //@group_call_id Group call identifier @user_ids User identifiers. At most 10 users can be invited simultaneously diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 584028a8c..35757b1ad 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -2295,7 +2295,7 @@ void GroupCallManager::on_toggle_group_call_mute_new_participants(InputGroupCall } } -void GroupCallManager::reset_group_call_invite_hash(GroupCallId group_call_id, Promise &&promise) { +void GroupCallManager::revoke_group_call_invite_link(GroupCallId group_call_id, Promise &&promise) { TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); auto *group_call = get_group_call(input_group_call_id); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index abe76f6f8..af4d6538a 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -68,7 +68,7 @@ class GroupCallManager : public Actor { void toggle_group_call_mute_new_participants(GroupCallId group_call_id, bool mute_new_participants, Promise &&promise); - void reset_group_call_invite_hash(GroupCallId group_call_id, Promise &&promise); + void revoke_group_call_invite_link(GroupCallId group_call_id, Promise &&promise); void invite_group_call_participants(GroupCallId group_call_id, vector &&user_ids, Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 23c1d5c12..634a6abb1 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6013,10 +6013,10 @@ void Td::on_request(uint64 id, const td_api::toggleGroupCallMuteNewParticipants request.mute_new_participants_, std::move(promise)); } -void Td::on_request(uint64 id, const td_api::resetGroupCallInviteHash &request) { +void Td::on_request(uint64 id, const td_api::revokeGroupCallInviteLink &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - group_call_manager_->reset_group_call_invite_hash(GroupCallId(request.group_call_id_), std::move(promise)); + group_call_manager_->revoke_group_call_invite_link(GroupCallId(request.group_call_id_), std::move(promise)); } void Td::on_request(uint64 id, const td_api::inviteGroupCallParticipants &request) { diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 8b022e1d8..9239a44b5 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -711,7 +711,7 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::toggleGroupCallMuteNewParticipants &request); - void on_request(uint64 id, const td_api::resetGroupCallInviteHash &request); + void on_request(uint64 id, const td_api::revokeGroupCallInviteLink &request); void on_request(uint64 id, const td_api::inviteGroupCallParticipants &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 81427b40f..86cd5c254 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2694,8 +2694,8 @@ class CliClient final : public Actor { } else if (op == "tgcmnp" || op == "tgcmnpe") { send_request( td_api::make_object(as_group_call_id(args), op == "tgcmnpe")); - } else if (op == "rgcih") { - send_request(td_api::make_object(as_group_call_id(args))); + } else if (op == "rgcil") { + send_request(td_api::make_object(as_group_call_id(args))); } else if (op == "sgcpis") { string group_call_id; int32 source; From 9ac71272a3711baff3e48cd5d5b6a8d8c9a4f3f7 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 12 Mar 2021 20:11:44 +0300 Subject: [PATCH 038/281] Support joining group call as a stream listener. --- td/generate/scheme/td_api.tl | 11 +++++++++-- td/telegram/GroupCallManager.cpp | 13 +++++++++---- td/telegram/GroupCallManager.h | 4 ++-- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 83cb6c325..600efb51e 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2138,8 +2138,15 @@ groupCallPayload ufrag:string pwd:string fingerprints:vector = GroupCallJoinResponse; + +//@class GroupCallJoinResponse @description Describes a group call join response + +//@description Contains data needed to join the group call with WebRTC @payload Group call payload to pass to tgcalls @candidates Join response candidates to pass to tgcalls +groupCallJoinResponseWebrtc payload:groupCallPayload candidates:vector = GroupCallJoinResponse; + +//@description Describes that group call needs to be joined as a stream +groupCallJoinResponseStream = GroupCallJoinResponse; + //@description Represents a group call participant //@participant Identifier of the group call participant diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 35757b1ad..b23a3c626 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -680,7 +680,7 @@ struct GroupCallManager::PendingJoinRequest { NetQueryRef query_ref; uint64 generation = 0; int32 audio_source = 0; - Promise> promise; + Promise> promise; }; GroupCallManager::GroupCallManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { @@ -1801,7 +1801,7 @@ void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id, void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, td_api::object_ptr &&payload, int32 audio_source, bool is_muted, const string &invite_hash, - Promise> &&promise) { + Promise> &&promise) { TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); auto *group_call = get_group_call(input_group_call_id); @@ -2017,7 +2017,7 @@ void GroupCallManager::process_join_group_call_response(InputGroupCallId input_g })); } -Result> GroupCallManager::get_group_call_join_response_object( +Result> GroupCallManager::get_group_call_join_response_object( string json_response) { auto r_value = json_decode(json_response); if (r_value.is_error()) { @@ -2030,6 +2030,11 @@ Result> GroupCallManager::get_ } auto &value_object = value.get_object(); + auto r_stream = get_json_object_bool_field(value_object, "stream"); + if (r_stream.is_ok() && r_stream.ok() == true) { + return td_api::make_object(); + } + TRY_RESULT(transport, get_json_object_field(value_object, "transport", JsonValue::Type::Object, false)); CHECK(transport.type() == JsonValue::Type::Object); auto &transport_object = transport.get_object(); @@ -2078,7 +2083,7 @@ Result> GroupCallManager::get_ } auto payload = td_api::make_object(ufrag, pwd, std::move(fingerprints_object)); - return td_api::make_object(std::move(payload), std::move(candidates_object)); + return td_api::make_object(std::move(payload), std::move(candidates_object)); } bool GroupCallManager::on_join_group_call_response(InputGroupCallId input_group_call_id, string json_response) { diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index af4d6538a..27173523c 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -61,7 +61,7 @@ class GroupCallManager : public Actor { void join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, td_api::object_ptr &&payload, int32 audio_source, bool is_muted, - const string &invite_hash, Promise> &&promise); + const string &invite_hash, Promise> &&promise); void set_group_call_title(GroupCallId group_call_id, string title, Promise &&promise); @@ -252,7 +252,7 @@ class GroupCallManager : public Actor { DialogId set_group_call_participant_is_speaking_by_source(InputGroupCallId input_group_call_id, int32 audio_source, bool is_speaking, int32 date); - static Result> get_group_call_join_response_object( + static Result> get_group_call_join_response_object( string json_response); void try_clear_group_call_participants(InputGroupCallId input_group_call_id); From 92b384f3f4f903a7e728c68be89ed49f4a6befe5 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 13 Mar 2021 02:49:40 +0300 Subject: [PATCH 039/281] Update group call title length limit. --- td/generate/scheme/td_api.tl | 2 +- td/telegram/GroupCallManager.cpp | 2 +- td/telegram/GroupCallManager.h | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 600efb51e..62db65789 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4579,7 +4579,7 @@ getGroupCall group_call_id:int32 = GroupCall; //@invite_hash If non-empty, invite hash to be used to join the group call without being muted by administrators joinGroupCall group_call_id:int32 participant_alias:MessageSender payload:groupCallPayload source:int32 is_muted:Bool invite_hash:string = GroupCallJoinResponse; -//@description Sets group call title. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title New group call title; 1-128 characters +//@description Sets group call title. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title New group call title; 1-64 characters setGroupCallTitle group_call_id:int32 title:string = Ok; //@description Toggles whether new participants of a group call can be unmuted only by administrators of the group call. Requires groupCall.can_change_mute_new_participants group call flag diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index b23a3c626..f165acbc3 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -2363,7 +2363,7 @@ void GroupCallManager::toggle_group_call_recording(GroupCallId group_call_id, bo return promise.set_error(Status::Error(400, "Can't manage group call recording")); } - title = clean_name(title, MAX_TITLE_LENGTH); + title = clean_name(title, MAX_RECORD_TITLE_LENGTH); if (is_enabled == get_group_call_has_recording(group_call)) { return promise.set_value(Unit()); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 27173523c..6f794bcfb 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -117,7 +117,8 @@ class GroupCallManager : public Actor { static constexpr int32 RECENT_SPEAKER_TIMEOUT = 60 * 60; static constexpr int32 CHECK_GROUP_CALL_IS_JOINED_TIMEOUT = 10; - static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for group call/group call record title + static constexpr size_t MAX_TITLE_LENGTH = 64; // server side limit for group call title length + static constexpr size_t MAX_RECORD_TITLE_LENGTH = 128; // server side limit for group call record title length void tear_down() override; From 2bcb81bec0ed3f537beef0d918757a0839e2209e Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sat, 13 Mar 2021 11:58:58 +0100 Subject: [PATCH 040/281] Describe memory cleanup errors --- td/telegram/MemoryManager.cpp | 19 +++++++++++++++++-- td/telegram/MemoryManager.h | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/td/telegram/MemoryManager.cpp b/td/telegram/MemoryManager.cpp index 5370164a5..22e792085 100644 --- a/td/telegram/MemoryManager.cpp +++ b/td/telegram/MemoryManager.cpp @@ -88,6 +88,13 @@ bool MemoryManager::can_manage_memory() const { if (!(td_->auth_manager_->is_authorized() && !G()->close_flag())) { return false; } + if (!do_session_settings_allow_for_memory_management()) { + return false; + } + return true; +} + +bool MemoryManager::do_session_settings_allow_for_memory_management() { if (G()->parameters().use_message_db || G()->parameters().use_chat_info_db || G()->parameters().use_file_db) { return false; } @@ -96,7 +103,9 @@ bool MemoryManager::can_manage_memory() const { void MemoryManager::get_memory_stats(bool full, Promise promise) const { if (!can_manage_memory()) { - promise.set_error(Status::Error(500, "Request aborted")); + auto value = MemoryStats("{}"); + + promise.set_value(std::move(value)); return; } @@ -202,7 +211,13 @@ void MemoryManager::get_memory_stats(bool full, Promise promise) co void MemoryManager::clean_memory(bool full, Promise promise) const { if (!can_manage_memory()) { - promise.set_error(Status::Error(500, "Request aborted")); + if (!do_session_settings_allow_for_memory_management()) { + promise.set_error(Status::Error(405, "MEMORY_STATS_DISALLOWED" + " Session settings don't allow memory optimization." + " If you want to optimize memory, you should completely disable all databases.")); + } else { + promise.set_error(Status::Error(405, "Can't manage memory now")); + } return; } diff --git a/td/telegram/MemoryManager.h b/td/telegram/MemoryManager.h index 39782641d..9b49f6283 100644 --- a/td/telegram/MemoryManager.h +++ b/td/telegram/MemoryManager.h @@ -50,6 +50,8 @@ class MemoryManager : public Actor { bool can_manage_memory() const; + static bool do_session_settings_allow_for_memory_management(); + void get_memory_stats(bool full, Promise promise) const; void clean_memory(bool full, Promise promise) const; From 4d754052e0882c7e8f949603268d02322f0a8d7a Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 13 Mar 2021 16:50:11 +0300 Subject: [PATCH 041/281] Fix getGroupCallStreamSegment. --- td/telegram/Td.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 634a6abb1..1ada45881 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6108,7 +6108,7 @@ void Td::on_request(uint64 id, const td_api::getGroupCallStreamSegment &request) if (result.is_error()) { promise.set_error(result.move_as_error()); } else { - td_api::object_ptr file_part; + auto file_part = td_api::make_object(); file_part->data_ = result.move_as_ok(); promise.set_value(std::move(file_part)); } From a4431b2604b440b0763b39b26fc7cb16e113f860 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 14 Mar 2021 04:33:51 +0300 Subject: [PATCH 042/281] Don't allow to show as speaking muted by admin participants. --- td/telegram/GroupCallManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index f165acbc3..ebcfc3586 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -3187,6 +3187,10 @@ DialogId GroupCallManager::set_group_call_participant_is_speaking_by_source(Inpu for (auto &participant : participants_it->second->participants) { if (participant.audio_source == audio_source) { + if (is_speaking && participant.get_is_muted_by_admin()) { + // don't allow to show as speaking muted by admin participants + return DialogId(); + } if (participant.is_speaking != is_speaking) { participant.is_speaking = is_speaking; if (is_speaking) { From 76dce207b3201fe2ebda941db1398c67adfce0f4 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 14 Mar 2021 05:08:37 +0300 Subject: [PATCH 043/281] Force getDifference after receiving an update with incorrect qts. --- td/telegram/UpdatesManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index 4a56771e6..41d4a3203 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -1653,6 +1653,7 @@ void UpdatesManager::add_pending_qts_update(tl_object_ptr CHECK(update != nullptr); if (qts <= 1) { LOG(ERROR) << "Receive wrong qts " << qts << " in " << oneline(to_string(update)); + schedule_get_difference("add_pending_qts_update"); promise.set_value(Unit()); return; } From 58d9f668c15aba845bba160a9c6775e40adab0aa Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 14 Mar 2021 05:19:07 +0300 Subject: [PATCH 044/281] Improve schedule_get_difference logging. --- td/telegram/UpdatesManager.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index 41d4a3203..e4767cfd9 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -216,7 +216,7 @@ void UpdatesManager::fill_qts_gap(void *td) { } void UpdatesManager::fill_get_difference_gap(void *td) { - fill_gap(td, "rare getDifference calls"); + fill_gap(td, nullptr); } void UpdatesManager::fill_gap(void *td, const char *source) { @@ -226,7 +226,9 @@ void UpdatesManager::fill_gap(void *td, const char *source) { } auto updates_manager = static_cast(td)->updates_manager_.get(); - LOG(WARNING) << "Filling gap in " << source << " by running getDifference"; + if (source != nullptr) { + LOG(WARNING) << "Filling gap in " << source << " by running getDifference"; + } updates_manager->get_difference("fill_gap"); } @@ -359,7 +361,7 @@ Promise<> UpdatesManager::set_pts(int32 pts, const char *source) { result = add_pts(pts); if (last_get_difference_pts_ < get_pts() - FORCED_GET_DIFFERENCE_PTS_DIFF) { last_get_difference_pts_ = get_pts(); - schedule_get_difference("set_pts"); + schedule_get_difference("rare pts getDifference"); } } else if (pts < get_pts()) { LOG(ERROR) << "Receive wrong pts = " << pts << " from " << source << ". Current pts = " << get_pts(); @@ -904,8 +906,8 @@ void UpdatesManager::on_failed_get_difference(Status &&error) { } void UpdatesManager::schedule_get_difference(const char *source) { - VLOG(get_difference) << "Schedule getDifference from " << source; if (!retry_timeout_.has_timeout()) { + LOG(WARNING) << "Schedule getDifference in " << retry_time_ << " seconds from " << source; retry_timeout_.set_callback(std::move(fill_get_difference_gap)); retry_timeout_.set_callback_data(static_cast(td_)); retry_timeout_.set_timeout_in(retry_time_); @@ -913,6 +915,8 @@ void UpdatesManager::schedule_get_difference(const char *source) { if (retry_time_ > 60) { retry_time_ = Random::fast(60, 80); } + } else { + VLOG(get_difference) << "Schedule getDifference from " << source; } } @@ -1653,7 +1657,7 @@ void UpdatesManager::add_pending_qts_update(tl_object_ptr CHECK(update != nullptr); if (qts <= 1) { LOG(ERROR) << "Receive wrong qts " << qts << " in " << oneline(to_string(update)); - schedule_get_difference("add_pending_qts_update"); + schedule_get_difference("wrong qts"); promise.set_value(Unit()); return; } @@ -1959,7 +1963,7 @@ void UpdatesManager::process_qts_update(tl_object_ptr &&up LOG(DEBUG) << "Process " << to_string(update_ptr); if (last_get_difference_qts_ < qts - FORCED_GET_DIFFERENCE_PTS_DIFF) { if (last_get_difference_qts_ != 0) { - schedule_get_difference("process_qts_update"); + schedule_get_difference("rare qts getDifference"); } last_get_difference_qts_ = qts; } From 449c37c41f36260b8c12f223d75c434c524061d6 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 14 Mar 2021 21:57:39 +0300 Subject: [PATCH 045/281] Fix building with Ninja. --- td/generate/CMakeLists.txt | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/td/generate/CMakeLists.txt b/td/generate/CMakeLists.txt index 8bcd1d724..7e0e2c6b5 100644 --- a/td/generate/CMakeLists.txt +++ b/td/generate/CMakeLists.txt @@ -107,6 +107,15 @@ if (NOT CMAKE_CROSSCOMPILING) add_subdirectory(tl-parser) set(TLO_AUTO_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/auto/tlo) + set(TLO_FILES ${TLO_AUTO_INCLUDE_DIR}/mtproto_api.tlo ${TLO_AUTO_INCLUDE_DIR}/secret_api.tlo ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo ${TLO_AUTO_INCLUDE_DIR}/telegram_api.tlo) + set(TD_API_TLO_FILE ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo) + + # Ninja generator uses relative paths and can't correctly handle these dependencies + # See https://gitlab.kitware.com/cmake/cmake/-/issues/13894 + if (CMAKE_GENERATOR STREQUAL "Ninja") + set(TLO_FILES) + set(TD_API_TLO_FILE) + endif() add_custom_target(tl_generate_tlo WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -124,7 +133,7 @@ if (NOT CMAKE_CROSSCOMPILING) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${GENERATE_COMMON_CMD} COMMENT "Generate common TL source files" - DEPENDS generate_common tl_generate_tlo ${TLO_AUTO_INCLUDE_DIR}/mtproto_api.tlo ${TLO_AUTO_INCLUDE_DIR}/secret_api.tlo ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo ${TLO_AUTO_INCLUDE_DIR}/telegram_api.tlo ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ${CMAKE_CURRENT_SOURCE_DIR}/DoxygenTlDocumentationGenerator.php + DEPENDS generate_common tl_generate_tlo ${TLO_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ${CMAKE_CURRENT_SOURCE_DIR}/DoxygenTlDocumentationGenerator.php ) if (TD_ENABLE_JNI) target_compile_definitions(generate_common PRIVATE TD_ENABLE_JNI=1) @@ -139,7 +148,7 @@ if (NOT CMAKE_CROSSCOMPILING) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND generate_c COMMENT "Generate C TL source files" - DEPENDS generate_c tl_generate_tlo ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl + DEPENDS generate_c tl_generate_tlo ${TD_API_TLO_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ) add_executable(td_generate_java_api ${TL_GENERATE_JAVA_SOURCE}) @@ -151,7 +160,7 @@ if (NOT CMAKE_CROSSCOMPILING) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND generate_json COMMENT "Generate JSON TL source files" - DEPENDS generate_json tl_generate_tlo ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl + DEPENDS generate_json tl_generate_tlo ${TD_API_TLO_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ) if (TD_ENABLE_JNI) @@ -162,9 +171,9 @@ if (NOT CMAKE_CROSSCOMPILING) if (TD_ENABLE_DOTNET) if (PHP_EXECUTABLE) - set(GENERATE_DOTNET_API_CMD td_generate_dotnet_api ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo && ${PHP_EXECUTABLE} DotnetTlDocumentationGenerator.php scheme/td_api.tl auto/td/telegram/TdDotNetApi.h) + set(GENERATE_DOTNET_API_CMD td_generate_dotnet_api ${TD_API_TLO_FILE} && ${PHP_EXECUTABLE} DotnetTlDocumentationGenerator.php scheme/td_api.tl auto/td/telegram/TdDotNetApi.h) else() - set(GENERATE_DOTNET_API_CMD td_generate_dotnet_api ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo) + set(GENERATE_DOTNET_API_CMD td_generate_dotnet_api ${TD_API_TLO_FILE}) endif() add_executable(td_generate_dotnet_api generate_dotnet.cpp tl_writer_dotnet.h) @@ -173,7 +182,7 @@ if (NOT CMAKE_CROSSCOMPILING) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${GENERATE_DOTNET_API_CMD} COMMENT "Generate .NET API files" - DEPENDS td_generate_dotnet_api tl_generate_tlo ${TLO_AUTO_INCLUDE_DIR}/td_api.tlo ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ${CMAKE_CURRENT_SOURCE_DIR}/DotnetTlDocumentationGenerator.php + DEPENDS td_generate_dotnet_api tl_generate_tlo ${TD_API_TLO_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tl ${CMAKE_CURRENT_SOURCE_DIR}/DotnetTlDocumentationGenerator.php ) endif() From e2ac80f2ba5e5935b5593265ecf88c72664f572a Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 01:56:59 +0300 Subject: [PATCH 046/281] Add td_api::toggleGroupCallParticipantIsHandRaised. --- td/generate/scheme/td_api.tl | 5 ++ td/telegram/GroupCallManager.cpp | 106 +++++++++++++++++++++++++++++-- td/telegram/GroupCallManager.h | 12 +++- td/telegram/Td.cpp | 8 +++ td/telegram/Td.h | 2 + td/telegram/cli.cpp | 7 ++ 6 files changed, 133 insertions(+), 7 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 62db65789..69c6d7eaf 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4616,6 +4616,11 @@ toggleGroupCallParticipantIsMuted group_call_id:int32 participant:MessageSender //@group_call_id Group call identifier @participant Participant identifier @volume_level New participant's volume level; 1-20000 in hundreds of percents setGroupCallParticipantVolumeLevel group_call_id:int32 participant:MessageSender volume_level:int32 = Ok; +//@description Toggles whether a group call participant hand is rased +//@group_call_id Group call identifier @participant Participant identifier +//@is_hand_raised Pass true if the user's hand should be raised. Only self hand can be raised. Requires groupCall.can_be_managed group call flag to lower other's hand +toggleGroupCallParticipantIsHandRaised group_call_id:int32 participant:MessageSender is_hand_raised:Bool = Ok; + //@description Loads more group call participants. The loaded participants will be received through updates. Use the field groupCall.loaded_all_participants to check whether all participants has already been loaded //@group_call_id Group call identifier. The group call must be previously received through getGroupCall and must be joined or being joined //@limit Maximum number of participants to load diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index ebcfc3586..2fa3720af 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -497,12 +497,15 @@ class EditGroupCallParticipantQuery : public Td::ResultHandler { explicit EditGroupCallParticipantQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(InputGroupCallId input_group_call_id, DialogId dialog_id, bool is_muted, int32 volume_level) { + void send(InputGroupCallId input_group_call_id, DialogId dialog_id, bool is_muted, int32 volume_level, + bool set_raise_hand, bool raise_hand) { auto input_peer = MessagesManager::get_input_peer_force(dialog_id); CHECK(input_peer != nullptr); int32 flags = 0; - if (volume_level) { + if (set_raise_hand) { + flags |= telegram_api::phone_editGroupCallParticipant::RAISE_HAND_MASK; + } else if (volume_level) { flags |= telegram_api::phone_editGroupCallParticipant::VOLUME_MASK; } else if (is_muted) { flags |= telegram_api::phone_editGroupCallParticipant::MUTED_MASK; @@ -510,7 +513,7 @@ class EditGroupCallParticipantQuery : public Td::ResultHandler { send_query(G()->net_query_creator().create(telegram_api::phone_editGroupCallParticipant( flags, false /*ignored*/, input_group_call_id.get_input_group_call(), std::move(input_peer), volume_level, - false))); + raise_hand))); } void on_result(uint64 id, BufferSlice packet) override { @@ -2564,7 +2567,7 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ generation, std::move(promise)); }); td_->create_handler(std::move(query_promise)) - ->send(input_group_call_id, dialog_id, is_muted, 0); + ->send(input_group_call_id, dialog_id, is_muted, 0, false, false); } void GroupCallManager::on_toggle_group_call_participant_is_muted(InputGroupCallId input_group_call_id, @@ -2654,7 +2657,7 @@ void GroupCallManager::set_group_call_participant_volume_level(GroupCallId group dialog_id, generation, std::move(promise)); }); td_->create_handler(std::move(query_promise)) - ->send(input_group_call_id, dialog_id, false, volume_level); + ->send(input_group_call_id, dialog_id, false, volume_level, false, false); } void GroupCallManager::on_set_group_call_participant_volume_level(InputGroupCallId input_group_call_id, @@ -2687,6 +2690,99 @@ void GroupCallManager::on_set_group_call_participant_volume_level(InputGroupCall promise.set_value(Unit()); } +void GroupCallManager::toggle_group_call_participant_is_hand_raised(GroupCallId group_call_id, DialogId dialog_id, + bool is_hand_raised, Promise &&promise) { + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active) { + return promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); + } + if (!group_call->is_joined) { + if (is_group_call_being_joined(input_group_call_id) || group_call->need_rejoin) { + group_call->after_join.push_back( + PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, dialog_id, is_hand_raised, + promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); + } else { + send_closure(actor_id, &GroupCallManager::toggle_group_call_participant_is_hand_raised, group_call_id, + dialog_id, is_hand_raised, std::move(promise)); + } + })); + return; + } + return promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); + } + + auto participants = add_group_call_participants(input_group_call_id); + auto participant = get_group_call_participant(participants, dialog_id); + if (participant == nullptr) { + return promise.set_error(Status::Error(400, "Can't find group call participant")); + } + + if (is_hand_raised == participant->get_is_hand_raised()) { + return promise.set_value(Unit()); + } + + if (is_hand_raised) { + if (!participant->is_self) { + return promise.set_error(Status::Error(400, "Can't raise others hand")); + } + } else { + if (!can_manage_group_call(input_group_call_id)) { + return promise.set_error(Status::Error(400, "Have not enough rights in the group call")); + } + } + + participant->have_pending_is_hand_raised = true; + participant->pending_is_hand_raised = is_hand_raised; + participant->pending_is_hand_raised_generation = ++toggle_is_hand_raised_generation_; + if (participant->order != 0) { + send_update_group_call_participant(input_group_call_id, *participant); + } + + auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, dialog_id, + generation = participant->pending_is_hand_raised_generation, + promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } + send_closure(actor_id, &GroupCallManager::on_toggle_group_call_participant_is_hand_raised, input_group_call_id, + dialog_id, generation, std::move(promise)); + }); + td_->create_handler(std::move(query_promise)) + ->send(input_group_call_id, dialog_id, false, 0, true, is_hand_raised); +} + +void GroupCallManager::on_toggle_group_call_participant_is_hand_raised(InputGroupCallId input_group_call_id, + DialogId dialog_id, uint64 generation, + Promise &&promise) { + if (G()->close_flag()) { + return promise.set_value(Unit()); + } + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || !group_call->is_joined) { + return promise.set_value(Unit()); + } + + auto participant = get_group_call_participant(input_group_call_id, dialog_id); + if (participant == nullptr || participant->pending_is_hand_raised_generation != generation) { + return promise.set_value(Unit()); + } + + CHECK(participant->have_pending_is_hand_raised); + participant->have_pending_is_hand_raised = false; + if (participant->get_is_hand_raised() != participant->pending_is_hand_raised) { + LOG(ERROR) << "Failed to change raised hand state for " << dialog_id << " in " << input_group_call_id; + if (participant->order != 0) { + send_update_group_call_participant(input_group_call_id, *participant); + } + } + promise.set_value(Unit()); +} + void GroupCallManager::load_group_call_participants(GroupCallId group_call_id, int32 limit, Promise &&promise) { if (limit <= 0) { return promise.set_error(Status::Error(400, "Parameter limit must be positive")); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 6f794bcfb..b8b722e90 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -85,6 +85,9 @@ class GroupCallManager : public Actor { void set_group_call_participant_volume_level(GroupCallId group_call_id, DialogId dialog_id, int32 volume_level, Promise &&promise); + void toggle_group_call_participant_is_hand_raised(GroupCallId group_call_id, DialogId dialog_id, bool is_hand_raised, + Promise &&promise); + void load_group_call_participants(GroupCallId group_call_id, int32 limit, Promise &&promise); void leave_group_call(GroupCallId group_call_id, Promise &&promise); @@ -117,7 +120,7 @@ class GroupCallManager : public Actor { static constexpr int32 RECENT_SPEAKER_TIMEOUT = 60 * 60; static constexpr int32 CHECK_GROUP_CALL_IS_JOINED_TIMEOUT = 10; - static constexpr size_t MAX_TITLE_LENGTH = 64; // server side limit for group call title length + static constexpr size_t MAX_TITLE_LENGTH = 64; // server side limit for group call title length static constexpr size_t MAX_RECORD_TITLE_LENGTH = 128; // server side limit for group call record title length void tear_down() override; @@ -235,6 +238,9 @@ class GroupCallManager : public Actor { void on_set_group_call_participant_volume_level(InputGroupCallId input_group_call_id, DialogId dialog_id, uint64 generation, Promise &&promise); + void on_toggle_group_call_participant_is_hand_raised(InputGroupCallId input_group_call_id, DialogId dialog_id, + uint64 generation, Promise &&promise); + void on_group_call_left(InputGroupCallId input_group_call_id, int32 audio_source, bool need_rejoin); void on_group_call_left_impl(GroupCall *group_call, bool need_rejoin); @@ -302,9 +308,11 @@ class GroupCallManager : public Actor { uint64 toggle_recording_generation_ = 0; + uint64 toggle_is_muted_generation_ = 0; + uint64 set_volume_level_generation_ = 0; - uint64 toggle_is_muted_generation_ = 0; + uint64 toggle_is_hand_raised_generation_ = 0; MultiTimeout check_group_call_is_joined_timeout_{"CheckGroupCallIsJoinedTimeout"}; MultiTimeout pending_send_speaking_action_timeout_{"PendingSendSpeakingActionTimeout"}; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 1ada45881..14ef50289 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6082,6 +6082,14 @@ void Td::on_request(uint64 id, const td_api::setGroupCallParticipantVolumeLevel request.volume_level_, std::move(promise)); } +void Td::on_request(uint64 id, const td_api::toggleGroupCallParticipantIsHandRaised &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + group_call_manager_->toggle_group_call_participant_is_hand_raised( + GroupCallId(request.group_call_id_), group_call_manager_->get_group_call_participant_id(request.participant_), + request.is_hand_raised_, std::move(promise)); +} + void Td::on_request(uint64 id, const td_api::loadGroupCallParticipants &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 9239a44b5..adcc33dda 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -727,6 +727,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::setGroupCallParticipantVolumeLevel &request); + void on_request(uint64 id, const td_api::toggleGroupCallParticipantIsHandRaised &request); + void on_request(uint64 id, const td_api::loadGroupCallParticipants &request); void on_request(uint64 id, const td_api::leaveGroupCall &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 86cd5c254..1e43371bc 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2737,6 +2737,13 @@ class CliClient final : public Actor { get_args(args, group_call_id, participant_id, volume_level); send_request(td_api::make_object( as_group_call_id(group_call_id), as_message_sender(participant_id), volume_level)); + } else if (op == "tgcpihr") { + string group_call_id; + string participant_id; + bool is_hand_raised; + get_args(args, group_call_id, participant_id, is_hand_raised); + send_request(td_api::make_object( + as_group_call_id(group_call_id), as_message_sender(participant_id), is_hand_raised)); } else if (op == "lgcp") { string group_call_id; string limit; From 42911b9122eeca29ac0b5c30a5ebf970d2d89ea3 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 02:03:52 +0300 Subject: [PATCH 047/281] Add source to process_group_call_after_join_requests. --- td/telegram/GroupCallManager.cpp | 19 ++++++++++--------- td/telegram/GroupCallManager.h | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 2fa3720af..8137b3969 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -2118,7 +2118,7 @@ bool GroupCallManager::on_join_group_call_response(InputGroupCallId input_group_ } pending_join_requests_.erase(it); try_clear_group_call_participants(input_group_call_id); - process_group_call_after_join_requests(input_group_call_id); + process_group_call_after_join_requests(input_group_call_id, "on_join_group_call_response"); return need_update; } @@ -2131,7 +2131,7 @@ void GroupCallManager::finish_join_group_call(InputGroupCallId input_group_call_ it->second->promise.set_error(std::move(error)); pending_join_requests_.erase(it); try_clear_group_call_participants(input_group_call_id); - process_group_call_after_join_requests(input_group_call_id); + process_group_call_after_join_requests(input_group_call_id, "finish_join_group_call"); GroupCall *group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr); @@ -2140,14 +2140,15 @@ void GroupCallManager::finish_join_group_call(InputGroupCallId input_group_call_ } } -void GroupCallManager::process_group_call_after_join_requests(InputGroupCallId input_group_call_id) { +void GroupCallManager::process_group_call_after_join_requests(InputGroupCallId input_group_call_id, + const char *source) { GroupCall *group_call = get_group_call(input_group_call_id); if (group_call == nullptr || !group_call->is_inited) { return; } if (is_group_call_being_joined(input_group_call_id) || group_call->need_rejoin) { - LOG(ERROR) << "Failed to process after-join requests: " << is_group_call_being_joined(input_group_call_id) << " " - << group_call->need_rejoin; + LOG(ERROR) << "Failed to process after-join requests from " << source << ": " + << is_group_call_being_joined(input_group_call_id) << " " << group_call->need_rejoin; return; } if (group_call->after_join.empty()) { @@ -2817,14 +2818,14 @@ void GroupCallManager::leave_group_call(GroupCallId group_call_id, Promise group_call->is_being_left) { if (cancel_join_group_call_request(input_group_call_id) != 0) { try_clear_group_call_participants(input_group_call_id); - process_group_call_after_join_requests(input_group_call_id); + process_group_call_after_join_requests(input_group_call_id, "leave_group_call 1"); return promise.set_value(Unit()); } if (group_call->need_rejoin) { group_call->need_rejoin = false; send_update_group_call(group_call, "leave_group_call"); try_clear_group_call_participants(input_group_call_id); - process_group_call_after_join_requests(input_group_call_id); + process_group_call_after_join_requests(input_group_call_id, "leave_group_call 2"); return promise.set_value(Unit()); } return promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); @@ -2837,7 +2838,7 @@ void GroupCallManager::leave_group_call(GroupCallId group_call_id, Promise group_call->need_rejoin = false; send_update_group_call(group_call, "leave_group_call"); - process_group_call_after_join_requests(input_group_call_id); + process_group_call_after_join_requests(input_group_call_id, "leave_group_call 3"); auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, audio_source, promise = std::move(promise)](Result &&result) mutable { @@ -2879,7 +2880,7 @@ void GroupCallManager::on_group_call_left_impl(GroupCall *group_call, bool need_ check_group_call_is_joined_timeout_.cancel_timeout(group_call->group_call_id.get()); auto input_group_call_id = get_input_group_call_id(group_call->group_call_id).ok(); try_clear_group_call_participants(input_group_call_id); - process_group_call_after_join_requests(input_group_call_id); + process_group_call_after_join_requests(input_group_call_id, "on_group_call_left_impl"); } void GroupCallManager::discard_group_call(GroupCallId group_call_id, Promise &&promise) { diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index b8b722e90..5019daa31 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -208,7 +208,7 @@ class GroupCallManager : public Actor { void finish_join_group_call(InputGroupCallId input_group_call_id, uint64 generation, Status error); - void process_group_call_after_join_requests(InputGroupCallId input_group_call_id); + void process_group_call_after_join_requests(InputGroupCallId input_group_call_id, const char *source); GroupCallParticipants *add_group_call_participants(InputGroupCallId input_group_call_id); From b9f7668b07a6462834c363372f3d6154873232f8 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 02:15:01 +0300 Subject: [PATCH 048/281] Allow to always get self group call participant by user_id. --- td/telegram/GroupCallManager.cpp | 36 ++++++++++++++++++++------------ td/telegram/GroupCallManager.h | 4 ++-- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 8137b3969..eec92a145 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1276,10 +1276,18 @@ GroupCallParticipant *GroupCallManager::get_group_call_participant(InputGroupCal } GroupCallParticipant *GroupCallManager::get_group_call_participant(GroupCallParticipants *group_call_participants, - DialogId dialog_id) { - for (auto &group_call_participant : group_call_participants->participants) { - if (group_call_participant.dialog_id == dialog_id) { - return &group_call_participant; + DialogId dialog_id) const { + if (dialog_id == DialogId(td_->contacts_manager_->get_my_id())) { + for (auto &group_call_participant : group_call_participants->participants) { + if (group_call_participant.is_self) { + return &group_call_participant; + } + } + } else { + for (auto &group_call_participant : group_call_participants->participants) { + if (group_call_participant.dialog_id == dialog_id) { + return &group_call_participant; + } } } return nullptr; @@ -1395,15 +1403,17 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup auto version = it->first; auto &participants = it->second; if (version <= group_call->version) { - auto my_participant = - get_group_call_participant(participants_it->second.get(), DialogId(td_->contacts_manager_->get_my_id())); for (auto &participant : participants) { on_participant_speaking_in_group_call(input_group_call_id, participant); - if (participant.is_self && (my_participant == nullptr || my_participant->is_fake || - my_participant->joined_date < participant.joined_date || - (my_participant->joined_date <= participant.joined_date && - my_participant->audio_source != participant.audio_source))) { - process_group_call_participant(input_group_call_id, std::move(participant)); + if (participant.is_self) { + auto my_participant = + get_group_call_participant(participants_it->second.get(), DialogId(td_->contacts_manager_->get_my_id())); + if (my_participant == nullptr || my_participant->is_fake || + my_participant->joined_date < participant.joined_date || + (my_participant->joined_date <= participant.joined_date && + my_participant->audio_source != participant.audio_source)) { + process_group_call_participant(input_group_call_id, std::move(participant)); + } } } LOG(INFO) << "Ignore already applied updateGroupCallParticipants with version " << version << " in " @@ -1682,7 +1692,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou auto *participants = add_group_call_participants(input_group_call_id); for (size_t i = 0; i < participants->participants.size(); i++) { auto &old_participant = participants->participants[i]; - if (old_participant.dialog_id == participant.dialog_id) { + if (old_participant.dialog_id == participant.dialog_id || (old_participant.is_self && participant.is_self)) { if (participant.joined_date == 0) { LOG(INFO) << "Remove " << old_participant; if (old_participant.order != 0) { @@ -3180,7 +3190,7 @@ void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, if (!td_->messages_manager_->have_dialog_info_force(dialog_id) || (!recursive && need_group_call_participants(input_group_call_id, group_call) && get_group_call_participant(input_group_call_id, dialog_id) == nullptr)) { - if (recursive || dialog_id.get_type() != DialogType::User) { + if (recursive) { LOG(ERROR) << "Failed to find speaking " << dialog_id << " from " << input_group_call_id; } else { auto query_promise = diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 5019daa31..39098924c 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -214,8 +214,8 @@ class GroupCallManager : public Actor { GroupCallParticipant *get_group_call_participant(InputGroupCallId input_group_call_id, DialogId dialog_id); - static GroupCallParticipant *get_group_call_participant(GroupCallParticipants *group_call_participants, - DialogId dialog_id); + GroupCallParticipant *get_group_call_participant(GroupCallParticipants *group_call_participants, + DialogId dialog_id) const; void send_edit_group_call_title_query(InputGroupCallId input_group_call_id, const string &title); From 0339921102e7ec26c3b1581324bf30187bbfc7de Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 03:32:14 +0300 Subject: [PATCH 049/281] Improve some spelling. --- example/cpp/td_example.cpp | 6 ++-- td/telegram/AnimationsManager.cpp | 2 +- td/telegram/AudiosManager.cpp | 2 +- td/telegram/AuthManager.cpp | 4 +-- td/telegram/ContactsManager.cpp | 6 ++-- td/telegram/DocumentsManager.cpp | 4 +-- td/telegram/Game.cpp | 2 +- td/telegram/InlineQueriesManager.cpp | 4 +-- td/telegram/MessagesManager.cpp | 44 ++++++++++++----------- td/telegram/MessagesManager.h | 2 +- td/telegram/NotificationManager.cpp | 12 ++++--- td/telegram/Payments.cpp | 4 +-- td/telegram/Photo.cpp | 8 ++--- td/telegram/ReplyMarkup.cpp | 2 +- td/telegram/SecretChatActor.cpp | 10 +++--- td/telegram/StickersManager.cpp | 4 +-- td/telegram/Td.cpp | 2 +- td/telegram/UpdatesManager.cpp | 2 +- td/telegram/Venue.cpp | 2 +- td/telegram/VideoNotesManager.cpp | 2 +- td/telegram/VideosManager.cpp | 2 +- td/telegram/VoiceNotesManager.cpp | 2 +- td/telegram/WebPagesManager.cpp | 4 +-- td/telegram/cli.cpp | 2 +- td/telegram/files/FileDb.cpp | 4 +-- td/telegram/files/FileGenerateManager.cpp | 2 +- td/telegram/files/FileLocation.h | 4 +-- td/telegram/files/FileManager.cpp | 6 ++-- 28 files changed, 78 insertions(+), 72 deletions(-) diff --git a/example/cpp/td_example.cpp b/example/cpp/td_example.cpp index 398518df6..9e998f835 100644 --- a/example/cpp/td_example.cpp +++ b/example/cpp/td_example.cpp @@ -66,8 +66,8 @@ class TdExample { } else if (!are_authorized_) { process_response(client_manager_->receive(10)); } else { - std::cout << "Enter action [q] quit [u] check for updates and request results [c] show chats [m ] " - "send message [me] show self [l] logout: " + std::cout << "Enter action [q] quit [u] check for updates and request results [c] show chats [m " + "] send message [me] show self [l] logout: " << std::endl; std::string line; std::getline(std::cin, line); @@ -123,7 +123,7 @@ class TdExample { } auto chats = td::move_tl_object_as(object); for (auto chat_id : chats->chat_ids_) { - std::cout << "[id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl; + std::cout << "[chat_id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl; } }); } diff --git a/td/telegram/AnimationsManager.cpp b/td/telegram/AnimationsManager.cpp index b2d20b24d..69c024574 100644 --- a/td/telegram/AnimationsManager.cpp +++ b/td/telegram/AnimationsManager.cpp @@ -284,7 +284,7 @@ FileId AnimationsManager::dup_animation(FileId new_id, FileId old_id) { bool AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_delete_old) { if (!old_id.is_valid()) { - LOG(ERROR) << "Old file id is invalid"; + LOG(ERROR) << "Old file identifier is invalid"; return true; } diff --git a/td/telegram/AudiosManager.cpp b/td/telegram/AudiosManager.cpp index 7ea0f811b..dd71aee69 100644 --- a/td/telegram/AudiosManager.cpp +++ b/td/telegram/AudiosManager.cpp @@ -111,7 +111,7 @@ FileId AudiosManager::dup_audio(FileId new_id, FileId old_id) { bool AudiosManager::merge_audios(FileId new_id, FileId old_id, bool can_delete_old) { if (!old_id.is_valid()) { - LOG(ERROR) << "Old file id is invalid"; + LOG(ERROR) << "Old file identifier is invalid"; return true; } diff --git a/td/telegram/AuthManager.cpp b/td/telegram/AuthManager.cpp index 301105f15..1da0117ed 100644 --- a/td/telegram/AuthManager.cpp +++ b/td/telegram/AuthManager.cpp @@ -308,7 +308,7 @@ void AuthManager::check_password(uint64 query_id, string password) { return on_query_error(query_id, Status::Error(8, "Call to checkAuthenticationPassword unexpected")); } - LOG(INFO) << "Have SRP id " << wait_password_state_.srp_id_; + LOG(INFO) << "Have SRP ID " << wait_password_state_.srp_id_; on_new_query(query_id); password_ = std::move(password); start_net_query(NetQueryType::GetPassword, @@ -569,7 +569,7 @@ void AuthManager::on_get_password_result(NetQueryPtr &result) { } if (state_ == State::WaitPassword) { - LOG(INFO) << "Have SRP id " << wait_password_state_.srp_id_; + LOG(INFO) << "Have SRP ID " << wait_password_state_.srp_id_; auto hash = PasswordManager::get_input_check_password(password_, wait_password_state_.current_client_salt_, wait_password_state_.current_server_salt_, wait_password_state_.srp_g_, wait_password_state_.srp_p_, diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 06abf3f95..1fd71da64 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -3467,7 +3467,7 @@ UserId ContactsManager::load_my_id() { return my_id; } - LOG(ERROR) << "Wrong my id = \"" << id_string << "\" stored in database"; + LOG(ERROR) << "Wrong my ID = \"" << id_string << "\" stored in database"; } return UserId(); } @@ -4891,7 +4891,7 @@ FolderId ContactsManager::get_secret_chat_initial_folder_id(SecretChatId secret_ } UserId ContactsManager::get_my_id() const { - LOG_IF(ERROR, !my_id_.is_valid()) << "Wrong or unknown my id returned"; + LOG_IF(ERROR, !my_id_.is_valid()) << "Wrong or unknown my ID returned"; return my_id_; } @@ -4901,7 +4901,7 @@ void ContactsManager::set_my_id(UserId my_id) { LOG(ERROR) << "Already know that me is " << my_old_id << " but received userSelf with " << my_id; } if (!my_id.is_valid()) { - LOG(ERROR) << "Receive invalid my id " << my_id; + LOG(ERROR) << "Receive invalid my ID " << my_id; return; } if (my_old_id != my_id) { diff --git a/td/telegram/DocumentsManager.cpp b/td/telegram/DocumentsManager.cpp index 028b77ae4..e3bdd244d 100644 --- a/td/telegram/DocumentsManager.cpp +++ b/td/telegram/DocumentsManager.cpp @@ -364,7 +364,7 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo // fix_animated_sticker_type(); } - LOG(DEBUG) << "Receive document with id = " << id << " of type " << document_type; + LOG(DEBUG) << "Receive document with ID = " << id << " of type " << document_type; if (!is_web && !DcId::is_valid(dc_id)) { LOG(ERROR) << "Wrong dc_id = " << dc_id; return {}; @@ -646,7 +646,7 @@ FileId DocumentsManager::dup_document(FileId new_id, FileId old_id) { bool DocumentsManager::merge_documents(FileId new_id, FileId old_id, bool can_delete_old) { if (!old_id.is_valid()) { - LOG(ERROR) << "Old file id is invalid"; + LOG(ERROR) << "Old file identifier is invalid"; return true; } diff --git a/td/telegram/Game.cpp b/td/telegram/Game.cpp index f7b90b5f9..9d68e8685 100644 --- a/td/telegram/Game.cpp +++ b/td/telegram/Game.cpp @@ -120,7 +120,7 @@ bool operator!=(const Game &lhs, const Game &rhs) { } StringBuilder &operator<<(StringBuilder &string_builder, const Game &game) { - return string_builder << "Game[id = " << game.id_ << ", access_hash = " << game.access_hash_ + return string_builder << "Game[ID = " << game.id_ << ", access_hash = " << game.access_hash_ << ", bot = " << game.bot_user_id_ << ", short_name = " << game.short_name_ << ", title = " << game.title_ << ", description = " << game.description_ << ", photo = " << game.photo_ << ", animation_file_id = " << game.animation_file_id_ << "]"; diff --git a/td/telegram/InlineQueriesManager.cpp b/td/telegram/InlineQueriesManager.cpp index ddc6dab75..759f84ce0 100644 --- a/td/telegram/InlineQueriesManager.cpp +++ b/td/telegram/InlineQueriesManager.cpp @@ -206,7 +206,7 @@ tl_object_ptr InlineQueriesManager::get_i if (!DcId::is_valid(result->dc_id_)) { return nullptr; } - LOG(INFO) << "Have inline message id: " << to_string(result); + LOG(INFO) << "Have inline message identifier: " << to_string(result); return result; } @@ -215,7 +215,7 @@ string InlineQueriesManager::get_inline_message_id( if (input_bot_inline_message_id == nullptr) { return string(); } - LOG(INFO) << "Got inline message id: " << to_string(input_bot_inline_message_id); + LOG(INFO) << "Got inline message identifier: " << to_string(input_bot_inline_message_id); return base64url_encode(serialize(*input_bot_inline_message_id)); } diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index bf1e6b2c7..96459ef94 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -12606,7 +12606,7 @@ void MessagesManager::init() { } else if (begins_with(log_string, " local message ")) { log_string.remove_prefix(15); } else { - LOG(ERROR) << "Message id expected, found " << log_string; + LOG(ERROR) << "Message identifier expected, found " << log_string; continue; } @@ -13512,7 +13512,7 @@ std::pair> MessagesManager::creat message->contains_mention || dialog_type == DialogType::User); if (content_type == MessageContentType::ExpiredPhoto || content_type == MessageContentType::ExpiredVideo) { - CHECK(message->ttl == 0); // ttl is ignored/set to 0 if the message has already been expired + CHECK(message->ttl == 0); // TTL is ignored/set to 0 if the message has already been expired if (message->reply_markup != nullptr) { if (message->reply_markup->type != ReplyMarkup::Type::InlineKeyboard) { message->had_reply_markup = true; @@ -13527,7 +13527,7 @@ std::pair> MessagesManager::creat if (message_info.media_album_id != 0) { if (!is_allowed_media_group_content(content_type)) { - LOG(ERROR) << "Receive media group id " << message_info.media_album_id << " in " << message_id << " from " + LOG(ERROR) << "Receive media group identifier " << message_info.media_album_id << " in " << message_id << " from " << dialog_id << " with content " << oneline(to_string( get_message_content_object(message->content.get(), td_, message->date, is_content_secret))); @@ -13616,14 +13616,14 @@ FullMessageId MessagesManager::on_get_message(MessageInfo &&message_info, bool f if (message_id <= d->last_new_message_id) { if (get_message_force(d, message_id, "receive missed unsent message not from update") != nullptr) { LOG(ERROR) << "New " << old_message_id << "/" << message_id << " in " << dialog_id << " from " << source - << " has id less than last_new_message_id = " << d->last_new_message_id; + << " has identifier less than last_new_message_id = " << d->last_new_message_id; return FullMessageId(); } // if there is no message yet, then it is likely was missed because of a server bug and is being repaired via // get_message_from_server from after_get_difference // TODO move to INFO LOG(ERROR) << "Receive " << old_message_id << "/" << message_id << " in " << dialog_id << " from " << source - << " with id less than last_new_message_id = " << d->last_new_message_id + << " with identifier less than last_new_message_id = " << d->last_new_message_id << " and trying to add it anyway"; } else { LOG(ERROR) << "Ignore " << old_message_id << "/" << message_id << " received not through update from " << source @@ -14880,8 +14880,8 @@ void MessagesManager::fix_dialog_last_notification_id(Dialog *d, bool from_menti CHECK(!message_id.is_scheduled()); MessagesConstIterator it(d, message_id); auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group; - VLOG(notifications) << "Trying to fix last notification id in " << group_info.group_id << " from " << d->dialog_id - << " from " << message_id << "/" << group_info.last_notification_id; + VLOG(notifications) << "Trying to fix last notification identifier in " << group_info.group_id << " from " + << d->dialog_id << " from " << message_id << "/" << group_info.last_notification_id; if (*it != nullptr && ((*it)->message_id == message_id || (*it)->have_next)) { while (*it != nullptr) { const Message *m = *it; @@ -25849,7 +25849,8 @@ unique_ptr MessagesManager::get_message_for if (forward_header->from_id_ != nullptr) { sender_dialog_id = DialogId(forward_header->from_id_); if (!sender_dialog_id.is_valid()) { - LOG(ERROR) << "Receive invalid sender id in message forward header: " << oneline(to_string(forward_header)); + LOG(ERROR) << "Receive invalid sender identifier in message forward header: " + << oneline(to_string(forward_header)); sender_dialog_id = DialogId(); } } @@ -27247,7 +27248,7 @@ MessagesManager::MessageNotificationGroup MessagesManager::get_message_notificat if (last_notification_date != group_info.last_notification_date || last_notification_id != group_info.last_notification_id) { LOG(ERROR) << "Fix last notification date in " << d->dialog_id << " from " << group_info.last_notification_date - << " to " << last_notification_date << " and last notification id from " + << " to " << last_notification_date << " and last notification identifier from " << group_info.last_notification_id << " to " << last_notification_id; set_dialog_last_notification(d->dialog_id, group_info, last_notification_date, last_notification_id, "get_message_notification_group_force"); @@ -27354,7 +27355,7 @@ vector MessagesManager::get_message_notifications_from_database_fo auto notification_id = m->notification_id.is_valid() ? m->notification_id : m->removed_notification_id; if (!notification_id.is_valid()) { - VLOG(ERROR) << "Can't find notification ID for " << m->message_id << " in " << d->dialog_id; + VLOG(ERROR) << "Can't find notification identifier for " << m->message_id << " in " << d->dialog_id; continue; } CHECK(m->message_id.is_valid()); @@ -27362,7 +27363,7 @@ vector MessagesManager::get_message_notifications_from_database_fo bool is_correct = true; if (notification_id.get() >= from_notification_id.get()) { // possible if two messages has the same notification_id - LOG(ERROR) << "Have nonmonotoic notification ids: " << d->dialog_id << " " << m->message_id << " " + LOG(ERROR) << "Have nonmonotonic notification identifiers: " << d->dialog_id << " " << m->message_id << " " << notification_id << " " << from_message_id << " " << from_notification_id; is_correct = false; } else { @@ -27370,8 +27371,8 @@ vector MessagesManager::get_message_notifications_from_database_fo is_found = true; } if (m->message_id >= from_message_id) { - LOG(ERROR) << "Have nonmonotoic message ids: " << d->dialog_id << " " << m->message_id << " " << notification_id - << " " << from_message_id << " " << from_notification_id; + LOG(ERROR) << "Have nonmonotonic message identifiers: " << d->dialog_id << " " << m->message_id << " " + << notification_id << " " << from_message_id << " " << from_notification_id; is_correct = false; } else { from_message_id = m->message_id; @@ -27610,7 +27611,7 @@ void MessagesManager::on_get_message_notifications_from_database(DialogId dialog auto notification_id = m->notification_id.is_valid() ? m->notification_id : m->removed_notification_id; if (!notification_id.is_valid()) { - VLOG(ERROR) << "Can't find notification ID for " << m->message_id << " in " << d->dialog_id; + VLOG(ERROR) << "Can't find notification identifier for " << m->message_id << " in " << d->dialog_id; continue; } CHECK(m->message_id.is_valid()); @@ -31958,7 +31959,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq << d->last_new_message_id << " to " << message_id; } LOG(ERROR) << "New " << message_id << " in " << dialog_id << " from " << source - << " has id less than last_new_message_id = " << d->last_new_message_id; + << " has identifier less than last_new_message_id = " << d->last_new_message_id; dump_debug_message_op(d); } } @@ -32404,7 +32405,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq set_dialog_last_read_inbox_message_id(d, MessageId::min(), server_unread_count, local_unread_count, false, source); } else { - // if non-scheduled outgoing message has id one greater than last_read_inbox_message_id, + // if non-scheduled outgoing message has identifier one greater than last_read_inbox_message_id, // then definitely there are no unread incoming messages before it if (message_id.is_server() && d->last_read_inbox_message_id.is_valid() && d->last_read_inbox_message_id.is_server() && @@ -33263,9 +33264,10 @@ bool MessagesManager::update_message(Dialog *d, Message *old_message, unique_ptr CHECK(!is_scheduled); if (old_message->notification_id.is_valid()) { if (new_message->notification_id.is_valid()) { - LOG(ERROR) << "Notification id for " << message_id << " in " << dialog_id << " has tried to change from " - << old_message->notification_id << " to " << new_message->notification_id - << ", message content type is " << old_content_type << '/' << new_content_type; + LOG(ERROR) << "Notification identifier for " << message_id << " in " << dialog_id + << " has tried to change from " << old_message->notification_id << " to " + << new_message->notification_id << ", message content type is " << old_content_type << '/' + << new_content_type; } } else { CHECK(new_message->notification_id.is_valid()); @@ -33945,11 +33947,11 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab } if (being_added_dialog_id_ != dialog_id && !d->is_folder_id_inited && !td_->auth_manager_->is_bot() && order != DEFAULT_ORDER) { - // asynchronously get dialog folder id from the server + // asynchronously get dialog folder identifier from the server get_dialog_info_full(dialog_id, Auto()); } if (!d->is_message_ttl_setting_inited && !td_->auth_manager_->is_bot() && order != DEFAULT_ORDER) { - // asynchronously get dialog message ttl setting from the server + // asynchronously get dialog message TTL setting from the server get_dialog_info_full(dialog_id, Auto()); } if (!d->know_action_bar && !td_->auth_manager_->is_bot() && dialog_type != DialogType::SecretChat && diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index c389151c7..75c74125a 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1091,7 +1091,7 @@ class MessagesManager : public Actor { int32 ttl_period = 0; // counted from message send date int32 ttl = 0; // counted from message content view date - double ttl_expires_at = 0; // only for ttl + double ttl_expires_at = 0; // only for TTL int64 media_album_id = 0; diff --git a/td/telegram/NotificationManager.cpp b/td/telegram/NotificationManager.cpp index f61734e2b..f2393b91f 100644 --- a/td/telegram/NotificationManager.cpp +++ b/td/telegram/NotificationManager.cpp @@ -249,7 +249,8 @@ void NotificationManager::init() { VLOG(notifications) << "Load call_notification_group_ids = " << call_notification_group_ids; for (auto &group_id : call_notification_group_ids) { if (group_id.get() > current_notification_group_id_.get()) { - LOG(ERROR) << "Fix current notification group id from " << current_notification_group_id_ << " to " << group_id; + LOG(ERROR) << "Fix current notification group identifier from " << current_notification_group_id_ << " to " + << group_id; current_notification_group_id_ = group_id; G()->td_db()->get_binlog_pmc()->set("notification_group_id_current", to_string(current_notification_group_id_.get())); @@ -413,14 +414,15 @@ NotificationManager::NotificationGroups::iterator NotificationManager::get_group group_key.last_notification_date = notification.date; } if (notification.notification_id.get() > current_notification_id_.get()) { - LOG(ERROR) << "Fix current notification id from " << current_notification_id_ << " to " + LOG(ERROR) << "Fix current notification identifier from " << current_notification_id_ << " to " << notification.notification_id; current_notification_id_ = notification.notification_id; G()->td_db()->get_binlog_pmc()->set("notification_id_current", to_string(current_notification_id_.get())); } } if (group_id.get() > current_notification_group_id_.get()) { - LOG(ERROR) << "Fix current notification group id from " << current_notification_group_id_ << " to " << group_id; + LOG(ERROR) << "Fix current notification group identifier from " << current_notification_group_id_ << " to " + << group_id; current_notification_group_id_ = group_id; G()->td_db()->get_binlog_pmc()->set("notification_group_id_current", to_string(current_notification_group_id_.get())); @@ -735,7 +737,7 @@ NotificationId NotificationManager::get_next_notification_id() { return NotificationId(); } if (current_notification_id_.get() == std::numeric_limits::max()) { - LOG(ERROR) << "Notification id overflowed"; + LOG(ERROR) << "Notification identifier overflowed"; return NotificationId(); } @@ -749,7 +751,7 @@ NotificationGroupId NotificationManager::get_next_notification_group_id() { return NotificationGroupId(); } if (current_notification_group_id_.get() == std::numeric_limits::max()) { - LOG(ERROR) << "Notification group id overflowed"; + LOG(ERROR) << "Notification group identifier overflowed"; return NotificationGroupId(); } diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 5896d1c5b..3af931db2 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -746,7 +746,7 @@ void answer_shipping_query(int64 shipping_query_id, vectorid_)) { - return promise.set_error(Status::Error(400, "Shipping option id must be encoded in UTF-8")); + return promise.set_error(Status::Error(400, "Shipping option identifier must be encoded in UTF-8")); } if (!clean_input_string(option->title_)) { return promise.set_error(Status::Error(400, "Shipping option title must be encoded in UTF-8")); @@ -836,7 +836,7 @@ void send_payment_form(ServerMessageId server_message_id, const string &order_in auto credentials_saved = static_cast(credentials.get()); auto credentials_id = credentials_saved->saved_credentials_id_; if (!clean_input_string(credentials_id)) { - return promise.set_error(Status::Error(400, "Credentials id must be encoded in UTF-8")); + return promise.set_error(Status::Error(400, "Credentials identifier must be encoded in UTF-8")); } auto temp_password_state = G()->td().get_actor_unsafe()->password_manager_->get_actor_unsafe()->get_temp_password_state_sync(); diff --git a/td/telegram/Photo.cpp b/td/telegram/Photo.cpp index 4c48ef839..2fa58f8bf 100644 --- a/td/telegram/Photo.cpp +++ b/td/telegram/Photo.cpp @@ -217,7 +217,7 @@ bool operator!=(const ProfilePhoto &lhs, const ProfilePhoto &rhs) { } StringBuilder &operator<<(StringBuilder &string_builder, const ProfilePhoto &profile_photo) { - return string_builder << ""; } @@ -709,7 +709,7 @@ Photo get_photo(FileManager *file_manager, tl_object_ptr && res.has_stickers = (photo->flags_ & telegram_api::photo::HAS_STICKERS_MASK) != 0; if (res.is_empty()) { - LOG(ERROR) << "Receive photo with id " << res.id.get(); + LOG(ERROR) << "Receive photo with identifier " << res.id.get(); res.id = -3; } @@ -925,11 +925,11 @@ bool operator!=(const Photo &lhs, const Photo &rhs) { } StringBuilder &operator<<(StringBuilder &string_builder, const Photo &photo) { - string_builder << "[id = " << photo.id.get() << ", photos = " << format::as_array(photo.photos); + string_builder << "[ID = " << photo.id.get() << ", photos = " << format::as_array(photo.photos); if (!photo.animations.empty()) { string_builder << ", animations = " << format::as_array(photo.animations); } - return string_builder << "]"; + return string_builder << ']'; } static tl_object_ptr copy_location( diff --git a/td/telegram/ReplyMarkup.cpp b/td/telegram/ReplyMarkup.cpp index 3216c6139..6674432e6 100644 --- a/td/telegram/ReplyMarkup.cpp +++ b/td/telegram/ReplyMarkup.cpp @@ -82,7 +82,7 @@ static StringBuilder &operator<<(StringBuilder &string_builder, const InlineKeyb string_builder << "Buy"; break; case InlineKeyboardButton::Type::UrlAuth: - string_builder << "UrlAuth, id = " << keyboard_button.id; + string_builder << "UrlAuth, ID = " << keyboard_button.id; break; case InlineKeyboardButton::Type::CallbackWithPassword: string_builder << "CallbackWithPassword"; diff --git a/td/telegram/SecretChatActor.cpp b/td/telegram/SecretChatActor.cpp index cf290178c..8a7ee44a6 100644 --- a/td/telegram/SecretChatActor.cpp +++ b/td/telegram/SecretChatActor.cpp @@ -646,7 +646,7 @@ void SecretChatActor::run_fill_gaps() { void SecretChatActor::run_pfs() { while (true) { - LOG(INFO) << "Run pfs loop: " << pfs_state_; + LOG(INFO) << "Run PFS loop: " << pfs_state_; if (pfs_state_.state == PfsState::Empty && (pfs_state_.last_message_id + 100 < seq_no_state_.message_id || pfs_state_.last_timestamp + 60 * 60 * 24 * 7 < Time::now()) && @@ -1078,7 +1078,7 @@ void SecretChatActor::do_outbound_message_impl(unique_ptrcrc = crc64(binlog_event->encrypted_message.as_slice()); LOG(INFO) << "Do outbound message: " << *binlog_event << tag("crc", binlog_event->crc); auto &state_id_ref = random_id_to_outbound_message_state_token_[binlog_event->random_id]; - LOG_CHECK(state_id_ref == 0) << "Random id collision"; + LOG_CHECK(state_id_ref == 0) << "Random ID collision"; state_id_ref = outbound_message_states_.create(); const uint64 state_id = state_id_ref; auto *state = outbound_message_states_.get(state_id); @@ -2283,9 +2283,9 @@ Status SecretChatActor::on_inbound_action(secret_api::DecryptedMessageAction &ac // Also, if SeqNoState with message_id greater than current message_id is not saved, then corresponding action will be // replayed. // - // This works only for ttl, not for pfs. Same ttl action may be processed twice. + // This works only for TTL, not for PFS. Same TTL action may be processed twice. if (message_id < seq_no_state_.message_id) { - LOG(INFO) << "Drop old inbound DecryptedMessageAction (non-pfs action): " << to_string(action); + LOG(INFO) << "Drop old inbound DecryptedMessageAction (non-PFS action): " << to_string(action); return Status::OK(); } pfs_state_.message_id = message_id; // replay protection @@ -2305,7 +2305,7 @@ void SecretChatActor::on_outbound_action(secret_api::DecryptedMessageAction &act // see comment in on_inbound_action if (message_id < seq_no_state_.message_id) { - LOG(INFO) << "Drop old outbound DecryptedMessageAction (non-pfs action): " << to_string(action); + LOG(INFO) << "Drop old outbound DecryptedMessageAction (non-PFS action): " << to_string(action); return; } pfs_state_.message_id = message_id; // replay protection diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index f2455084b..05151d843 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -2079,7 +2079,7 @@ FileId StickersManager::dup_sticker(FileId new_id, FileId old_id) { bool StickersManager::merge_stickers(FileId new_id, FileId old_id, bool can_delete_old) { if (!old_id.is_valid()) { - LOG(ERROR) << "Old file id is invalid"; + LOG(ERROR) << "Old file identifier is invalid"; return true; } @@ -2674,7 +2674,7 @@ StickerSetId StickersManager::on_get_messages_sticker_set(StickerSetId sticker_s for (int64 document_id : pack->documents_) { auto it = document_id_to_sticker_id.find(document_id); if (it == document_id_to_sticker_id.end()) { - LOG(ERROR) << "Can't find document with id " << document_id << " in " << set_id << "/" << s->short_name + LOG(ERROR) << "Can't find document with ID " << document_id << " in " << set_id << "/" << s->short_name << " from " << source; continue; } diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 14ef50289..3baa18099 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -3349,7 +3349,7 @@ DbKey Td::as_db_key(string key) { void Td::request(uint64 id, tl_object_ptr function) { if (id == 0) { - LOG(ERROR) << "Ignore request with id == 0: " << to_string(function); + LOG(ERROR) << "Ignore request with ID == 0: " << to_string(function); return; } diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index e703b8d77..0eeaca35b 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -1088,7 +1088,7 @@ vector UpdatesManager::get_chat_dialog_ids(const telegram_api::Updates continue; } - LOG(ERROR) << "Can't find id of " << oneline(to_string(chat)); + LOG(ERROR) << "Can't find identifier of " << oneline(to_string(chat)); } return dialog_ids; } diff --git a/td/telegram/Venue.cpp b/td/telegram/Venue.cpp index 68151dc45..1eee9828f 100644 --- a/td/telegram/Venue.cpp +++ b/td/telegram/Venue.cpp @@ -84,7 +84,7 @@ bool operator!=(const Venue &lhs, const Venue &rhs) { StringBuilder &operator<<(StringBuilder &string_builder, const Venue &venue) { return string_builder << "Venue[location = " << venue.location_ << ", title = " << venue.title_ << ", address = " << venue.address_ << ", provider = " << venue.provider_ - << ", id = " << venue.id_ << ", type = " << venue.type_ << "]"; + << ", ID = " << venue.id_ << ", type = " << venue.type_ << "]"; } Result process_input_message_venue(tl_object_ptr &&input_message_content) { diff --git a/td/telegram/VideoNotesManager.cpp b/td/telegram/VideoNotesManager.cpp index a1221df31..84a20b3c7 100644 --- a/td/telegram/VideoNotesManager.cpp +++ b/td/telegram/VideoNotesManager.cpp @@ -112,7 +112,7 @@ FileId VideoNotesManager::dup_video_note(FileId new_id, FileId old_id) { bool VideoNotesManager::merge_video_notes(FileId new_id, FileId old_id, bool can_delete_old) { if (!old_id.is_valid()) { - LOG(ERROR) << "Old file id is invalid"; + LOG(ERROR) << "Old file identifier is invalid"; return true; } diff --git a/td/telegram/VideosManager.cpp b/td/telegram/VideosManager.cpp index 86103cb6f..d36fd0f54 100644 --- a/td/telegram/VideosManager.cpp +++ b/td/telegram/VideosManager.cpp @@ -152,7 +152,7 @@ FileId VideosManager::dup_video(FileId new_id, FileId old_id) { bool VideosManager::merge_videos(FileId new_id, FileId old_id, bool can_delete_old) { if (!old_id.is_valid()) { - LOG(ERROR) << "Old file id is invalid"; + LOG(ERROR) << "Old file identifier is invalid"; return true; } diff --git a/td/telegram/VoiceNotesManager.cpp b/td/telegram/VoiceNotesManager.cpp index 6374de612..0600259d1 100644 --- a/td/telegram/VoiceNotesManager.cpp +++ b/td/telegram/VoiceNotesManager.cpp @@ -88,7 +88,7 @@ FileId VoiceNotesManager::dup_voice_note(FileId new_id, FileId old_id) { bool VoiceNotesManager::merge_voice_notes(FileId new_id, FileId old_id, bool can_delete_old) { if (!old_id.is_valid()) { - LOG(ERROR) << "Old file id is invalid"; + LOG(ERROR) << "Old file identifier is invalid"; return true; } diff --git a/td/telegram/WebPagesManager.cpp b/td/telegram/WebPagesManager.cpp index 9c442eb15..bd3fab7ca 100644 --- a/td/telegram/WebPagesManager.cpp +++ b/td/telegram/WebPagesManager.cpp @@ -1037,7 +1037,7 @@ WebPageId WebPagesManager::get_web_page_by_url(const string &url) const { return WebPageId(); } - LOG(INFO) << "Get web page id for the url \"" << url << '"'; + LOG(INFO) << "Get web page identifier for the url \"" << url << '"'; auto it = url_to_web_page_id_.find(url); if (it != url_to_web_page_id_.end()) { @@ -1048,7 +1048,7 @@ WebPageId WebPagesManager::get_web_page_by_url(const string &url) const { } WebPageId WebPagesManager::get_web_page_by_url(const string &url, Promise &&promise) { - LOG(INFO) << "Trying to get web page id for the url \"" << url << '"'; + LOG(INFO) << "Trying to get web page identifier for the url \"" << url << '"'; auto it = url_to_web_page_id_.find(url); if (it != url_to_web_page_id_.end()) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 1e43371bc..3a355b1f3 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -295,7 +295,7 @@ class CliClient final : public Actor { void update_option(const td_api::updateOption &option) { if (option.name_ == "my_id" && option.value_->get_id() == td_api::optionValueInteger::ID) { my_id_ = static_cast(static_cast(option.value_.get())->value_); - LOG(INFO) << "Set my id to " << my_id_; + LOG(INFO) << "Set my user identifier to " << my_id_; } } diff --git a/td/telegram/files/FileDb.cpp b/td/telegram/files/FileDb.cpp index 5dd966266..bfa2a6f9f 100644 --- a/td/telegram/files/FileDb.cpp +++ b/td/telegram/files/FileDb.cpp @@ -275,7 +275,7 @@ class FileDb : public FileDbInterface { if (ids.size() > 1) { send_closure(file_db_actor_id, &FileDbActor::optimize_refs, std::move(ids), id); } - //LOG(DEBUG) << "By id " << id.get() << " found data " << format::as_hex_dump<4>(Slice(data_str)); + //LOG(DEBUG) << "By ID " << id.get() << " found data " << format::as_hex_dump<4>(Slice(data_str)); //LOG(INFO) << attempt_count; log_event::WithVersion parser(data_str); @@ -292,7 +292,7 @@ class FileDb : public FileDbInterface { static Result get_id(SqliteKeyValue &pmc, const string &key) TD_WARN_UNUSED_RESULT { auto id_str = pmc.get(key); - //LOG(DEBUG) << "Found id " << id_str << " by key " << format::as_hex_dump<4>(Slice(key)); + //LOG(DEBUG) << "Found ID " << id_str << " by key " << format::as_hex_dump<4>(Slice(key)); if (id_str.empty()) { return Status::Error("There is no such a key in database"); } diff --git a/td/telegram/files/FileGenerateManager.cpp b/td/telegram/files/FileGenerateManager.cpp index a98a5237a..f2e33f86a 100644 --- a/td/telegram/files/FileGenerateManager.cpp +++ b/td/telegram/files/FileGenerateManager.cpp @@ -413,7 +413,7 @@ void FileGenerateManager::generate_file(uint64 query_id, FullGenerateFileLocatio CHECK(query_id != 0); auto it_flag = query_id_to_query_.emplace(query_id, Query{}); - LOG_CHECK(it_flag.second) << "Query id must be unique"; + LOG_CHECK(it_flag.second) << "Query identifier must be unique"; auto parent = actor_shared(this, query_id); Slice file_id_query = "#file_id#"; diff --git a/td/telegram/files/FileLocation.h b/td/telegram/files/FileLocation.h index 9e1428b81..4bf0140a2 100644 --- a/td/telegram/files/FileLocation.h +++ b/td/telegram/files/FileLocation.h @@ -110,7 +110,7 @@ struct PhotoRemoteFileLocation { }; inline StringBuilder &operator<<(StringBuilder &string_builder, const PhotoRemoteFileLocation &location) { - return string_builder << "[id = " << location.id_ << ", access_hash = " << location.access_hash_ + return string_builder << "[ID = " << location.id_ << ", access_hash = " << location.access_hash_ << ", volume_id = " << location.volume_id_ << ", local_id = " << location.local_id_ << "]"; } @@ -173,7 +173,7 @@ struct CommonRemoteFileLocation { }; inline StringBuilder &operator<<(StringBuilder &string_builder, const CommonRemoteFileLocation &location) { - return string_builder << "[id = " << location.id_ << ", access_hash = " << location.access_hash_ << "]"; + return string_builder << "[ID = " << location.id_ << ", access_hash = " << location.access_hash_ << "]"; } class FullRemoteFileLocation { diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index fc184db27..48d211c67 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -1422,7 +1422,8 @@ Result FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sy } FileNodePtr x_node = no_sync ? get_file_node(x_file_id) : get_sync_file_node(x_file_id); if (!x_node) { - return Status::Error(PSLICE() << "Can't merge files. First id is invalid: " << x_file_id << " and " << y_file_id); + return Status::Error(PSLICE() << "Can't merge files. First identifier is invalid: " << x_file_id << " and " + << y_file_id); } if (!y_file_id.is_valid()) { @@ -1431,7 +1432,8 @@ Result FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sy } FileNodePtr y_node = get_file_node(y_file_id); if (!y_node) { - return Status::Error(PSLICE() << "Can't merge files. Second id is invalid: " << x_file_id << " and " << y_file_id); + return Status::Error(PSLICE() << "Can't merge files. Second identifier is invalid: " << x_file_id << " and " + << y_file_id); } if (x_file_id == x_node->upload_pause_) { From ffc07304a9d0dbd775901ceb6d7206b69384b479 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 15:17:23 +0300 Subject: [PATCH 050/281] Improve searchMessages documentation. --- td/generate/scheme/td_api.tl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 69c6d7eaf..c7ed24a2b 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -3919,7 +3919,7 @@ searchChatMessages chat_id:int53 query:string sender:MessageSender from_message_ //@description Searches for messages in all chats except secret chats. Returns the results in reverse chronological order (i.e., in order of decreasing (date, chat_id, message_id)). //-For optimal performance the number of returned messages is chosen by the library -//@chat_list Chat list in which to search messages; pass null to search in all chats regardless of their chat list +//@chat_list Chat list in which to search messages; pass null to search in all chats regardless of their chat list. Only Main and Archive chat lists are supported //@query Query to search for //@offset_date The date of the message starting from which the results should be fetched. Use 0 or any date in the future to get results from the last message //@offset_chat_id The chat identifier of the last found message, or 0 for the first request From 95391dc705e369cce89e3cb3f8fff5db7f4ff6ac Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 16:42:03 +0300 Subject: [PATCH 051/281] Improve logging. --- td/telegram/MessagesManager.cpp | 23 ++++++++++++++--------- td/telegram/MessagesManager.h | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 96459ef94..7da028503 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -6867,7 +6867,7 @@ void MessagesManager::update_message_interaction_info(FullMessageId full_message } if (update_message_interaction_info(dialog_id, m, view_count, forward_count, has_reply_info, - std::move(new_reply_info))) { + std::move(new_reply_info), "update_message_interaction_info")) { on_message_changed(d, m, true, "update_message_interaction_info"); } } @@ -6952,7 +6952,7 @@ td_api::object_ptr MessagesManager::get_message_ bool MessagesManager::update_message_interaction_info(DialogId dialog_id, Message *m, int32 view_count, int32 forward_count, bool has_reply_info, - MessageReplyInfo &&reply_info) { + MessageReplyInfo &&reply_info, const char *source) { CHECK(m != nullptr); m->interaction_info_update_date = G()->unix_time(); // doesn't force message saving if (m->message_id.is_valid_scheduled()) { @@ -6986,7 +6986,8 @@ bool MessagesManager::update_message_interaction_info(DialogId dialog_id, Messag if (need_update_reply_info) { if (m->reply_info.channel_id != reply_info.channel_id) { if (m->reply_info.channel_id.is_valid() && reply_info.channel_id.is_valid() && m->message_id.is_server()) { - LOG(ERROR) << "Reply info changed from " << m->reply_info << " to " << reply_info; + LOG(ERROR) << "Reply info of " << FullMessageId{dialog_id, m->message_id} << " changed from " << m->reply_info + << " to " << reply_info << " from " << source; } } m->reply_info = std::move(reply_info); @@ -11408,7 +11409,7 @@ void MessagesManager::read_history_inbox(DialogId dialog_id, MessageId max_messa LOG(ERROR) << "Have unknown " << unread_count << " unread messages up to " << max_message_id << " in " << dialog_id << " with last_new_message_id = " << d->last_new_message_id << ", last_message_id = " << d->last_message_id - << ", last_database_message_id = " << d->last_database_message_id; + << ", last_database_message_id = " << d->last_database_message_id << " from " << source; } unread_count = 0; } @@ -27249,7 +27250,8 @@ MessagesManager::MessageNotificationGroup MessagesManager::get_message_notificat last_notification_id != group_info.last_notification_id) { LOG(ERROR) << "Fix last notification date in " << d->dialog_id << " from " << group_info.last_notification_date << " to " << last_notification_date << " and last notification identifier from " - << group_info.last_notification_id << " to " << last_notification_id; + << group_info.last_notification_id << " to " << last_notification_id << " in " << group_id << " of type " + << result.type; set_dialog_last_notification(d->dialog_id, group_info, last_notification_date, last_notification_id, "get_message_notification_group_force"); } @@ -27355,7 +27357,8 @@ vector MessagesManager::get_message_notifications_from_database_fo auto notification_id = m->notification_id.is_valid() ? m->notification_id : m->removed_notification_id; if (!notification_id.is_valid()) { - VLOG(ERROR) << "Can't find notification identifier for " << m->message_id << " in " << d->dialog_id; + LOG(ERROR) << "Can't find notification identifier for " << m->message_id << " in " << d->dialog_id + << " with from_mentions = " << from_mentions; continue; } CHECK(m->message_id.is_valid()); @@ -27611,7 +27614,8 @@ void MessagesManager::on_get_message_notifications_from_database(DialogId dialog auto notification_id = m->notification_id.is_valid() ? m->notification_id : m->removed_notification_id; if (!notification_id.is_valid()) { - VLOG(ERROR) << "Can't find notification identifier for " << m->message_id << " in " << d->dialog_id; + LOG(ERROR) << "Can't find notification identifier for " << m->message_id << " in " << d->dialog_id + << " with from_mentions = " << from_mentions; continue; } CHECK(m->message_id.is_valid()); @@ -32478,7 +32482,8 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq if (next_message != nullptr) { if (next_message->message_id.is_server() && !(td_->auth_manager_->is_bot() && Slice(source) == Slice("GetChannelMessagesQuery"))) { - LOG(ERROR) << "Can't attach " << m->message_id << " from " << source << " before " << next_message->message_id + LOG(ERROR) << "Can't attach " << m->message_id << " from " << source << " from " + << (m->from_database ? "database" : "server") << " before " << next_message->message_id << " and after " << previous_message->message_id << " in " << dialog_id; dump_debug_message_op(d); } @@ -33386,7 +33391,7 @@ bool MessagesManager::update_message(Dialog *d, Message *old_message, unique_ptr need_send_update = true; } if (update_message_interaction_info(dialog_id, old_message, new_message->view_count, new_message->forward_count, true, - std::move(new_message->reply_info))) { + std::move(new_message->reply_info), "update_message")) { need_send_update = true; } if (old_message->restriction_reasons != new_message->restriction_reasons) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 75c74125a..cc75e6fcf 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1959,7 +1959,7 @@ class MessagesManager : public Actor { const Message *m) const; bool update_message_interaction_info(DialogId dialog_id, Message *m, int32 view_count, int32 forward_count, - bool has_reply_info, MessageReplyInfo &&reply_info); + bool has_reply_info, MessageReplyInfo &&reply_info, const char *source); bool update_message_contains_unread_mention(Dialog *d, Message *m, bool contains_unread_mention, const char *source); From ff3600b7621700315b4d13ce01efbe0b0be61780 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 17:48:18 +0300 Subject: [PATCH 052/281] Sync group call participants after rights changed. --- td/telegram/GroupCallManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index eec92a145..6bc23d509 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1050,6 +1050,7 @@ void GroupCallManager::on_update_group_call_rights(InputGroupCallId input_group_ } reload_group_call(input_group_call_id, Auto()); + sync_group_call_participants(input_group_call_id); // participant order is different for administrators } void GroupCallManager::reload_group_call(InputGroupCallId input_group_call_id, From be68cda22f0e302f0e272f7aa1860d7a59a0a831 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 18:32:28 +0300 Subject: [PATCH 053/281] Add class GroupCallParticipantOrder. --- CMakeLists.txt | 2 + td/telegram/GroupCallManager.cpp | 49 +++++++++--------- td/telegram/GroupCallManager.h | 3 +- td/telegram/GroupCallParticipant.cpp | 6 ++- td/telegram/GroupCallParticipant.h | 7 ++- td/telegram/GroupCallParticipantOrder.cpp | 60 +++++++++++++++++++++++ td/telegram/GroupCallParticipantOrder.h | 54 ++++++++++++++++++++ 7 files changed, 151 insertions(+), 30 deletions(-) create mode 100644 td/telegram/GroupCallParticipantOrder.cpp create mode 100644 td/telegram/GroupCallParticipantOrder.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b186375f4..9d8ef3a17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -321,6 +321,7 @@ set(TDLIB_SOURCE td/telegram/Global.cpp td/telegram/GroupCallManager.cpp td/telegram/GroupCallParticipant.cpp + td/telegram/GroupCallParticipantOrder.cpp td/telegram/HashtagHints.cpp td/telegram/InlineQueriesManager.cpp td/telegram/InputDialogId.cpp @@ -500,6 +501,7 @@ set(TDLIB_SOURCE td/telegram/GroupCallId.h td/telegram/GroupCallManager.h td/telegram/GroupCallParticipant.h + td/telegram/GroupCallParticipantOrder.h td/telegram/HashtagHints.h td/telegram/InlineQueriesManager.h td/telegram/InputDialogId.h diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 6bc23d509..806671a66 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -25,7 +25,6 @@ #include "td/utils/misc.h" #include "td/utils/Random.h" -#include #include #include #include @@ -664,7 +663,7 @@ struct GroupCallManager::GroupCall { struct GroupCallManager::GroupCallParticipants { vector participants; string next_offset; - int64 min_order = std::numeric_limits::max(); + GroupCallParticipantOrder min_order = GroupCallParticipantOrder::max(); bool are_administrators_loaded = false; vector administrator_user_ids; @@ -1050,7 +1049,7 @@ void GroupCallManager::on_update_group_call_rights(InputGroupCallId input_group_ } reload_group_call(input_group_call_id, Auto()); - sync_group_call_participants(input_group_call_id); // participant order is different for administrators + sync_group_call_participants(input_group_call_id); // participant order is different for administrators } void GroupCallManager::reload_group_call(InputGroupCallId input_group_call_id, @@ -1528,7 +1527,8 @@ void GroupCallManager::on_sync_group_call_participants_failed(InputGroupCallId i sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(), 1.0); } -int64 GroupCallManager::get_real_participant_order(const GroupCallParticipant &participant, int64 min_order) const { +GroupCallParticipantOrder GroupCallManager::get_real_participant_order(const GroupCallParticipant &participant, + GroupCallParticipantOrder min_order) const { auto real_order = participant.get_real_order(); if (real_order < min_order && participant.is_self) { return min_order; @@ -1536,7 +1536,7 @@ int64 GroupCallManager::get_real_participant_order(const GroupCallParticipant &p if (real_order >= min_order) { return real_order; } - return 0; + return GroupCallParticipantOrder(); } void GroupCallManager::process_group_call_participants( @@ -1566,7 +1566,7 @@ void GroupCallManager::process_group_call_participants( } } - int64 min_order = std::numeric_limits::max(); + auto min_order = GroupCallParticipantOrder::max(); for (auto &participant : participants) { GroupCallParticipant group_call_participant(participant); if (!group_call_participant.is_valid()) { @@ -1598,13 +1598,13 @@ void GroupCallManager::process_group_call_participants( for (auto participant_it = group_participants.begin(); participant_it != group_participants.end();) { auto &participant = *participant_it; if (old_participant_dialog_ids.count(participant.dialog_id) == 0) { - CHECK(participant.order == 0 || participant.order >= min_order); + CHECK(!participant.order.is_valid() || participant.order >= min_order); ++participant_it; continue; } // not synced user, needs to be deleted - if (participant.order != 0) { + if (participant.order.is_valid()) { CHECK(participant.order >= participants_it->second->min_order); if (participant.is_self) { if (participant.order != min_order) { @@ -1612,7 +1612,7 @@ void GroupCallManager::process_group_call_participants( send_update_group_call_participant(input_group_call_id, participant); } } else { - participant.order = 0; + participant.order = GroupCallParticipantOrder(); send_update_group_call_participant(input_group_call_id, participant); } } @@ -1635,7 +1635,7 @@ void GroupCallManager::process_group_call_participants( for (auto &participant : participants_it->second->participants) { auto real_order = get_real_participant_order(participant, min_order); if (old_min_order > real_order && real_order >= min_order) { - CHECK(participant.order == 0 || participant.order == old_min_order); + CHECK(!participant.order.is_valid() || participant.order == old_min_order); participant.order = real_order; send_update_group_call_participant(input_group_call_id, participant); } @@ -1659,7 +1659,8 @@ void GroupCallManager::update_group_call_participants_can_be_muted(InputGroupCal CHECK(participants != nullptr); LOG(INFO) << "Update group call participants can_be_muted in " << input_group_call_id; for (auto &participant : participants->participants) { - if (update_group_call_participant_can_be_muted(can_manage, participants, participant) && participant.order != 0) { + if (update_group_call_participant_can_be_muted(can_manage, participants, participant) && + participant.order.is_valid()) { send_update_group_call_participant(input_group_call_id, participant); } } @@ -1696,7 +1697,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (old_participant.dialog_id == participant.dialog_id || (old_participant.is_self && participant.is_self)) { if (participant.joined_date == 0) { LOG(INFO) << "Remove " << old_participant; - if (old_participant.order != 0) { + if (old_participant.order.is_valid()) { send_update_group_call_participant(input_group_call_id, participant); } on_remove_group_call_participant(input_group_call_id, participant.dialog_id); @@ -1712,7 +1713,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou update_group_call_participant_can_be_muted(can_manage, participants, participant); LOG(INFO) << "Edit " << old_participant << " to " << participant; - if (old_participant != participant && (old_participant.order != 0 || participant.order != 0)) { + if (old_participant != participant && (old_participant.order.is_valid() || participant.order.is_valid())) { send_update_group_call_participant(input_group_call_id, participant); } on_participant_speaking_in_group_call(input_group_call_id, participant); @@ -1738,7 +1739,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou participant.is_just_joined = false; update_group_call_participant_can_be_muted(can_manage, participants, participant); participants->participants.push_back(std::move(participant)); - if (participants->participants.back().order != 0) { + if (participants->participants.back().order.is_valid()) { send_update_group_call_participant(input_group_call_id, participants->participants.back()); } on_add_group_call_participant(input_group_call_id, participants->participants.back().dialog_id); @@ -1774,7 +1775,7 @@ void GroupCallManager::on_update_dialog_about(DialogId dialog_id, const string & CHECK(participant != nullptr); if ((from_server || participant->is_fake) && participant->about != about) { participant->about = about; - if (participant->order != 0) { + if (participant->order.is_valid()) { send_update_group_call_participant(input_group_call_id, *participant); } } @@ -2565,7 +2566,7 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ *participant = std::move(participant_copy); participant->pending_is_muted_generation = ++toggle_is_muted_generation_; - if (participant->order != 0) { + if (participant->order.is_valid()) { send_update_group_call_participant(input_group_call_id, *participant); } @@ -2605,7 +2606,7 @@ void GroupCallManager::on_toggle_group_call_participant_is_muted(InputGroupCallI participant->server_is_muted_by_admin != participant->pending_is_muted_by_admin || participant->server_is_muted_locally != participant->pending_is_muted_locally) { LOG(ERROR) << "Failed to mute/unmute " << dialog_id << " in " << input_group_call_id; - if (participant->order != 0) { + if (participant->order.is_valid()) { send_update_group_call_participant(input_group_call_id, *participant); } } @@ -2655,7 +2656,7 @@ void GroupCallManager::set_group_call_participant_volume_level(GroupCallId group participant->pending_volume_level = volume_level; participant->pending_volume_level_generation = ++set_volume_level_generation_; - if (participant->order != 0) { + if (participant->order.is_valid()) { send_update_group_call_participant(input_group_call_id, *participant); } @@ -2693,7 +2694,7 @@ void GroupCallManager::on_set_group_call_participant_volume_level(InputGroupCall if (participant->volume_level != participant->pending_volume_level) { LOG(ERROR) << "Failed to set volume level of " << dialog_id << " in " << input_group_call_id; participant->pending_volume_level = 0; - if (participant->order != 0) { + if (participant->order.is_valid()) { send_update_group_call_participant(input_group_call_id, *participant); } } else { @@ -2750,7 +2751,7 @@ void GroupCallManager::toggle_group_call_participant_is_hand_raised(GroupCallId participant->have_pending_is_hand_raised = true; participant->pending_is_hand_raised = is_hand_raised; participant->pending_is_hand_raised_generation = ++toggle_is_hand_raised_generation_; - if (participant->order != 0) { + if (participant->order.is_valid()) { send_update_group_call_participant(input_group_call_id, *participant); } @@ -2788,7 +2789,7 @@ void GroupCallManager::on_toggle_group_call_participant_is_hand_raised(InputGrou participant->have_pending_is_hand_raised = false; if (participant->get_is_hand_raised() != participant->pending_is_hand_raised) { LOG(ERROR) << "Failed to change raised hand state for " << dialog_id << " in " << input_group_call_id; - if (participant->order != 0) { + if (participant->order.is_valid()) { send_update_group_call_participant(input_group_call_id, *participant); } } @@ -2941,9 +2942,9 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ group_call->version = -1; for (auto &participant : participants->participants) { - if (participant.order != 0) { + if (participant.order.is_valid()) { CHECK(participant.order >= participants->min_order); - participant.order = 0; + participant.order = GroupCallParticipantOrder(); send_update_group_call_participant(input_group_call_id, participant); } on_remove_group_call_participant(input_group_call_id, participant.dialog_id); @@ -3305,7 +3306,7 @@ DialogId GroupCallManager::set_group_call_participant_is_speaking_by_source(Inpu participant.local_active_date = max(participant.local_active_date, date); } participant.order = get_real_participant_order(participant, participants_it->second->min_order); - if (participant.order != 0) { + if (participant.order.is_valid()) { send_update_group_call_participant(input_group_call_id, participant); } } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 39098924c..8f6911af5 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -180,7 +180,8 @@ class GroupCallManager : public Actor { void on_sync_group_call_participants_failed(InputGroupCallId input_group_call_id); - int64 get_real_participant_order(const GroupCallParticipant &participant, int64 min_order) const; + GroupCallParticipantOrder get_real_participant_order(const GroupCallParticipant &participant, + GroupCallParticipantOrder min_order) const; void process_group_call_participants(InputGroupCallId group_call_id, vector> &&participants, diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index 5db81a1f4..69c09d1b5 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -52,6 +52,10 @@ bool GroupCallParticipant::is_versioned_update(const tl_object_ptrjust_joined_ || participant->left_ || participant->versioned_; } +GroupCallParticipantOrder GroupCallParticipant::get_real_order() const { + return GroupCallParticipantOrder(max(active_date, local_active_date), 0, joined_date); +} + bool GroupCallParticipant::get_is_muted_by_themselves() const { return have_pending_is_muted ? pending_is_muted_by_themselves : server_is_muted_by_themselves; } @@ -228,7 +232,7 @@ td_api::object_ptr GroupCallParticipant::get_group td->messages_manager_->get_message_sender_object(dialog_id), audio_source, about, is_speaking, get_is_hand_raised(), can_be_muted_for_all_users, can_be_unmuted_for_all_users, can_be_muted_only_for_self, can_be_unmuted_only_for_self, get_is_muted_for_all_users(), get_is_muted_locally(), get_is_muted_by_themselves(), - get_volume_level(), order); + get_volume_level(), order.get_group_call_participant_order_object()); } bool operator==(const GroupCallParticipant &lhs, const GroupCallParticipant &rhs) { diff --git a/td/telegram/GroupCallParticipant.h b/td/telegram/GroupCallParticipant.h index 36fcd89ee..54b1bf686 100644 --- a/td/telegram/GroupCallParticipant.h +++ b/td/telegram/GroupCallParticipant.h @@ -7,6 +7,7 @@ #pragma once #include "td/telegram/DialogId.h" +#include "td/telegram/GroupCallParticipantOrder.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" @@ -41,7 +42,7 @@ struct GroupCallParticipant { bool is_just_joined = false; bool is_speaking = false; int32 local_active_date = 0; - int64 order = 0; + GroupCallParticipantOrder order; int32 pending_volume_level = 0; uint64 pending_volume_level_generation = 0; @@ -71,9 +72,7 @@ struct GroupCallParticipant { bool set_pending_is_muted(bool is_muted, bool can_manage, bool is_admin); - int64 get_real_order() const { - return (static_cast(max(active_date, local_active_date)) << 32) + joined_date; - } + GroupCallParticipantOrder get_real_order() const; bool is_valid() const { return dialog_id.is_valid(); diff --git a/td/telegram/GroupCallParticipantOrder.cpp b/td/telegram/GroupCallParticipantOrder.cpp new file mode 100644 index 000000000..810d02589 --- /dev/null +++ b/td/telegram/GroupCallParticipantOrder.cpp @@ -0,0 +1,60 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/GroupCallParticipantOrder.h" + +#include +#include + +namespace td { + +GroupCallParticipantOrder GroupCallParticipantOrder::max() { + return GroupCallParticipantOrder(std::numeric_limits::max(), std::numeric_limits::max(), + std::numeric_limits::max()); +} + +bool GroupCallParticipantOrder::is_valid() const { + return *this != GroupCallParticipantOrder(); +} + +int64 GroupCallParticipantOrder::get_group_call_participant_order_object() const { + return (static_cast(active_date) << 32) + joined_date; +} + +bool operator==(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs) { + return lhs.active_date == rhs.active_date && lhs.joined_date == rhs.joined_date && + lhs.raise_hand_rating == rhs.raise_hand_rating; +} + +bool operator!=(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs) { + return !(lhs == rhs); +} + +bool operator<(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs) { + return std::tie(lhs.active_date, lhs.raise_hand_rating, lhs.joined_date) < + std::tie(rhs.active_date, rhs.raise_hand_rating, rhs.joined_date); +} + +bool operator<=(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs) { + return !(rhs < lhs); +} + +bool operator>(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs) { + return rhs < lhs; +} + +bool operator>=(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs) { + return !(lhs < rhs); +} + +StringBuilder &operator<<(StringBuilder &string_builder, + const GroupCallParticipantOrder &group_call_participant_order) { + return string_builder << group_call_participant_order.active_date << '/' + << group_call_participant_order.raise_hand_rating << '/' + << group_call_participant_order.joined_date; +} + +} // namespace td diff --git a/td/telegram/GroupCallParticipantOrder.h b/td/telegram/GroupCallParticipantOrder.h new file mode 100644 index 000000000..abc196132 --- /dev/null +++ b/td/telegram/GroupCallParticipantOrder.h @@ -0,0 +1,54 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/utils/common.h" +#include "td/utils/StringBuilder.h" + +namespace td { + +class GroupCallParticipantOrder { + int32 active_date = 0; + int32 joined_date = 0; + int64 raise_hand_rating = 0; + + friend StringBuilder &operator<<(StringBuilder &string_builder, + const GroupCallParticipantOrder &group_call_participant_order); + + friend bool operator==(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs); + + friend bool operator<(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs); + + public: + GroupCallParticipantOrder() = default; + + GroupCallParticipantOrder(int32 active_date, int64 raise_hand_rating, int32 joined_date) + : active_date(active_date), joined_date(joined_date), raise_hand_rating(raise_hand_rating) { + } + + static GroupCallParticipantOrder max(); + + bool is_valid() const; + + int64 get_group_call_participant_order_object() const; +}; + +bool operator==(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs); + +bool operator!=(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs); + +bool operator<(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs); + +bool operator<=(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs); + +bool operator>(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs); + +bool operator>=(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs); + +StringBuilder &operator<<(StringBuilder &string_builder, const GroupCallParticipantOrder &group_call_participant_order); + +} // namespace td From 1c923154390b82c4c97f5525d039a8eeac69fbfa Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 18:39:02 +0300 Subject: [PATCH 054/281] Fix lpad0 signature. --- tdutils/td/utils/misc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tdutils/td/utils/misc.h b/tdutils/td/utils/misc.h index 1f89b9750..a514acc93 100644 --- a/tdutils/td/utils/misc.h +++ b/tdutils/td/utils/misc.h @@ -144,7 +144,7 @@ T trim(T str) { string lpad(string str, size_t size, char c); -string lpad0(const string str, size_t size); +string lpad0(string str, size_t size); string rpad(string str, size_t size, char c); From 798791223057067befb91e6786fbb0905469c180 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 18:53:51 +0300 Subject: [PATCH 055/281] Use string as groupCallParticipant.order. --- td/generate/scheme/td_api.tl | 4 ++-- td/telegram/GroupCallParticipant.cpp | 6 +++++- td/telegram/GroupCallParticipantOrder.cpp | 8 ++++++-- td/telegram/GroupCallParticipantOrder.h | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index c7ed24a2b..f72b2efb2 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2162,8 +2162,8 @@ groupCallJoinResponseStream = GroupCallJoinResponse; //@is_muted_for_current_user True, if the participant is muted for the current user //@can_unmute_self True, if the participant is muted for all users, but can unmute themself //@volume_level Participant's volume level; 1-20000 in hundreds of percents -//@order User's order in the group call participant list. The bigger is order, the higher is user in the list. If order is 0, the user must be removed from the participant list -groupCallParticipant participant:MessageSender source:int32 bio:string is_speaking:Bool is_hand_raised:Bool can_be_muted_for_all_users:Bool can_be_unmuted_for_all_users:Bool can_be_muted_for_current_user:Bool can_be_unmuted_for_current_user:Bool is_muted_for_all_users:Bool is_muted_for_current_user:Bool can_unmute_self:Bool volume_level:int32 order:int64 = GroupCallParticipant; +//@order User's order in the group call participant list. Orders must be compared lexicographically. The bigger is order, the higher is user in the list. If order is empty, the user must be removed from the participant list +groupCallParticipant participant:MessageSender source:int32 bio:string is_speaking:Bool is_hand_raised:Bool can_be_muted_for_all_users:Bool can_be_unmuted_for_all_users:Bool can_be_muted_for_current_user:Bool can_be_unmuted_for_current_user:Bool is_muted_for_all_users:Bool is_muted_for_current_user:Bool can_unmute_self:Bool volume_level:int32 order:string = GroupCallParticipant; //@class CallProblem @description Describes the exact type of a problem with a call diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index 69c09d1b5..88231bb72 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -36,12 +36,16 @@ GroupCallParticipant::GroupCallParticipant(const tl_object_ptractive_date_; } if (joined_date < 0 || active_date < 0) { - LOG(ERROR) << "Receive invalid " << to_string(participant); + LOG(ERROR) << "Receive invalid active_date/joined_date in " << to_string(participant); joined_date = 0; active_date = 0; } if ((participant->flags_ & telegram_api::groupCallParticipant::RAISE_HAND_RATING_MASK) != 0) { raise_hand_rating = participant->raise_hand_rating_; + if (raise_hand_rating < 0) { + LOG(ERROR) << "Receive invalid raise_hand_rating in " << to_string(participant); + raise_hand_rating = 0; + } } } is_just_joined = participant->just_joined_; diff --git a/td/telegram/GroupCallParticipantOrder.cpp b/td/telegram/GroupCallParticipantOrder.cpp index 810d02589..08486c441 100644 --- a/td/telegram/GroupCallParticipantOrder.cpp +++ b/td/telegram/GroupCallParticipantOrder.cpp @@ -6,6 +6,9 @@ // #include "td/telegram/GroupCallParticipantOrder.h" +#include "td/utils/logging.h" +#include "td/utils/misc.h" + #include #include @@ -20,8 +23,9 @@ bool GroupCallParticipantOrder::is_valid() const { return *this != GroupCallParticipantOrder(); } -int64 GroupCallParticipantOrder::get_group_call_participant_order_object() const { - return (static_cast(active_date) << 32) + joined_date; +string GroupCallParticipantOrder::get_group_call_participant_order_object() const { + return PSTRING() << lpad0(to_string(active_date), 10) << lpad0(to_string(raise_hand_rating), 19) + << lpad0(to_string(joined_date), 10); } bool operator==(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs) { diff --git a/td/telegram/GroupCallParticipantOrder.h b/td/telegram/GroupCallParticipantOrder.h index abc196132..973974465 100644 --- a/td/telegram/GroupCallParticipantOrder.h +++ b/td/telegram/GroupCallParticipantOrder.h @@ -34,7 +34,7 @@ class GroupCallParticipantOrder { bool is_valid() const; - int64 get_group_call_participant_order_object() const; + string get_group_call_participant_order_object() const; }; bool operator==(const GroupCallParticipantOrder &lhs, const GroupCallParticipantOrder &rhs); From b0aa14c031771f6c564a2b1ad8e2f952ed0a848a Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 18:58:31 +0300 Subject: [PATCH 056/281] Improve get_real_participant_order. --- td/telegram/GroupCallManager.cpp | 10 +++++----- td/telegram/GroupCallManager.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 806671a66..311b0c7d1 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1527,15 +1527,15 @@ void GroupCallManager::on_sync_group_call_participants_failed(InputGroupCallId i sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(), 1.0); } -GroupCallParticipantOrder GroupCallManager::get_real_participant_order(const GroupCallParticipant &participant, - GroupCallParticipantOrder min_order) const { +GroupCallParticipantOrder GroupCallManager::get_real_participant_order( + const GroupCallParticipant &participant, const GroupCallParticipantOrder &min_order) const { auto real_order = participant.get_real_order(); - if (real_order < min_order && participant.is_self) { - return min_order; - } if (real_order >= min_order) { return real_order; } + if (participant.is_self) { + return min_order; + } return GroupCallParticipantOrder(); } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 8f6911af5..465c0b0cf 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -181,7 +181,7 @@ class GroupCallManager : public Actor { void on_sync_group_call_participants_failed(InputGroupCallId input_group_call_id); GroupCallParticipantOrder get_real_participant_order(const GroupCallParticipant &participant, - GroupCallParticipantOrder min_order) const; + const GroupCallParticipantOrder &min_order) const; void process_group_call_participants(InputGroupCallId group_call_id, vector> &&participants, From 0a4f1c15b8144e8d134c67bb9c8778af6aae2b71 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 19:20:57 +0300 Subject: [PATCH 057/281] Ensure that group call participant is synchronized after explicit request. --- td/telegram/GroupCallManager.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 311b0c7d1..4f628984c 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -634,6 +634,7 @@ struct GroupCallManager::GroupCall { bool can_self_unmute = false; bool can_be_managed = false; bool syncing_participants = false; + bool need_syncing_participants = false; bool loaded_all_participants = false; bool mute_new_participants = false; bool allowed_change_mute_new_participants = false; @@ -1255,6 +1256,11 @@ void GroupCallManager::on_get_group_call_participants( if (need_update) { send_update_group_call(group_call, "on_get_group_call_participants"); } + + if (is_sync && group_call->need_syncing_participants) { + group_call->need_syncing_participants = false; + sync_group_call_participants(input_group_call_id); + } } } } @@ -1501,9 +1507,11 @@ void GroupCallManager::sync_group_call_participants(InputGroupCallId input_group sync_participants_timeout_.cancel_timeout(group_call->group_call_id.get()); if (group_call->syncing_participants) { + group_call->need_syncing_participants = true; return; } group_call->syncing_participants = true; + group_call->need_syncing_participants = false; LOG(INFO) << "Force participants synchronization in " << input_group_call_id << " from " << group_call->dialog_id; auto promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id](Result &&result) { @@ -1524,7 +1532,8 @@ void GroupCallManager::on_sync_group_call_participants_failed(InputGroupCallId i CHECK(group_call->syncing_participants); group_call->syncing_participants = false; - sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(), 1.0); + sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(), + group_call->need_syncing_participants ? 0.0 : 1.0); } GroupCallParticipantOrder GroupCallManager::get_real_participant_order( @@ -3029,6 +3038,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptris_being_left; call.is_speaking = group_call->is_speaking; call.syncing_participants = group_call->syncing_participants; + call.need_syncing_participants = group_call->need_syncing_participants; call.loaded_all_participants = group_call->loaded_all_participants; call.audio_source = group_call->audio_source; *group_call = std::move(call); From 24535d2aba3d6946c08fd15459f822355cd4a0f0 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 19:32:33 +0300 Subject: [PATCH 058/281] Support different order of group call participants for administrators. --- td/telegram/GroupCallManager.cpp | 16 +++++++++------- td/telegram/GroupCallManager.h | 2 +- td/telegram/GroupCallParticipant.cpp | 9 +++++++-- td/telegram/GroupCallParticipant.h | 2 +- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 4f628984c..617bf5d1b 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1537,8 +1537,8 @@ void GroupCallManager::on_sync_group_call_participants_failed(InputGroupCallId i } GroupCallParticipantOrder GroupCallManager::get_real_participant_order( - const GroupCallParticipant &participant, const GroupCallParticipantOrder &min_order) const { - auto real_order = participant.get_real_order(); + bool can_manage, const GroupCallParticipant &participant, const GroupCallParticipantOrder &min_order) const { + auto real_order = participant.get_real_order(can_manage); if (real_order >= min_order) { return real_order; } @@ -1576,6 +1576,7 @@ void GroupCallManager::process_group_call_participants( } auto min_order = GroupCallParticipantOrder::max(); + bool can_manage = can_manage_group_call(input_group_call_id); for (auto &participant : participants) { GroupCallParticipant group_call_participant(participant); if (!group_call_participant.is_valid()) { @@ -1587,7 +1588,7 @@ void GroupCallManager::process_group_call_participants( continue; } - auto real_order = group_call_participant.get_real_order(); + auto real_order = group_call_participant.get_real_order(can_manage); if (real_order > min_order) { LOG(ERROR) << "Receive call participant with order " << real_order << " after call participant with order " << min_order; @@ -1642,7 +1643,7 @@ void GroupCallManager::process_group_call_participants( participants_it->second->min_order = min_order; for (auto &participant : participants_it->second->participants) { - auto real_order = get_real_participant_order(participant, min_order); + auto real_order = get_real_participant_order(can_manage, participant, min_order); if (old_min_order > real_order && real_order >= min_order) { CHECK(!participant.order.is_valid() || participant.order == old_min_order); participant.order = real_order; @@ -1718,7 +1719,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou participant.update_from(old_participant); participant.is_just_joined = false; - participant.order = get_real_participant_order(participant, participants->min_order); + participant.order = get_real_participant_order(can_manage, participant, participants->min_order); update_group_call_participant_can_be_muted(can_manage, participants, participant); LOG(INFO) << "Edit " << old_participant << " to " << participant; @@ -1744,7 +1745,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou } else { LOG(INFO) << "Receive new " << participant; } - participant.order = get_real_participant_order(participant, participants->min_order); + participant.order = get_real_participant_order(can_manage, participant, participants->min_order); participant.is_just_joined = false; update_group_call_participant_can_be_muted(can_manage, participants, participant); participants->participants.push_back(std::move(participant)); @@ -3315,7 +3316,8 @@ DialogId GroupCallManager::set_group_call_participant_is_speaking_by_source(Inpu if (is_speaking) { participant.local_active_date = max(participant.local_active_date, date); } - participant.order = get_real_participant_order(participant, participants_it->second->min_order); + bool can_manage = can_manage_group_call(input_group_call_id); + participant.order = get_real_participant_order(can_manage, participant, participants_it->second->min_order); if (participant.order.is_valid()) { send_update_group_call_participant(input_group_call_id, participant); } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 465c0b0cf..b8a4ab336 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -180,7 +180,7 @@ class GroupCallManager : public Actor { void on_sync_group_call_participants_failed(InputGroupCallId input_group_call_id); - GroupCallParticipantOrder get_real_participant_order(const GroupCallParticipant &participant, + GroupCallParticipantOrder get_real_participant_order(bool can_manage, const GroupCallParticipant &participant, const GroupCallParticipantOrder &min_order) const; void process_group_call_participants(InputGroupCallId group_call_id, diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index 88231bb72..e15d5d958 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -6,6 +6,7 @@ // #include "td/telegram/GroupCallParticipant.h" +#include "td/telegram/Global.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/Td.h" @@ -56,8 +57,12 @@ bool GroupCallParticipant::is_versioned_update(const tl_object_ptrjust_joined_ || participant->left_ || participant->versioned_; } -GroupCallParticipantOrder GroupCallParticipant::get_real_order() const { - return GroupCallParticipantOrder(max(active_date, local_active_date), 0, joined_date); +GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_manage) const { + auto date = td::max(active_date, local_active_date); + if (date < G()->unix_time() - 300) { + date = 0; + } + return GroupCallParticipantOrder(date, can_manage ? raise_hand_rating : 0, joined_date); } bool GroupCallParticipant::get_is_muted_by_themselves() const { diff --git a/td/telegram/GroupCallParticipant.h b/td/telegram/GroupCallParticipant.h index 54b1bf686..20247947e 100644 --- a/td/telegram/GroupCallParticipant.h +++ b/td/telegram/GroupCallParticipant.h @@ -72,7 +72,7 @@ struct GroupCallParticipant { bool set_pending_is_muted(bool is_muted, bool can_manage, bool is_admin); - GroupCallParticipantOrder get_real_order() const; + GroupCallParticipantOrder get_real_order(bool can_manage) const; bool is_valid() const { return dialog_id.is_valid(); From eb7a1286ab512bf243b5dd40a177f1a9a0f011ea Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 15 Mar 2021 22:04:11 +0300 Subject: [PATCH 059/281] Automatically update order of inactive group call participants. --- td/telegram/GroupCallManager.cpp | 50 +++++++++++++++++++++++++++++++- td/telegram/GroupCallManager.h | 7 +++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 617bf5d1b..119c890ad 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -687,6 +687,9 @@ struct GroupCallManager::PendingJoinRequest { }; GroupCallManager::GroupCallManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { + update_group_call_participant_order_timeout_.set_callback(on_update_group_call_participant_order_timeout_callback); + update_group_call_participant_order_timeout_.set_callback_data(static_cast(this)); + check_group_call_is_joined_timeout_.set_callback(on_check_group_call_is_joined_timeout_callback); check_group_call_is_joined_timeout_.set_callback_data(static_cast(this)); @@ -706,6 +709,43 @@ void GroupCallManager::tear_down() { parent_.reset(); } +void GroupCallManager::on_update_group_call_participant_order_timeout_callback(void *group_call_manager_ptr, + int64 group_call_id_int) { + if (G()->close_flag()) { + return; + } + + auto group_call_manager = static_cast(group_call_manager_ptr); + send_closure_later(group_call_manager->actor_id(group_call_manager), + &GroupCallManager::on_update_group_call_participant_order_timeout, + GroupCallId(narrow_cast(group_call_id_int))); +} + +void GroupCallManager::on_update_group_call_participant_order_timeout(GroupCallId group_call_id) { + if (G()->close_flag()) { + return; + } + + LOG(INFO) << "Receive update group call participant order timeout in " << group_call_id; + auto input_group_call_id = get_input_group_call_id(group_call_id).move_as_ok(); + + if (!need_group_call_participants(input_group_call_id)) { + return; + } + + bool can_manage = can_manage_group_call(input_group_call_id); + auto *participants = add_group_call_participants(input_group_call_id); + for (auto &participant : participants->participants) { + auto new_order = get_real_participant_order(can_manage, participant, participants->min_order); + if (new_order != participant.order) { + participant.order = new_order; + send_update_group_call_participant(input_group_call_id, participant); + } + } + update_group_call_participant_order_timeout_.set_timeout_in(group_call_id.get(), + UPDATE_GROUP_CALL_PARTICIPANT_ORDER_TIMEOUT); +} + void GroupCallManager::on_check_group_call_is_joined_timeout_callback(void *group_call_manager_ptr, int64 group_call_id_int) { if (G()->close_flag()) { @@ -1650,6 +1690,11 @@ void GroupCallManager::process_group_call_participants( send_update_group_call_participant(input_group_call_id, participant); } } + + auto *group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr && group_call->is_inited); + update_group_call_participant_order_timeout_.add_timeout_in(group_call->group_call_id.get(), + UPDATE_GROUP_CALL_PARTICIPANT_ORDER_TIMEOUT); } } } @@ -2931,6 +2976,10 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ return; } + auto group_call = get_group_call(input_group_call_id); + if (group_call != nullptr) { + update_group_call_participant_order_timeout_.cancel_timeout(group_call->group_call_id.get()); + } remove_recent_group_call_speaker(input_group_call_id, DialogId(td_->contacts_manager_->get_my_id())); auto participants_it = group_call_participants_.find(input_group_call_id); @@ -2942,7 +2991,6 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ CHECK(participants != nullptr); group_call_participants_.erase(participants_it); - auto group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); LOG(INFO) << "Clear participants in " << input_group_call_id << " from " << group_call->dialog_id; if (group_call->loaded_all_participants) { diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index b8a4ab336..f648d4760 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -119,12 +119,18 @@ class GroupCallManager : public Actor { struct PendingJoinRequest; static constexpr int32 RECENT_SPEAKER_TIMEOUT = 60 * 60; + static constexpr int32 UPDATE_GROUP_CALL_PARTICIPANT_ORDER_TIMEOUT = 10; static constexpr int32 CHECK_GROUP_CALL_IS_JOINED_TIMEOUT = 10; static constexpr size_t MAX_TITLE_LENGTH = 64; // server side limit for group call title length static constexpr size_t MAX_RECORD_TITLE_LENGTH = 128; // server side limit for group call record title length void tear_down() override; + static void on_update_group_call_participant_order_timeout_callback(void *group_call_manager_ptr, + int64 group_call_id_int); + + void on_update_group_call_participant_order_timeout(GroupCallId group_call_id); + static void on_check_group_call_is_joined_timeout_callback(void *group_call_manager_ptr, int64 group_call_id_int); void on_check_group_call_is_joined_timeout(GroupCallId group_call_id); @@ -315,6 +321,7 @@ class GroupCallManager : public Actor { uint64 toggle_is_hand_raised_generation_ = 0; + MultiTimeout update_group_call_participant_order_timeout_{"UpdateGroupCallParticipantOrderTimeout"}; MultiTimeout check_group_call_is_joined_timeout_{"CheckGroupCallIsJoinedTimeout"}; MultiTimeout pending_send_speaking_action_timeout_{"PendingSendSpeakingActionTimeout"}; MultiTimeout recent_speaker_update_timeout_{"RecentSpeakerUpdateTimeout"}; From 54b97609358629c3a80aae42ac667eed42949453 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 16 Mar 2021 00:52:37 +0300 Subject: [PATCH 060/281] Improve getExternalLink methods. --- td/generate/scheme/td_api.tl | 8 ++++++-- td/telegram/ConfigManager.cpp | 17 +++++++++-------- td/telegram/ConfigManager.h | 2 +- td/telegram/Td.cpp | 18 +++++++++--------- td/telegram/Td.h | 2 ++ td/telegram/cli.cpp | 7 +++++-- 6 files changed, 32 insertions(+), 22 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index f72b2efb2..7f969af75 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4228,8 +4228,12 @@ viewMessages chat_id:int53 message_thread_id:int53 message_ids:vector for //@description Informs TDLib that the message content has been opened (e.g., the user has opened a photo, video, document, location or venue, or has listened to an audio file or voice note message). An updateMessageContentOpened update will be generated if something has changed @chat_id Chat identifier of the message @message_id Identifier of the message with the opened content openMessageContent chat_id:int53 message_id:int53 = Ok; -//@description Returns an HTTP URL to open when user clicks on a given HTTP link. This method can be used to automatically login user on a Telegram site @link The HTTP link -getExternalLink link:string = HttpUrl; +//@description Returns information about an action to be done when the current user clicks an HTTP link. This method can be used to automatically authorize the current user on a website @link The HTTP link +getExternalLinkInfo link:string = LoginUrlInfo; + +//@description Returns an HTTP URL which can be used to automatically authorize the current user on a website after clicking an HTTP link. Use the method getExternalLinkInfo to find whether a prior user confirmation is needed +//@link The HTTP link @allow_write_access True, if the current user allowed the bot, returned in getExternalLinkInfo, to send them messages +getExternalLink link:string allow_write_access:Bool = HttpUrl; //@description Marks all mentions in a chat as read @chat_id Chat identifier diff --git a/td/telegram/ConfigManager.cpp b/td/telegram/ConfigManager.cpp index 09bdd1e81..f583ac9cc 100644 --- a/td/telegram/ConfigManager.cpp +++ b/td/telegram/ConfigManager.cpp @@ -967,33 +967,34 @@ void ConfigManager::get_app_config(Promise } } -void ConfigManager::get_external_link(string &&link, Promise &&promise) { +void ConfigManager::get_external_link_info(string &&link, Promise> &&promise) { + auto default_result = td_api::make_object(link, false); if (G()->close_flag()) { - return promise.set_value(std::move(link)); + return promise.set_value(std::move(default_result)); } auto r_url = parse_url(link); if (r_url.is_error()) { - return promise.set_value(std::move(link)); + return promise.set_value(std::move(default_result)); } if (!td::contains(autologin_domains_, r_url.ok().host_)) { - return promise.set_value(std::move(link)); + return promise.set_value(std::move(default_result)); } if (autologin_update_time_ < Time::now() - 10000) { auto query_promise = PromiseCreator::lambda([link = std::move(link), promise = std::move(promise)]( Result> &&result) mutable { if (result.is_error()) { - return promise.set_value(std::move(link)); + return promise.set_value(td_api::make_object(link, false)); } - send_closure(G()->config_manager(), &ConfigManager::get_external_link, std::move(link), std::move(promise)); + send_closure(G()->config_manager(), &ConfigManager::get_external_link_info, std::move(link), std::move(promise)); }); return get_app_config(std::move(query_promise)); } if (autologin_token_.empty()) { - return promise.set_value(std::move(link)); + return promise.set_value(std::move(default_result)); } auto url = r_url.move_as_ok(); @@ -1018,7 +1019,7 @@ void ConfigManager::get_external_link(string &&link, Promise &&promise) url.query_ = PSTRING() << path << parameters << added_parameter << hash; - promise.set_value(url.get_url()); + promise.set_value(td_api::make_object(url.get_url(), false)); } void ConfigManager::get_content_settings(Promise &&promise) { diff --git a/td/telegram/ConfigManager.h b/td/telegram/ConfigManager.h index ecc3569c6..39d110496 100644 --- a/td/telegram/ConfigManager.h +++ b/td/telegram/ConfigManager.h @@ -93,7 +93,7 @@ class ConfigManager : public NetQueryCallback { void get_app_config(Promise> &&promise); - void get_external_link(string &&link, Promise &&promise); + void get_external_link_info(string &&link, Promise> &&promise); void get_content_settings(Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 3baa18099..01a7ea4bb 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5472,19 +5472,19 @@ void Td::on_request(uint64 id, const td_api::openMessageContent &request) { id, messages_manager_->open_message_content({DialogId(request.chat_id_), MessageId(request.message_id_)})); } +void Td::on_request(uint64 id, td_api::getExternalLinkInfo &request) { + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.link_); + CREATE_REQUEST_PROMISE(); + send_closure_later(G()->config_manager(), &ConfigManager::get_external_link_info, std::move(request.link_), + std::move(promise)); +} + void Td::on_request(uint64 id, td_api::getExternalLink &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.link_); CREATE_REQUEST_PROMISE(); - auto query_promise = [promise = std::move(promise)](Result &&result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(td_api::make_object(result.ok())); - } - }; - send_closure_later(G()->config_manager(), &ConfigManager::get_external_link, std::move(request.link_), - std::move(query_promise)); + promise.set_value(td_api::make_object(request.link_)); } void Td::on_request(uint64 id, const td_api::getChatHistory &request) { diff --git a/td/telegram/Td.h b/td/telegram/Td.h index adcc33dda..47d4b4516 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -577,6 +577,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::openMessageContent &request); + void on_request(uint64 id, td_api::getExternalLinkInfo &request); + void on_request(uint64 id, td_api::getExternalLink &request); void on_request(uint64 id, const td_api::getChatHistory &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 3a355b1f3..9609df64d 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -3923,9 +3923,12 @@ class CliClient final : public Actor { string message_id; get_args(args, chat_id, message_id); send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id))); - } else if (op == "gel") { + } else if (op == "geli") { string link = args; - send_request(td_api::make_object(link)); + send_request(td_api::make_object(link)); + } else if (op == "gel" || op == "gelw") { + string link = args; + send_request(td_api::make_object(link, op == "gelw")); } else if (op == "racm") { string chat_id = args; send_request(td_api::make_object(as_chat_id(chat_id))); From 62c9890bcfc65a1d36f3e3361092c0a784456da9 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 16 Mar 2021 01:29:54 +0300 Subject: [PATCH 061/281] Support url_auth_domains. --- td/telegram/ConfigManager.cpp | 29 +++++++++++++++++ td/telegram/ConfigManager.h | 1 + td/telegram/MessagesManager.cpp | 56 ++++++++++++++++++++++++--------- td/telegram/MessagesManager.h | 5 +++ td/telegram/Td.cpp | 2 +- 5 files changed, 78 insertions(+), 15 deletions(-) diff --git a/td/telegram/ConfigManager.cpp b/td/telegram/ConfigManager.cpp index f583ac9cc..e7ab6ed53 100644 --- a/td/telegram/ConfigManager.cpp +++ b/td/telegram/ConfigManager.cpp @@ -11,6 +11,7 @@ #include "td/telegram/Global.h" #include "td/telegram/JsonValue.h" #include "td/telegram/logevent/LogEvent.h" +#include "td/telegram/MessagesManager.h" #include "td/telegram/net/AuthDataShared.h" #include "td/telegram/net/ConnectionCreator.h" #include "td/telegram/net/DcId.h" @@ -891,6 +892,8 @@ void ConfigManager::start_up() { autologin_update_time_ = Time::now() - 365 * 86400; autologin_domains_ = full_split(G()->td_db()->get_binlog_pmc()->get("autologin_domains"), '\xFF'); + + url_auth_domains_ = full_split(G()->td_db()->get_binlog_pmc()->get("url_auth_domains"), '\xFF'); } ActorShared<> ConfigManager::create_reference() { @@ -979,6 +982,10 @@ void ConfigManager::get_external_link_info(string &&link, Promisemessages_manager(), &MessagesManager::get_link_login_url_info, link, std::move(promise)); + return; + } return promise.set_value(std::move(default_result)); } @@ -1525,6 +1532,9 @@ void ConfigManager::process_app_config(tl_object_ptr &c autologin_domains_.clear(); autologin_update_time_ = Time::now(); + auto old_url_auth_domains = std::move(url_auth_domains_); + url_auth_domains_.clear(); + vector> new_values; string ignored_restriction_reasons; vector dice_emojis; @@ -1715,6 +1725,22 @@ void ConfigManager::process_app_config(tl_object_ptr &c } continue; } + if (key == "url_auth_domains") { + if (value->get_id() == telegram_api::jsonArray::ID) { + auto domains = std::move(static_cast(value)->value_); + for (auto &domain : domains) { + CHECK(domain != nullptr); + if (domain->get_id() == telegram_api::jsonString::ID) { + url_auth_domains_.push_back(std::move(static_cast(domain.get())->value_)); + } else { + LOG(ERROR) << "Receive unexpected url auth domain " << to_string(domain); + } + } + } else { + LOG(ERROR) << "Receive unexpected url_auth_domains " << to_string(*value); + } + continue; + } new_values.push_back(std::move(key_value)); } @@ -1726,6 +1752,9 @@ void ConfigManager::process_app_config(tl_object_ptr &c if (autologin_domains_ != old_autologin_domains) { G()->td_db()->get_binlog_pmc()->set("autologin_domains", implode(autologin_domains_, '\xFF')); } + if (url_auth_domains_ != old_url_auth_domains) { + G()->td_db()->get_binlog_pmc()->set("url_auth_domains", implode(url_auth_domains_, '\xFF')); + } ConfigShared &shared_config = G()->shared_config(); diff --git a/td/telegram/ConfigManager.h b/td/telegram/ConfigManager.h index 39d110496..978268113 100644 --- a/td/telegram/ConfigManager.h +++ b/td/telegram/ConfigManager.h @@ -119,6 +119,7 @@ class ConfigManager : public NetQueryCallback { string autologin_token_; vector autologin_domains_; double autologin_update_time_ = 0.0; + vector url_auth_domains_; FloodControlStrict lazy_request_flood_control_; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 7da028503..bd3546da6 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -4616,12 +4616,18 @@ class RequestUrlAuthQuery : public Td::ResultHandler { void send(string url, DialogId dialog_id, MessageId message_id, int32 button_id) { url_ = std::move(url); - dialog_id_ = dialog_id; - auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); - CHECK(input_peer != nullptr); - int32 flags = telegram_api::messages_requestUrlAuth::PEER_MASK; + int32 flags = 0; + tl_object_ptr input_peer; + if (dialog_id.is_valid()) { + dialog_id_ = dialog_id; + input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + CHECK(input_peer != nullptr); + flags |= telegram_api::messages_requestUrlAuth::PEER_MASK; + } else { + flags |= telegram_api::messages_requestUrlAuth::URL_MASK; + } send_query(G()->net_query_creator().create(telegram_api::messages_requestUrlAuth( - flags, std::move(input_peer), message_id.get_server_message_id().get(), button_id, string()))); + flags, std::move(input_peer), message_id.get_server_message_id().get(), button_id, url_))); } void on_result(uint64 id, BufferSlice packet) override { @@ -4659,7 +4665,8 @@ class RequestUrlAuthQuery : public Td::ResultHandler { } void on_error(uint64 id, Status status) override { - if (!td->messages_manager_->on_get_dialog_error(dialog_id_, status, "RequestUrlAuthQuery")) { + if (!dialog_id_.is_valid() || + !td->messages_manager_->on_get_dialog_error(dialog_id_, status, "RequestUrlAuthQuery")) { LOG(INFO) << "RequestUrlAuthQuery returned " << status; } promise_.set_value(td_api::make_object(url_, false)); @@ -4677,16 +4684,21 @@ class AcceptUrlAuthQuery : public Td::ResultHandler { void send(string url, DialogId dialog_id, MessageId message_id, int32 button_id, bool allow_write_access) { url_ = std::move(url); - dialog_id_ = dialog_id; - auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); - CHECK(input_peer != nullptr); - int32 flags = telegram_api::messages_acceptUrlAuth::PEER_MASK; + int32 flags = 0; + tl_object_ptr input_peer; + if (dialog_id.is_valid()) { + dialog_id_ = dialog_id; + input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + CHECK(input_peer != nullptr); + flags |= telegram_api::messages_acceptUrlAuth::PEER_MASK; + } else { + flags |= telegram_api::messages_acceptUrlAuth::URL_MASK; + } if (allow_write_access) { flags |= telegram_api::messages_acceptUrlAuth::WRITE_ALLOWED_MASK; } - send_query(G()->net_query_creator().create( - telegram_api::messages_acceptUrlAuth(flags, false /*ignored*/, std::move(input_peer), - message_id.get_server_message_id().get(), button_id, string()))); + send_query(G()->net_query_creator().create(telegram_api::messages_acceptUrlAuth( + flags, false /*ignored*/, std::move(input_peer), message_id.get_server_message_id().get(), button_id, url_))); } void on_result(uint64 id, BufferSlice packet) override { @@ -4713,7 +4725,8 @@ class AcceptUrlAuthQuery : public Td::ResultHandler { } void on_error(uint64 id, Status status) override { - if (!td->messages_manager_->on_get_dialog_error(dialog_id_, status, "AcceptUrlAuthQuery")) { + if (!dialog_id_.is_valid() || + !td->messages_manager_->on_get_dialog_error(dialog_id_, status, "AcceptUrlAuthQuery")) { LOG(INFO) << "AcceptUrlAuthQuery returned " << status; } promise_.set_error(std::move(status)); @@ -8630,6 +8643,21 @@ void MessagesManager::get_login_url(DialogId dialog_id, MessageId message_id, in ->send(r_url.move_as_ok(), dialog_id, message_id, button_id, allow_write_access); } +void MessagesManager::get_link_login_url_info(const string &url, + Promise> &&promise) { + if (G()->close_flag()) { + return promise.set_value(td_api::make_object(url, false)); + } + + td_->create_handler(std::move(promise))->send(url, DialogId(), MessageId(), 0); +} + +void MessagesManager::get_link_login_url(const string &url, bool allow_write_access, + Promise> &&promise) { + td_->create_handler(std::move(promise)) + ->send(url, DialogId(), MessageId(), 0, allow_write_access); +} + void MessagesManager::load_secret_thumbnail(FileId thumbnail_file_id) { class Callback : public FileManager::DownloadCallback { public: diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index cc75e6fcf..4275d8aed 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -806,6 +806,11 @@ class MessagesManager : public Actor { void get_login_url(DialogId dialog_id, MessageId message_id, int32 button_id, bool allow_write_access, Promise> &&promise); + void get_link_login_url_info(const string &url, Promise> &&promise); + + void get_link_login_url(const string &url, bool allow_write_access, + Promise> &&promise); + void on_authorization_success(); void before_get_difference(); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 01a7ea4bb..daf709ffa 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5484,7 +5484,7 @@ void Td::on_request(uint64 id, td_api::getExternalLink &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.link_); CREATE_REQUEST_PROMISE(); - promise.set_value(td_api::make_object(request.link_)); + messages_manager_->get_link_login_url(request.link_, request.allow_write_access_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::getChatHistory &request) { From d5f02b006600724c58edb86d356c494e9d30d1d1 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 16 Mar 2021 14:35:32 +0300 Subject: [PATCH 062/281] Avoid int64 multiplication. --- tdutils/test/bitmask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tdutils/test/bitmask.cpp b/tdutils/test/bitmask.cpp index 7e998f1af..1c7a5280b 100644 --- a/tdutils/test/bitmask.cpp +++ b/tdutils/test/bitmask.cpp @@ -131,7 +131,7 @@ class RangeSet { } return res; } - int64 get_ready_parts(int64 offset_part, int64 part_size) const { + int64 get_ready_parts(int64 offset_part, int32 part_size) const { auto offset = offset_part * part_size; auto it = find(offset); if (it == ranges_.end()) { From 3bcf4bb61ac2a38edf003c9c824811842c2e9a1c Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 16 Mar 2021 17:17:00 +0300 Subject: [PATCH 063/281] Get group call from the server before first usage if appropriate. --- td/telegram/GroupCallManager.cpp | 100 +++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 6 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 119c890ad..23ef3ceb5 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -2236,10 +2236,28 @@ void GroupCallManager::process_group_call_after_join_requests(InputGroupCallId i } void GroupCallManager::set_group_call_title(GroupCallId group_call_id, string title, Promise &&promise) { + if (G()->close_flag()) { + return promise.set_error(Status::Error(500, "Request aborted")); + } + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); auto *group_call = get_group_call(input_group_call_id); - if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || !group_call->can_be_managed) { + if (group_call == nullptr || !group_call->is_inited) { + reload_group_call( + input_group_call_id, + PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, title, promise = std::move(promise)]( + Result> &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &GroupCallManager::set_group_call_title, group_call_id, std::move(title), + std::move(promise)); + } + })); + return; + } + if (!group_call->is_active || !group_call->can_be_managed) { return promise.set_error(Status::Error(400, "Can't change group call title")); } @@ -2299,11 +2317,28 @@ void GroupCallManager::on_edit_group_call_title(InputGroupCallId input_group_cal void GroupCallManager::toggle_group_call_mute_new_participants(GroupCallId group_call_id, bool mute_new_participants, Promise &&promise) { + if (G()->close_flag()) { + return promise.set_error(Status::Error(500, "Request aborted")); + } + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); auto *group_call = get_group_call(input_group_call_id); - if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || !group_call->can_be_managed || - !group_call->allowed_change_mute_new_participants) { + if (group_call == nullptr || !group_call->is_inited) { + reload_group_call(input_group_call_id, + PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, mute_new_participants, + promise = std::move(promise)]( + Result> &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &GroupCallManager::toggle_group_call_mute_new_participants, + group_call_id, mute_new_participants, std::move(promise)); + } + })); + return; + } + if (!group_call->is_active || !group_call->can_be_managed || !group_call->allowed_change_mute_new_participants) { return promise.set_error(Status::Error(400, "Can't change mute_new_participant setting")); } @@ -2372,10 +2407,27 @@ void GroupCallManager::on_toggle_group_call_mute_new_participants(InputGroupCall } void GroupCallManager::revoke_group_call_invite_link(GroupCallId group_call_id, Promise &&promise) { + if (G()->close_flag()) { + return promise.set_error(Status::Error(500, "Request aborted")); + } + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); auto *group_call = get_group_call(input_group_call_id); - if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || !group_call->can_be_managed) { + if (group_call == nullptr || !group_call->is_inited) { + reload_group_call(input_group_call_id, + PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, promise = std::move(promise)]( + Result> &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &GroupCallManager::revoke_group_call_invite_link, group_call_id, + std::move(promise)); + } + })); + return; + } + if (!group_call->is_active || !group_call->can_be_managed) { return promise.set_error(Status::Error(400, "Can't reset invite hash in the group call")); } @@ -2411,10 +2463,28 @@ void GroupCallManager::invite_group_call_participants(GroupCallId group_call_id, void GroupCallManager::get_group_call_invite_link(GroupCallId group_call_id, bool can_self_unmute, Promise &&promise) { + if (G()->close_flag()) { + return promise.set_error(Status::Error(500, "Request aborted")); + } + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); auto *group_call = get_group_call(input_group_call_id); - if (group_call == nullptr || !group_call->is_inited || !group_call->is_active) { + if (group_call == nullptr || !group_call->is_inited) { + reload_group_call(input_group_call_id, + PromiseCreator::lambda( + [actor_id = actor_id(this), group_call_id, can_self_unmute, promise = std::move(promise)]( + Result> &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &GroupCallManager::get_group_call_invite_link, group_call_id, + can_self_unmute, std::move(promise)); + } + })); + return; + } + if (!group_call->is_active) { return promise.set_error(Status::Error(400, "Can't get group call invite link")); } @@ -2427,10 +2497,28 @@ void GroupCallManager::get_group_call_invite_link(GroupCallId group_call_id, boo void GroupCallManager::toggle_group_call_recording(GroupCallId group_call_id, bool is_enabled, string title, Promise &&promise) { + if (G()->close_flag()) { + return promise.set_error(Status::Error(500, "Request aborted")); + } + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); auto *group_call = get_group_call(input_group_call_id); - if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || !group_call->can_be_managed) { + if (group_call == nullptr || !group_call->is_inited) { + reload_group_call(input_group_call_id, + PromiseCreator::lambda( + [actor_id = actor_id(this), group_call_id, is_enabled, title, promise = std::move(promise)]( + Result> &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &GroupCallManager::toggle_group_call_recording, group_call_id, + is_enabled, std::move(title), std::move(promise)); + } + })); + return; + } + if (!group_call->is_active || !group_call->can_be_managed) { return promise.set_error(Status::Error(400, "Can't manage group call recording")); } From 582f033a098dee4a6290c9127dfb6ed6ba8e0747 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 16 Mar 2021 17:20:53 +0300 Subject: [PATCH 064/281] Update limit for group call recording titlw length. --- td/generate/scheme/td_api.tl | 2 +- td/telegram/GroupCallManager.cpp | 2 +- td/telegram/GroupCallManager.h | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 7f969af75..aa7dcf8bb 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4602,7 +4602,7 @@ inviteGroupCallParticipants group_call_id:int32 user_ids:vector = Ok; //@can_self_unmute Pass true if the invite_link should contain an invite hash, passing which to joinGroupCall would allow the invited user to unmute themself. Requires groupCall.can_be_managed group call flag getGroupCallInviteLink group_call_id:int32 can_self_unmute:Bool = HttpUrl; -//@description Starts recording of a group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title Group call recording title; 0-128 characters +//@description Starts recording of a group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title Group call recording title; 0-64 characters startGroupCallRecording group_call_id:int32 title:string = Ok; //@description Ends recording of a group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 23ef3ceb5..7b2b01cd1 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -2522,7 +2522,7 @@ void GroupCallManager::toggle_group_call_recording(GroupCallId group_call_id, bo return promise.set_error(Status::Error(400, "Can't manage group call recording")); } - title = clean_name(title, MAX_RECORD_TITLE_LENGTH); + title = clean_name(title, MAX_TITLE_LENGTH); if (is_enabled == get_group_call_has_recording(group_call)) { return promise.set_value(Unit()); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index f648d4760..251894be5 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -121,8 +121,7 @@ class GroupCallManager : public Actor { static constexpr int32 RECENT_SPEAKER_TIMEOUT = 60 * 60; static constexpr int32 UPDATE_GROUP_CALL_PARTICIPANT_ORDER_TIMEOUT = 10; static constexpr int32 CHECK_GROUP_CALL_IS_JOINED_TIMEOUT = 10; - static constexpr size_t MAX_TITLE_LENGTH = 64; // server side limit for group call title length - static constexpr size_t MAX_RECORD_TITLE_LENGTH = 128; // server side limit for group call record title length + static constexpr size_t MAX_TITLE_LENGTH = 64; // server side limit for group call/call record title length void tear_down() override; From d06025d40d8a4c49e102669347327c9cd9241fac Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 16 Mar 2021 17:40:46 +0300 Subject: [PATCH 065/281] Disable sanitizer for 32-bit builds: https://github.com/tdlib/td/issues/1447. --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7ad2117ea..ed1893fd3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -49,7 +49,7 @@ if (NOT CMAKE_CROSSCOMPILING OR EMSCRIPTEN) add_executable(test-tdutils EXCLUDE_FROM_ALL ${TESTS_MAIN} ${TDUTILS_TEST_SOURCE}) add_executable(test-online EXCLUDE_FROM_ALL online.cpp) add_executable(run_all_tests ${TESTS_MAIN} ${TD_TEST_SOURCE}) - if (CLANG AND NOT CYGWIN AND NOT EMSCRIPTEN AND NOT (CMAKE_HOST_SYSTEM_NAME MATCHES "OpenBSD")) + if (CLANG AND NOT CYGWIN AND NOT EMSCRIPTEN AND NOT (CMAKE_HOST_SYSTEM_NAME MATCHES "OpenBSD") AND NOT (CMAKE_SIZEOF_VOID_P EQUAL 4)) target_compile_options(test-tdutils PUBLIC -fsanitize=undefined -fno-sanitize=vptr) target_compile_options(run_all_tests PUBLIC -fsanitize=undefined -fno-sanitize=vptr) target_compile_options(test-online PUBLIC -fsanitize=undefined -fno-sanitize=vptr) From c67a8cc5f97323b42d7f91310786ab1b77ff3679 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 16 Mar 2021 18:07:17 +0300 Subject: [PATCH 066/281] Unify variable names and ensure that groupCallParticipant's chat is created. --- td/telegram/GroupCallManager.cpp | 81 +++++++++++++++++++------------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 7b2b01cd1..72efc87be 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1348,6 +1348,13 @@ void GroupCallManager::on_update_group_call_participants( auto group_call = get_group_call(input_group_call_id); for (auto &group_call_participant : participants) { GroupCallParticipant participant(group_call_participant); + if (!participant.is_valid()) { + LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); + continue; + } + if (participant.dialog_id.get_type() != DialogType::User) { + td_->messages_manager_->force_create_dialog(participant.dialog_id, "on_update_group_call_participants 1"); + } if (participant.joined_date == 0) { diff--; remove_recent_group_call_speaker(input_group_call_id, participant.dialog_id); @@ -1393,6 +1400,13 @@ void GroupCallManager::on_update_group_call_participants( vector version_updates; for (auto &group_call_participant : participants) { GroupCallParticipant participant(group_call_participant); + if (!participant.is_valid()) { + LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); + continue; + } + if (participant.dialog_id.get_type() != DialogType::User) { + td_->messages_manager_->force_create_dialog(participant.dialog_id, "on_update_group_call_participants 2"); + } if (participant.is_min && participant.joined_date != 0) { auto old_participant = get_group_call_participant(group_call_participants, participant.dialog_id); if (old_participant == nullptr) { @@ -1471,16 +1485,14 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup if (version == group_call->version + 1) { group_call->version = version; for (auto &participant : participants) { - GroupCallParticipant group_call_participant(participant); - if (group_call_participant.is_self && group_call->is_joined && - (group_call_participant.joined_date == 0) == - (group_call_participant.audio_source == group_call->audio_source)) { + if (participant.is_self && group_call->is_joined && + (participant.joined_date == 0) == (participant.audio_source == group_call->audio_source)) { is_left = true; - if (group_call_participant.joined_date != 0) { + if (participant.joined_date != 0) { need_rejoin = false; } } - diff += process_group_call_participant(input_group_call_id, std::move(group_call_participant)); + diff += process_group_call_participant(input_group_call_id, std::move(participant)); } pending_version_updates.erase(it); } else if (!group_call->syncing_participants) { @@ -1592,14 +1604,17 @@ void GroupCallManager::process_group_call_participants( InputGroupCallId input_group_call_id, vector> &&participants, bool is_load, bool is_sync) { if (!need_group_call_participants(input_group_call_id)) { - for (auto &participant : participants) { - GroupCallParticipant group_call_participant(participant); - if (!group_call_participant.is_valid()) { - LOG(ERROR) << "Receive invalid " << to_string(participant); + for (auto &group_call_participant : participants) { + GroupCallParticipant participant(group_call_participant); + if (!participant.is_valid()) { + LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); continue; } + if (participant.dialog_id.get_type() != DialogType::User) { + td_->messages_manager_->force_create_dialog(participant.dialog_id, "process_group_call_participants"); + } - on_participant_speaking_in_group_call(input_group_call_id, group_call_participant); + on_participant_speaking_in_group_call(input_group_call_id, participant); } return; } @@ -1617,18 +1632,21 @@ void GroupCallManager::process_group_call_participants( auto min_order = GroupCallParticipantOrder::max(); bool can_manage = can_manage_group_call(input_group_call_id); - for (auto &participant : participants) { - GroupCallParticipant group_call_participant(participant); - if (!group_call_participant.is_valid()) { - LOG(ERROR) << "Receive invalid " << to_string(participant); + for (auto &group_call_participant : participants) { + GroupCallParticipant participant(group_call_participant); + if (!participant.is_valid()) { + LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); continue; } - if (group_call_participant.is_min) { - LOG(ERROR) << "Receive unexpected min " << to_string(participant); + if (participant.is_min) { + LOG(ERROR) << "Receive unexpected min " << to_string(group_call_participant); continue; } + if (participant.dialog_id.get_type() != DialogType::User) { + td_->messages_manager_->force_create_dialog(participant.dialog_id, "process_group_call_participants"); + } - auto real_order = group_call_participant.get_real_order(can_manage); + auto real_order = participant.get_real_order(can_manage); if (real_order > min_order) { LOG(ERROR) << "Receive call participant with order " << real_order << " after call participant with order " << min_order; @@ -1636,9 +1654,9 @@ void GroupCallManager::process_group_call_participants( min_order = real_order; } if (is_sync) { - old_participant_dialog_ids.erase(group_call_participant.dialog_id); + old_participant_dialog_ids.erase(participant.dialog_id); } - process_group_call_participant(input_group_call_id, std::move(group_call_participant)); + process_group_call_participant(input_group_call_id, std::move(participant)); } if (is_sync) { auto participants_it = group_call_participants_.find(input_group_call_id); @@ -1986,20 +2004,19 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di } } if (group_call->is_inited && have_as_dialog_id) { - GroupCallParticipant group_call_participant; - group_call_participant.is_self = true; - group_call_participant.dialog_id = as_dialog_id; - group_call_participant.about = td_->contacts_manager_->get_dialog_about(group_call_participant.dialog_id); - group_call_participant.audio_source = audio_source; - group_call_participant.joined_date = G()->unix_time(); + GroupCallParticipant participant; + participant.is_self = true; + participant.dialog_id = as_dialog_id; + participant.about = td_->contacts_manager_->get_dialog_about(participant.dialog_id); + participant.audio_source = audio_source; + participant.joined_date = G()->unix_time(); // if can_self_unmute has never been inited from self-participant, // it contains reasonable default "!call.mute_new_participants || call.can_be_managed" - group_call_participant.server_is_muted_by_admin = - !group_call->can_self_unmute && !can_manage_group_call(input_group_call_id); - group_call_participant.server_is_muted_by_themselves = is_muted && !group_call_participant.server_is_muted_by_admin; - group_call_participant.is_just_joined = !is_rejoin; - group_call_participant.is_fake = true; - int diff = process_group_call_participant(input_group_call_id, std::move(group_call_participant)); + participant.server_is_muted_by_admin = !group_call->can_self_unmute && !can_manage_group_call(input_group_call_id); + participant.server_is_muted_by_themselves = is_muted && !participant.server_is_muted_by_admin; + participant.is_just_joined = !is_rejoin; + participant.is_fake = true; + int diff = process_group_call_participant(input_group_call_id, std::move(participant)); if (diff != 0) { CHECK(diff == 1); group_call->participant_count++; From 2e447b3cea487189c0a47082f07c268c17a1dc6e Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 16 Mar 2021 18:15:10 +0300 Subject: [PATCH 067/281] Don't process after_join requets if need rejoin. --- td/telegram/GroupCallManager.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 72efc87be..934e34651 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -2898,13 +2898,13 @@ void GroupCallManager::toggle_group_call_participant_is_hand_raised(GroupCallId return promise.set_value(Unit()); } - if (is_hand_raised) { - if (!participant->is_self) { + if (!participant->is_self) { + if (is_hand_raised) { return promise.set_error(Status::Error(400, "Can't raise others hand")); - } - } else { - if (!can_manage_group_call(input_group_call_id)) { - return promise.set_error(Status::Error(400, "Have not enough rights in the group call")); + } else { + if (!can_manage_group_call(input_group_call_id)) { + return promise.set_error(Status::Error(400, "Have not enough rights in the group call")); + } } } @@ -3052,7 +3052,9 @@ void GroupCallManager::on_group_call_left_impl(GroupCall *group_call, bool need_ check_group_call_is_joined_timeout_.cancel_timeout(group_call->group_call_id.get()); auto input_group_call_id = get_input_group_call_id(group_call->group_call_id).ok(); try_clear_group_call_participants(input_group_call_id); - process_group_call_after_join_requests(input_group_call_id, "on_group_call_left_impl"); + if (!group_call->need_rejoin) { + process_group_call_after_join_requests(input_group_call_id, "on_group_call_left_impl"); + } } void GroupCallManager::discard_group_call(GroupCallId group_call_id, Promise &&promise) { From ebeaf7f90e733441f417a52dee7920f6b76c8f71 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Tue, 16 Mar 2021 16:35:13 +0100 Subject: [PATCH 068/281] Update SplitSource.php --- SplitSource.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SplitSource.php b/SplitSource.php index 2c5da8fa6..2b65aaa6f 100644 --- a/SplitSource.php +++ b/SplitSource.php @@ -278,12 +278,15 @@ function split_file($file, $chunks, $undo) { 'animations_manager[_(-][^.]|AnimationsManager[^;>]' => "AnimationsManager", 'audios_manager[_(-][^.]|AudiosManager' => "AudiosManager", 'auth_manager[_(-][^.]|AuthManager' => 'AuthManager', + 'background_manager[_(-][^.]|BackgroundManager' => "BackgroundManager", 'ConfigShared|shared_config[(]' => 'ConfigShared', 'contacts_manager[_(-][^.]|ContactsManager([^ ;.]| [^*])' => 'ContactsManager', + 'country_info_manager[_(-][^.]|CountryInfoManager' => 'CountryInfoManager', 'documents_manager[_(-][^.]|DocumentsManager' => "DocumentsManager", 'file_reference_manager[_(-][^.]|FileReferenceManager|file_references[)]' => 'FileReferenceManager', 'file_manager[_(-][^.]|FileManager([^ ;.]| [^*])|update_file[)]' => 'files/FileManager', 'G[(][)]|Global[^A-Za-z]' => 'Global', + 'group_call_manager[_(-][^.]|GroupCallManager' => 'GroupCallManager', 'HashtagHints' => 'HashtagHints', 'inline_queries_manager[_(-][^.]|InlineQueriesManager' => 'InlineQueriesManager', 'language_pack_manager[_(-][^.]|LanguagePackManager' => 'LanguagePackManager', @@ -291,6 +294,8 @@ function split_file($file, $chunks, $undo) { 'MessageCopyOptions' => 'MessageCopyOptions', 'messages_manager[_(-][^.]|MessagesManager' => 'MessagesManager', 'notification_manager[_(-][^.]|NotificationManager|notifications[)]' => 'NotificationManager', + 'phone_number_manager[_(-][^.]|PhoneNumberManager' => "PhoneNumberManager", + 'poll_manager[_(-][^.]|PollManager' => "PollManager", 'PublicDialogType|get_public_dialog_type' => 'PublicDialogType', 'SecretChatActor' => 'SecretChatActor', 'secret_chats_manager[_(-][^.]|SecretChatsManager' => 'SecretChatsManager', From 93a2cf055644e74c969e32f79f1ac4a2c7103e3f Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 16 Mar 2021 23:23:05 +0300 Subject: [PATCH 069/281] Fix updating participant_id_to_group_call_id_. --- td/telegram/GroupCallManager.cpp | 36 ++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 934e34651..d68f1e61f 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1671,19 +1671,22 @@ void GroupCallManager::process_group_call_participants( continue; } - // not synced user, needs to be deleted - if (participant.order.is_valid()) { - CHECK(participant.order >= participants_it->second->min_order); - if (participant.is_self) { - if (participant.order != min_order) { - participant.order = min_order; - send_update_group_call_participant(input_group_call_id, participant); - } - } else { - participant.order = GroupCallParticipantOrder(); + if (participant.is_self) { + if (participant.order != min_order) { + participant.order = min_order; send_update_group_call_participant(input_group_call_id, participant); } + ++participant_it; + continue; } + + // not synced user and not self, needs to be deleted + if (participant.order.is_valid()) { + CHECK(participant.order >= participants_it->second->min_order); + participant.order = GroupCallParticipantOrder(); + send_update_group_call_participant(input_group_call_id, participant); + } + on_remove_group_call_participant(input_group_call_id, participant.dialog_id); participant_it = group_participants.erase(participant_it); } if (participants_it->second->min_order < min_order) { @@ -1773,12 +1776,17 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (old_participant.order.is_valid()) { send_update_group_call_participant(input_group_call_id, participant); } - on_remove_group_call_participant(input_group_call_id, participant.dialog_id); - remove_recent_group_call_speaker(input_group_call_id, participant.dialog_id); + on_remove_group_call_participant(input_group_call_id, old_participant.dialog_id); + remove_recent_group_call_speaker(input_group_call_id, old_participant.dialog_id); participants->participants.erase(participants->participants.begin() + i); return -1; } + if (old_participant.dialog_id != participant.dialog_id) { + on_remove_group_call_participant(input_group_call_id, old_participant.dialog_id); + on_add_group_call_participant(input_group_call_id, participant.dialog_id); + } + participant.update_from(old_participant); participant.is_just_joined = false; @@ -1822,7 +1830,9 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou void GroupCallManager::on_add_group_call_participant(InputGroupCallId input_group_call_id, DialogId participant_dialog_id) { - participant_id_to_group_call_id_[participant_dialog_id].push_back(input_group_call_id); + auto &participants = participant_id_to_group_call_id_[participant_dialog_id]; + CHECK(!td::contains(participants, input_group_call_id)); + participants.push_back(input_group_call_id); } void GroupCallManager::on_remove_group_call_participant(InputGroupCallId input_group_call_id, From 23b781834eb10ab9b3e1a0adc217579022d3300b Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 17 Mar 2021 02:56:33 +0300 Subject: [PATCH 070/281] Fix updating recent speakers in joined as chats voice chats. --- td/telegram/GroupCallManager.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index d68f1e61f..b3e9e3a75 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -644,6 +644,7 @@ struct GroupCallManager::GroupCall { int32 joined_date = 0; int32 record_start_date = 0; DcId stream_dc_id; + DialogId as_dialog_id; int32 version = -1; int32 title_version = -1; @@ -683,6 +684,7 @@ struct GroupCallManager::PendingJoinRequest { NetQueryRef query_ref; uint64 generation = 0; int32 audio_source = 0; + DialogId as_dialog_id; Promise> promise; }; @@ -812,7 +814,8 @@ void GroupCallManager::on_send_speaking_action_timeout(GroupCallId group_call_id return; } - on_user_speaking_in_group_call(group_call_id, DialogId(td_->contacts_manager_->get_my_id()), G()->unix_time()); + CHECK(group_call->as_dialog_id.is_valid()); + on_user_speaking_in_group_call(group_call_id, group_call->as_dialog_id, G()->unix_time()); pending_send_speaking_action_timeout_.add_timeout_in(group_call_id.get(), 4.0); @@ -1994,6 +1997,7 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di request = make_unique(); request->generation = generation; request->audio_source = audio_source; + request->as_dialog_id = as_dialog_id; request->promise = std::move(promise); auto query_promise = @@ -2203,6 +2207,7 @@ bool GroupCallManager::on_join_group_call_response(InputGroupCallId input_group_ group_call->is_being_left = false; group_call->joined_date = G()->unix_time(); group_call->audio_source = it->second->audio_source; + group_call->as_dialog_id = it->second->as_dialog_id; it->second->promise.set_value(result.move_as_ok()); if (group_call->audio_source != 0) { check_group_call_is_joined_timeout_.set_timeout_in(group_call->group_call_id.get(), @@ -3097,7 +3102,7 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ if (group_call != nullptr) { update_group_call_participant_order_timeout_.cancel_timeout(group_call->group_call_id.get()); } - remove_recent_group_call_speaker(input_group_call_id, DialogId(td_->contacts_manager_->get_my_id())); + remove_recent_group_call_speaker(input_group_call_id, group_call->as_dialog_id); auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it == group_call_participants_.end()) { @@ -3207,6 +3212,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrneed_syncing_participants; call.loaded_all_participants = group_call->loaded_all_participants; call.audio_source = group_call->audio_source; + call.as_dialog_id = group_call->as_dialog_id; *group_call = std::move(call); need_update = true; From 2162fd62649458509b6e8369bfec65258a2e7afd Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 17 Mar 2021 03:16:34 +0300 Subject: [PATCH 071/281] Postpone checkGroupCall after receiving a stream segment. --- td/telegram/GroupCallManager.cpp | 19 ++++++++++++++++++- td/telegram/GroupCallManager.h | 3 +++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index b3e9e3a75..12452434f 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1895,10 +1895,27 @@ void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id, return promise.set_error(Status::Error(400, "Group call can't be streamed")); } - td_->create_handler(std::move(promise)) + auto query_promise = PromiseCreator::lambda( + [actor_id = actor_id(this), input_group_call_id, promise = std::move(promise)](Result &&result) mutable { + send_closure(actor_id, &GroupCallManager::finish_get_group_call_stream_segment, input_group_call_id, + std::move(result), std::move(promise)); + }); + td_->create_handler(std::move(query_promise)) ->send(input_group_call_id, group_call->stream_dc_id, time_offset, scale); } +void GroupCallManager::finish_get_group_call_stream_segment(InputGroupCallId input_group_call_id, + Result &&result, Promise &&promise) { + auto *group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr); + if (group_call->is_inited && check_group_call_is_joined_timeout_.has_timeout(group_call->group_call_id.get())) { + check_group_call_is_joined_timeout_.set_timeout_in(group_call->group_call_id.get(), + CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); + } + + promise.set_result(std::move(result)); +} + void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, td_api::object_ptr &&payload, int32 audio_source, bool is_muted, const string &invite_hash, diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 251894be5..6907bac9c 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -164,6 +164,9 @@ class GroupCallManager : public Actor { void finish_get_group_call(InputGroupCallId input_group_call_id, Result> &&result); + void finish_get_group_call_stream_segment(InputGroupCallId input_group_call_id, Result &&result, + Promise &&promise); + void finish_check_group_call_is_joined(InputGroupCallId input_group_call_id, int32 audio_source, Result &&result); From 7e45fc3949c036a2f2b55278750bc7e85a687eab Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 17 Mar 2021 03:28:07 +0300 Subject: [PATCH 072/281] Add more close_flag checks. --- td/telegram/GroupCallManager.cpp | 41 +++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 12452434f..7a9941b2d 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -778,10 +778,6 @@ void GroupCallManager::on_check_group_call_is_joined_timeout(GroupCallId group_c auto promise = PromiseCreator::lambda( [actor_id = actor_id(this), input_group_call_id, audio_source](Result &&result) mutable { - if (result.is_error() && result.error().message() == "GROUPCALL_JOIN_MISSING") { - send_closure(actor_id, &GroupCallManager::on_group_call_left, input_group_call_id, audio_source, true); - result = Unit(); - } send_closure(actor_id, &GroupCallManager::finish_check_group_call_is_joined, input_group_call_id, audio_source, std::move(result)); }); @@ -1117,6 +1113,10 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i auto promises = std::move(it->second); load_group_call_queries_.erase(it); + if (G()->close_flag()) { + result = Status::Error(500, "Request aborted"); + } + if (result.is_ok()) { td_->contacts_manager_->on_get_users(std::move(result.ok_ref()->users_), "finish_get_group_call"); td_->contacts_manager_->on_get_chats(std::move(result.ok_ref()->chats_), "finish_get_group_call"); @@ -1157,8 +1157,20 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i void GroupCallManager::finish_check_group_call_is_joined(InputGroupCallId input_group_call_id, int32 audio_source, Result &&result) { + if (G()->close_flag()) { + return; + } + LOG(INFO) << "Finish check group call is_joined for " << input_group_call_id; + if (result.is_error()) { + auto message = result.error().message(); + if (message == "GROUPCALL_JOIN_MISSING" || message == "GROUPCALL_FORBIDDEN" || message == "GROUPCALL_INVALID") { + on_group_call_left(input_group_call_id, audio_source, true); + result = Unit(); + } + } + auto *group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); CHECK(audio_source != 0); @@ -1906,11 +1918,13 @@ void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id, void GroupCallManager::finish_get_group_call_stream_segment(InputGroupCallId input_group_call_id, Result &&result, Promise &&promise) { - auto *group_call = get_group_call(input_group_call_id); - CHECK(group_call != nullptr); - if (group_call->is_inited && check_group_call_is_joined_timeout_.has_timeout(group_call->group_call_id.get())) { - check_group_call_is_joined_timeout_.set_timeout_in(group_call->group_call_id.get(), - CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); + if (!G()->close_flag()) { + auto *group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr); + if (group_call->is_inited && check_group_call_is_joined_timeout_.has_timeout(group_call->group_call_id.get())) { + check_group_call_is_joined_timeout_.set_timeout_in(group_call->group_call_id.get(), + CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); + } } promise.set_result(std::move(result)); @@ -2246,6 +2260,11 @@ void GroupCallManager::finish_join_group_call(InputGroupCallId input_group_call_ } it->second->promise.set_error(std::move(error)); pending_join_requests_.erase(it); + + if (G()->close_flag()) { + return; + } + try_clear_group_call_participants(input_group_call_id); process_group_call_after_join_requests(input_group_call_id, "finish_join_group_call"); @@ -3056,6 +3075,10 @@ void GroupCallManager::leave_group_call(GroupCallId group_call_id, Promise } void GroupCallManager::on_group_call_left(InputGroupCallId input_group_call_id, int32 audio_source, bool need_rejoin) { + if (G()->close_flag()) { + return; + } + auto *group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); if (group_call->is_joined && group_call->audio_source == audio_source) { From ca6ece67073164c435e2e2cff869f60fdada72c5 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 17 Mar 2021 14:30:51 +0300 Subject: [PATCH 073/281] Improve getGroupCallStreamSegment. --- td/telegram/GroupCallManager.cpp | 67 +++++++++++++++++++++++++------- td/telegram/GroupCallManager.h | 4 +- 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 7a9941b2d..03bcb61d2 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1166,8 +1166,7 @@ void GroupCallManager::finish_check_group_call_is_joined(InputGroupCallId input_ if (result.is_error()) { auto message = result.error().message(); if (message == "GROUPCALL_JOIN_MISSING" || message == "GROUPCALL_FORBIDDEN" || message == "GROUPCALL_INVALID") { - on_group_call_left(input_group_call_id, audio_source, true); - result = Unit(); + on_group_call_left(input_group_call_id, audio_source, message == "GROUPCALL_JOIN_MISSING"); } } @@ -1898,32 +1897,72 @@ int32 GroupCallManager::cancel_join_group_call_request(InputGroupCallId input_gr void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id, int64 time_offset, int32 scale, Promise &&promise) { + if (G()->close_flag()) { + return promise.set_error(Status::Error(500, "Request aborted")); + } + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); auto *group_call = get_group_call(input_group_call_id); - CHECK(group_call != nullptr); - - if (!group_call->stream_dc_id.is_exact()) { + if (group_call == nullptr || !group_call->is_inited) { + reload_group_call(input_group_call_id, + PromiseCreator::lambda( + [actor_id = actor_id(this), group_call_id, time_offset, scale, promise = std::move(promise)]( + Result> &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &GroupCallManager::get_group_call_stream_segment, group_call_id, + time_offset, scale, std::move(promise)); + } + })); + return; + } + if (!group_call->is_active || !group_call->stream_dc_id.is_exact()) { return promise.set_error(Status::Error(400, "Group call can't be streamed")); } + if (!group_call->is_joined) { + if (is_group_call_being_joined(input_group_call_id) || group_call->need_rejoin) { + group_call->after_join.push_back( + PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, time_offset, scale, + promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &GroupCallManager::get_group_call_stream_segment, group_call_id, time_offset, + scale, std::move(promise)); + } + })); + return; + } + return promise.set_error(Status::Error(400, "GROUPCALL_JOIN_MISSING")); + } - auto query_promise = PromiseCreator::lambda( - [actor_id = actor_id(this), input_group_call_id, promise = std::move(promise)](Result &&result) mutable { + auto query_promise = + PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, audio_source = group_call->audio_source, + promise = std::move(promise)](Result &&result) mutable { send_closure(actor_id, &GroupCallManager::finish_get_group_call_stream_segment, input_group_call_id, - std::move(result), std::move(promise)); + audio_source, std::move(result), std::move(promise)); }); td_->create_handler(std::move(query_promise)) ->send(input_group_call_id, group_call->stream_dc_id, time_offset, scale); } -void GroupCallManager::finish_get_group_call_stream_segment(InputGroupCallId input_group_call_id, +void GroupCallManager::finish_get_group_call_stream_segment(InputGroupCallId input_group_call_id, int32 audio_source, Result &&result, Promise &&promise) { if (!G()->close_flag()) { - auto *group_call = get_group_call(input_group_call_id); - CHECK(group_call != nullptr); - if (group_call->is_inited && check_group_call_is_joined_timeout_.has_timeout(group_call->group_call_id.get())) { - check_group_call_is_joined_timeout_.set_timeout_in(group_call->group_call_id.get(), - CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); + if (result.is_ok()) { + auto *group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr); + if (group_call->is_inited && check_group_call_is_joined_timeout_.has_timeout(group_call->group_call_id.get())) { + check_group_call_is_joined_timeout_.set_timeout_in(group_call->group_call_id.get(), + CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); + } + } else { + auto message = result.error().message(); + if (message == "GROUPCALL_JOIN_MISSING" || message == "GROUPCALL_FORBIDDEN" || message == "GROUPCALL_INVALID") { + on_group_call_left(input_group_call_id, audio_source, message == "GROUPCALL_JOIN_MISSING"); + } } } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 6907bac9c..e56db2c1e 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -164,8 +164,8 @@ class GroupCallManager : public Actor { void finish_get_group_call(InputGroupCallId input_group_call_id, Result> &&result); - void finish_get_group_call_stream_segment(InputGroupCallId input_group_call_id, Result &&result, - Promise &&promise); + void finish_get_group_call_stream_segment(InputGroupCallId input_group_call_id, int32 audio_source, + Result &&result, Promise &&promise); void finish_check_group_call_is_joined(InputGroupCallId input_group_call_id, int32 audio_source, Result &&result); From ccc9920399c6a062669c2b90241b5244a78841af Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 17 Mar 2021 15:26:36 +0300 Subject: [PATCH 074/281] Don't create Dialog for unknown min-participants. --- td/telegram/GroupCallManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 03bcb61d2..5f34a493d 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1418,9 +1418,6 @@ void GroupCallManager::on_update_group_call_participants( LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); continue; } - if (participant.dialog_id.get_type() != DialogType::User) { - td_->messages_manager_->force_create_dialog(participant.dialog_id, "on_update_group_call_participants 2"); - } if (participant.is_min && participant.joined_date != 0) { auto old_participant = get_group_call_participant(group_call_participants, participant.dialog_id); if (old_participant == nullptr) { @@ -1433,6 +1430,9 @@ void GroupCallManager::on_update_group_call_participants( participant.update_from(*old_participant); CHECK(!participant.is_min); } + if (participant.dialog_id.get_type() != DialogType::User && participant.joined_date != 0) { + td_->messages_manager_->force_create_dialog(participant.dialog_id, "on_update_group_call_participants 2"); + } if (GroupCallParticipant::is_versioned_update(group_call_participant)) { version_updates.push_back(std::move(participant)); From 1139470bba4705e0cd3747435ab8ab09b9819dbb Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 17 Mar 2021 19:56:00 +0300 Subject: [PATCH 075/281] Pass GroupCallParticipants to get_real_participant_order. --- td/telegram/GroupCallManager.cpp | 16 ++++++++-------- td/telegram/GroupCallManager.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 5f34a493d..89f3e6029 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -738,7 +738,7 @@ void GroupCallManager::on_update_group_call_participant_order_timeout(GroupCallI bool can_manage = can_manage_group_call(input_group_call_id); auto *participants = add_group_call_participants(input_group_call_id); for (auto &participant : participants->participants) { - auto new_order = get_real_participant_order(can_manage, participant, participants->min_order); + auto new_order = get_real_participant_order(can_manage, participant, participants); if (new_order != participant.order) { participant.order = new_order; send_update_group_call_participant(input_group_call_id, participant); @@ -1603,13 +1603,13 @@ void GroupCallManager::on_sync_group_call_participants_failed(InputGroupCallId i } GroupCallParticipantOrder GroupCallManager::get_real_participant_order( - bool can_manage, const GroupCallParticipant &participant, const GroupCallParticipantOrder &min_order) const { + bool can_manage, const GroupCallParticipant &participant, const GroupCallParticipants *participants) const { auto real_order = participant.get_real_order(can_manage); - if (real_order >= min_order) { + if (real_order >= participants->min_order) { return real_order; } if (participant.is_self) { - return min_order; + return participants->min_order; } return GroupCallParticipantOrder(); } @@ -1718,7 +1718,7 @@ void GroupCallManager::process_group_call_participants( participants_it->second->min_order = min_order; for (auto &participant : participants_it->second->participants) { - auto real_order = get_real_participant_order(can_manage, participant, min_order); + auto real_order = get_real_participant_order(can_manage, participant, participants_it->second.get()); if (old_min_order > real_order && real_order >= min_order) { CHECK(!participant.order.is_valid() || participant.order == old_min_order); participant.order = real_order; @@ -1804,7 +1804,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou participant.update_from(old_participant); participant.is_just_joined = false; - participant.order = get_real_participant_order(can_manage, participant, participants->min_order); + participant.order = get_real_participant_order(can_manage, participant, participants); update_group_call_participant_can_be_muted(can_manage, participants, participant); LOG(INFO) << "Edit " << old_participant << " to " << participant; @@ -1830,7 +1830,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou } else { LOG(INFO) << "Receive new " << participant; } - participant.order = get_real_participant_order(can_manage, participant, participants->min_order); + participant.order = get_real_participant_order(can_manage, participant, participants); participant.is_just_joined = false; update_group_call_participant_can_be_muted(can_manage, participants, participant); participants->participants.push_back(std::move(participant)); @@ -3567,7 +3567,7 @@ DialogId GroupCallManager::set_group_call_participant_is_speaking_by_source(Inpu participant.local_active_date = max(participant.local_active_date, date); } bool can_manage = can_manage_group_call(input_group_call_id); - participant.order = get_real_participant_order(can_manage, participant, participants_it->second->min_order); + participant.order = get_real_participant_order(can_manage, participant, participants_it->second.get()); if (participant.order.is_valid()) { send_update_group_call_participant(input_group_call_id, participant); } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index e56db2c1e..35b4ba01a 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -189,7 +189,7 @@ class GroupCallManager : public Actor { void on_sync_group_call_participants_failed(InputGroupCallId input_group_call_id); GroupCallParticipantOrder get_real_participant_order(bool can_manage, const GroupCallParticipant &participant, - const GroupCallParticipantOrder &min_order) const; + const GroupCallParticipants *participants) const; void process_group_call_participants(InputGroupCallId group_call_id, vector> &&participants, From b833d23e41e1f84156aa3b0ce80219e1ea3b09a2 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 18 Mar 2021 02:36:31 +0300 Subject: [PATCH 076/281] Support ascending by joined_date sort of group call participants. --- td/telegram/GroupCallManager.cpp | 16 ++++++++++++++-- td/telegram/GroupCallManager.h | 2 ++ td/telegram/GroupCallParticipant.cpp | 13 ++++++++----- td/telegram/GroupCallParticipant.h | 2 +- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 89f3e6029..af9a22eab 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -638,6 +638,7 @@ struct GroupCallManager::GroupCall { bool loaded_all_participants = false; bool mute_new_participants = false; bool allowed_change_mute_new_participants = false; + bool joined_date_asc = false; int32 participant_count = 0; int32 duration = 0; int32 audio_source = 0; @@ -666,6 +667,7 @@ struct GroupCallManager::GroupCallParticipants { vector participants; string next_offset; GroupCallParticipantOrder min_order = GroupCallParticipantOrder::max(); + bool joined_date_asc = false; bool are_administrators_loaded = false; vector administrator_user_ids; @@ -997,6 +999,12 @@ bool GroupCallManager::can_manage_group_call(InputGroupCallId input_group_call_i return can_manage_group_calls(group_call->dialog_id).is_ok(); } +bool GroupCallManager::get_group_call_joined_date_asc(InputGroupCallId input_group_call_id) const { + auto group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr && group_call->is_inited); + return group_call->joined_date_asc; +} + void GroupCallManager::get_group_call_join_as(DialogId dialog_id, Promise> &&promise) { if (!dialog_id.is_valid()) { @@ -1326,6 +1334,7 @@ GroupCallManager::GroupCallParticipants *GroupCallManager::add_group_call_partic auto &participants = group_call_participants_[input_group_call_id]; if (participants == nullptr) { participants = make_unique(); + participants->joined_date_asc = get_group_call_joined_date_asc(input_group_call_id); } return participants.get(); } @@ -1604,7 +1613,7 @@ void GroupCallManager::on_sync_group_call_participants_failed(InputGroupCallId i GroupCallParticipantOrder GroupCallManager::get_real_participant_order( bool can_manage, const GroupCallParticipant &participant, const GroupCallParticipants *participants) const { - auto real_order = participant.get_real_order(can_manage); + auto real_order = participant.get_real_order(can_manage, participants->joined_date_asc); if (real_order >= participants->min_order) { return real_order; } @@ -1646,6 +1655,7 @@ void GroupCallManager::process_group_call_participants( auto min_order = GroupCallParticipantOrder::max(); bool can_manage = can_manage_group_call(input_group_call_id); + bool joined_date_asc = get_group_call_joined_date_asc(input_group_call_id); for (auto &group_call_participant : participants) { GroupCallParticipant participant(group_call_participant); if (!participant.is_valid()) { @@ -1660,7 +1670,7 @@ void GroupCallManager::process_group_call_participants( td_->messages_manager_->force_create_dialog(participant.dialog_id, "process_group_call_participants"); } - auto real_order = participant.get_real_order(can_manage); + auto real_order = participant.get_real_order(can_manage, joined_date_asc); if (real_order > min_order) { LOG(ERROR) << "Receive call participant with order " << real_order << " after call participant with order " << min_order; @@ -3230,6 +3240,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrtitle_); call.mute_new_participants = group_call->join_muted_; + call.joined_date_asc = group_call->join_date_asc_; call.allowed_change_mute_new_participants = group_call->can_change_join_muted_; call.participant_count = group_call->participants_count_; if ((group_call->flags_ & telegram_api::groupCall::STREAM_DC_ID_MASK) != 0) { @@ -3346,6 +3357,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrstream_dc_id = call.stream_dc_id; group_call->stream_dc_id_version = call.stream_dc_id_version; } + // flag call.joined_date_asc must not change if (call.record_start_date != group_call->record_start_date && call.record_start_date_version >= group_call->record_start_date_version) { int32 old_record_start_date = get_group_call_record_start_date(group_call); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 35b4ba01a..772957e78 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -159,6 +159,8 @@ class GroupCallManager : public Actor { bool can_manage_group_call(InputGroupCallId input_group_call_id) const; + bool get_group_call_joined_date_asc(InputGroupCallId input_group_call_id) const; + void on_voice_chat_created(DialogId dialog_id, InputGroupCallId input_group_call_id, Promise &&promise); void finish_get_group_call(InputGroupCallId input_group_call_id, diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index e15d5d958..8b479bb06 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -54,15 +54,18 @@ GroupCallParticipant::GroupCallParticipant(const tl_object_ptr &participant) { + // updates about new and left participants must be applyed as versioned, even they don't increase version return participant->just_joined_ || participant->left_ || participant->versioned_; } -GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_manage) const { - auto date = td::max(active_date, local_active_date); - if (date < G()->unix_time() - 300) { - date = 0; +GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_manage, bool joined_date_asc) const { + auto sort_active_date = td::max(active_date, local_active_date); + if (sort_active_date < G()->unix_time() - 300) { + sort_active_date = 0; } - return GroupCallParticipantOrder(date, can_manage ? raise_hand_rating : 0, joined_date); + auto sort_raise_hand_rating = can_manage ? raise_hand_rating : 0; + auto sort_joined_date = joined_date_asc ? std::numeric_limits::max() - joined_date : joined_date; + return GroupCallParticipantOrder(sort_active_date, sort_raise_hand_rating, sort_joined_date); } bool GroupCallParticipant::get_is_muted_by_themselves() const { diff --git a/td/telegram/GroupCallParticipant.h b/td/telegram/GroupCallParticipant.h index 20247947e..41f1b1a41 100644 --- a/td/telegram/GroupCallParticipant.h +++ b/td/telegram/GroupCallParticipant.h @@ -72,7 +72,7 @@ struct GroupCallParticipant { bool set_pending_is_muted(bool is_muted, bool can_manage, bool is_admin); - GroupCallParticipantOrder get_real_order(bool can_manage) const; + GroupCallParticipantOrder get_real_order(bool can_manage, bool joined_date_asc) const; bool is_valid() const { return dialog_id.is_valid(); From e072f2ffa2f8e641f6fed4dc67a4f7db9955e3b7 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 18 Mar 2021 03:12:52 +0300 Subject: [PATCH 077/281] Add struct PendingUpdates. --- td/telegram/GroupCallManager.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index af9a22eab..11a481bac 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -672,8 +672,11 @@ struct GroupCallManager::GroupCallParticipants { bool are_administrators_loaded = false; vector administrator_user_ids; - std::map> pending_version_updates_; - std::map> pending_mute_updates_; + struct PendingUpdates { + std::vector updates; + }; + std::map pending_version_updates_; + std::map pending_mute_updates_; }; struct GroupCallManager::GroupCallRecentSpeakers { @@ -1419,7 +1422,7 @@ void GroupCallManager::on_update_group_call_participants( } auto *group_call_participants = add_group_call_participants(input_group_call_id); - auto &pending_mute_updates = group_call_participants->pending_mute_updates_[version]; + auto &pending_mute_updates = group_call_participants->pending_mute_updates_[version].updates; vector version_updates; for (auto &group_call_participant : participants) { GroupCallParticipant participant(group_call_participant); @@ -1450,7 +1453,7 @@ void GroupCallManager::on_update_group_call_participants( } } if (!version_updates.empty()) { - auto &pending_version_updates = group_call_participants->pending_version_updates_[version]; + auto &pending_version_updates = group_call_participants->pending_version_updates_[version].updates; if (version_updates.size() <= pending_version_updates.size()) { LOG(INFO) << "Receive duplicate updateGroupCallParticipants with version " << version << " in " << input_group_call_id; @@ -1484,7 +1487,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup while (!pending_version_updates.empty()) { auto it = pending_version_updates.begin(); auto version = it->first; - auto &participants = it->second; + auto &participants = it->second.updates; if (version <= group_call->version) { for (auto &participant : participants) { on_participant_speaking_in_group_call(input_group_call_id, participant); @@ -1532,7 +1535,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup auto it = pending_mute_updates.begin(); auto version = it->first; if (version <= group_call->version) { - auto &participants = it->second; + auto &participants = it->second.updates; for (auto &participant : participants) { on_participant_speaking_in_group_call(input_group_call_id, participant); int mute_diff = process_group_call_participant(input_group_call_id, std::move(participant)); From 25e5c0bac2c239b9946f66eb78866c21ddd054b3 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 18 Mar 2021 03:21:43 +0300 Subject: [PATCH 078/281] Combine versioned updates with the same version instead of replacing. --- td/telegram/GroupCallManager.cpp | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 11a481bac..7726d11a9 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -673,7 +673,7 @@ struct GroupCallManager::GroupCallParticipants { vector administrator_user_ids; struct PendingUpdates { - std::vector updates; + std::unordered_map updates; }; std::map pending_version_updates_; std::map pending_mute_updates_; @@ -1422,8 +1422,8 @@ void GroupCallManager::on_update_group_call_participants( } auto *group_call_participants = add_group_call_participants(input_group_call_id); + auto &pending_version_updates = group_call_participants->pending_version_updates_[version].updates; auto &pending_mute_updates = group_call_participants->pending_mute_updates_[version].updates; - vector version_updates; for (auto &group_call_participant : participants) { GroupCallParticipant participant(group_call_participant); if (!participant.is_valid()) { @@ -1442,25 +1442,17 @@ void GroupCallManager::on_update_group_call_participants( participant.update_from(*old_participant); CHECK(!participant.is_min); } - if (participant.dialog_id.get_type() != DialogType::User && participant.joined_date != 0) { - td_->messages_manager_->force_create_dialog(participant.dialog_id, "on_update_group_call_participants 2"); + auto dialog_id = participant.dialog_id; + if (dialog_id.get_type() != DialogType::User && participant.joined_date != 0) { + td_->messages_manager_->force_create_dialog(dialog_id, "on_update_group_call_participants 2"); } if (GroupCallParticipant::is_versioned_update(group_call_participant)) { - version_updates.push_back(std::move(participant)); + pending_version_updates[dialog_id] = std::move(participant); } else { - pending_mute_updates.push_back(std::move(participant)); + pending_mute_updates[dialog_id] = std::move(participant); } } - if (!version_updates.empty()) { - auto &pending_version_updates = group_call_participants->pending_version_updates_[version].updates; - if (version_updates.size() <= pending_version_updates.size()) { - LOG(INFO) << "Receive duplicate updateGroupCallParticipants with version " << version << " in " - << input_group_call_id; - return; - } - pending_version_updates = std::move(version_updates); - } process_pending_group_call_participant_updates(input_group_call_id); } @@ -1489,7 +1481,8 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup auto version = it->first; auto &participants = it->second.updates; if (version <= group_call->version) { - for (auto &participant : participants) { + for (auto &participant_it : participants) { + auto &participant = participant_it.second; on_participant_speaking_in_group_call(input_group_call_id, participant); if (participant.is_self) { auto my_participant = @@ -1510,7 +1503,8 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup if (version == group_call->version + 1) { group_call->version = version; - for (auto &participant : participants) { + for (auto &participant_it : participants) { + auto &participant = participant_it.second; if (participant.is_self && group_call->is_joined && (participant.joined_date == 0) == (participant.audio_source == group_call->audio_source)) { is_left = true; @@ -1536,7 +1530,8 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup auto version = it->first; if (version <= group_call->version) { auto &participants = it->second.updates; - for (auto &participant : participants) { + for (auto &participant_it : participants) { + auto &participant = participant_it.second; on_participant_speaking_in_group_call(input_group_call_id, participant); int mute_diff = process_group_call_participant(input_group_call_id, std::move(participant)); CHECK(mute_diff == 0); From fee3ca166b468ac23cf3c2c1a2d5bada95352e91 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 18 Mar 2021 22:03:14 +0300 Subject: [PATCH 079/281] Apply prepended my_participant. --- td/telegram/GroupCallManager.cpp | 39 +++++++++++++++++++++++--------- td/telegram/GroupCallManager.h | 4 +++- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 7726d11a9..e4cdd7166 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1146,7 +1146,7 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i } auto call = result.move_as_ok(); - process_group_call_participants(input_group_call_id, std::move(call->participants_), true, false); + process_group_call_participants(input_group_call_id, std::move(call->participants_), string(), true, false); if (need_group_call_participants(input_group_call_id)) { auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it != group_call_participants_.end()) { @@ -1265,7 +1265,8 @@ void GroupCallManager::on_get_group_call_participants( } auto is_empty = participants->participants_.empty(); - process_group_call_participants(input_group_call_id, std::move(participants->participants_), is_load, is_sync); + process_group_call_participants(input_group_call_id, std::move(participants->participants_), offset, is_load, + is_sync); if (!is_sync) { on_receive_group_call_version(input_group_call_id, participants->version_); @@ -1485,14 +1486,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup auto &participant = participant_it.second; on_participant_speaking_in_group_call(input_group_call_id, participant); if (participant.is_self) { - auto my_participant = - get_group_call_participant(participants_it->second.get(), DialogId(td_->contacts_manager_->get_my_id())); - if (my_participant == nullptr || my_participant->is_fake || - my_participant->joined_date < participant.joined_date || - (my_participant->joined_date <= participant.joined_date && - my_participant->audio_source != participant.audio_source)) { - process_group_call_participant(input_group_call_id, std::move(participant)); - } + process_my_group_call_participant(input_group_call_id, std::move(participant)); } } LOG(INFO) << "Ignore already applied updateGroupCallParticipants with version " << version << " in " @@ -1623,7 +1617,14 @@ GroupCallParticipantOrder GroupCallManager::get_real_participant_order( void GroupCallManager::process_group_call_participants( InputGroupCallId input_group_call_id, vector> &&participants, - bool is_load, bool is_sync) { + const string &offset, bool is_load, bool is_sync) { + if (offset.empty() && is_load && !participants.empty() && participants[0]->self_) { + GroupCallParticipant participant(participants[0]); + if (participant.is_valid()) { + process_my_group_call_participant(input_group_call_id, std::move(participant)); + } + participants.erase(participants.begin()); + } if (!need_group_call_participants(input_group_call_id)) { for (auto &group_call_participant : participants) { GroupCallParticipant participant(group_call_participant); @@ -1764,6 +1765,22 @@ void GroupCallManager::update_group_call_participants_can_be_muted(InputGroupCal } } +void GroupCallManager::process_my_group_call_participant(InputGroupCallId input_group_call_id, + GroupCallParticipant &&participant) { + CHECK(participant.is_valid()); + CHECK(participant.is_self); + if (!need_group_call_participants(input_group_call_id)) { + return; + } + auto my_participant = get_group_call_participant(add_group_call_participants(input_group_call_id), + DialogId(td_->contacts_manager_->get_my_id())); + if (my_participant == nullptr || my_participant->is_fake || my_participant->joined_date < participant.joined_date || + (my_participant->joined_date <= participant.joined_date && + my_participant->audio_source != participant.audio_source)) { + process_group_call_participant(input_group_call_id, std::move(participant)); + } +} + int GroupCallManager::process_group_call_participant(InputGroupCallId input_group_call_id, GroupCallParticipant &&participant) { if (!participant.is_valid()) { diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 772957e78..eaf4b590d 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -193,9 +193,11 @@ class GroupCallManager : public Actor { GroupCallParticipantOrder get_real_participant_order(bool can_manage, const GroupCallParticipant &participant, const GroupCallParticipants *participants) const; + void process_my_group_call_participant(InputGroupCallId input_group_call_id, GroupCallParticipant &&participant); + void process_group_call_participants(InputGroupCallId group_call_id, vector> &&participants, - bool is_load, bool is_sync); + const string &offset, bool is_load, bool is_sync); bool update_group_call_participant_can_be_muted(bool can_manage, const GroupCallParticipants *participants, GroupCallParticipant &participant); From 110a68c764f0e07d9fdb42dd74a16487dbcaf132 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 18 Mar 2021 22:36:59 +0300 Subject: [PATCH 080/281] Try to get information about min-participants from server. --- td/telegram/GroupCallManager.cpp | 48 ++++++++++++++++++++++++-------- td/telegram/GroupCallManager.h | 4 +-- td/telegram/UpdatesManager.cpp | 2 +- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index e4cdd7166..8d5535f91 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1368,7 +1368,11 @@ GroupCallParticipant *GroupCallManager::get_group_call_participant(GroupCallPart void GroupCallManager::on_update_group_call_participants( InputGroupCallId input_group_call_id, vector> &&participants, - int32 version) { + int32 version, bool is_recursive) { + if (G()->close_flag()) { + return; + } + if (!need_group_call_participants(input_group_call_id)) { int32 diff = 0; bool need_update = false; @@ -1423,6 +1427,29 @@ void GroupCallManager::on_update_group_call_participants( } auto *group_call_participants = add_group_call_participants(input_group_call_id); + if (!is_recursive) { + vector missing_participants; + for (auto &group_call_participant : participants) { + GroupCallParticipant participant(group_call_participant); + if (participant.is_valid() && participant.is_min && participant.joined_date != 0 && + get_group_call_participant(group_call_participants, participant.dialog_id) == nullptr) { + missing_participants.push_back(participant.dialog_id); + } + } + if (!missing_participants.empty()) { + LOG(INFO) << "Can't apply min updates about " << missing_participants << " in " << input_group_call_id; + auto input_peers = transform(missing_participants, &MessagesManager::get_input_peer_force); + auto query_promise = + PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, + participants = std::move(participants), version](Result &&result) mutable { + send_closure(actor_id, &GroupCallManager::on_update_group_call_participants, input_group_call_id, + std::move(participants), version, true); + }); + td_->create_handler(std::move(query_promise)) + ->send(input_group_call_id, std::move(input_peers), {}); + } + } + auto &pending_version_updates = group_call_participants->pending_version_updates_[version].updates; auto &pending_mute_updates = group_call_participants->pending_mute_updates_[version].updates; for (auto &group_call_participant : participants) { @@ -1434,8 +1461,7 @@ void GroupCallManager::on_update_group_call_participants( if (participant.is_min && participant.joined_date != 0) { auto old_participant = get_group_call_participant(group_call_participants, participant.dialog_id); if (old_participant == nullptr) { - LOG(INFO) << "Can't apply min update about " << participant.dialog_id << " in " << input_group_call_id; - // TODO instead of synchronization, such participants can be received through GetGroupCallParticipantQuery + LOG(ERROR) << "Can't apply min update about " << participant.dialog_id << " in " << input_group_call_id; on_receive_group_call_version(input_group_call_id, version, true); return; } @@ -2745,20 +2771,20 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ } } - bool recursive = false; + bool is_recursive = false; if (date == 0) { date = G()->unix_time(); } else { - recursive = true; + is_recursive = true; } - if (group_call->audio_source != 0 && audio_source != group_call->audio_source && !recursive && is_speaking && + if (group_call->audio_source != 0 && audio_source != group_call->audio_source && !is_recursive && is_speaking && check_group_call_is_joined_timeout_.has_timeout(group_call_id.get())) { check_group_call_is_joined_timeout_.set_timeout_in(group_call_id.get(), CHECK_GROUP_CALL_IS_JOINED_TIMEOUT); } DialogId dialog_id = set_group_call_participant_is_speaking_by_source(input_group_call_id, audio_source, is_speaking, date); if (!dialog_id.is_valid()) { - if (!recursive) { + if (!is_recursive) { auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, audio_source, is_speaking, promise = std::move(promise), date](Result &&result) mutable { if (G()->close_flag()) { @@ -2782,7 +2808,7 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_ } if (is_speaking) { - on_user_speaking_in_group_call(group_call_id, dialog_id, date, recursive); + on_user_speaking_in_group_call(group_call_id, dialog_id, date, is_recursive); } if (group_call->audio_source == audio_source && group_call->dialog_id.is_valid() && @@ -3462,7 +3488,7 @@ void GroupCallManager::on_participant_speaking_in_group_call(InputGroupCallId in } void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, DialogId dialog_id, int32 date, - bool recursive) { + bool is_recursive) { if (G()->close_flag()) { return; } @@ -3478,9 +3504,9 @@ void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, } if (!td_->messages_manager_->have_dialog_info_force(dialog_id) || - (!recursive && need_group_call_participants(input_group_call_id, group_call) && + (!is_recursive && need_group_call_participants(input_group_call_id, group_call) && get_group_call_participant(input_group_call_id, dialog_id) == nullptr)) { - if (recursive) { + if (is_recursive) { LOG(ERROR) << "Failed to find speaking " << dialog_id << " from " << input_group_call_id; } else { auto query_promise = diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index eaf4b590d..ddf926431 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -99,7 +99,7 @@ class GroupCallManager : public Actor { void on_update_group_call(tl_object_ptr group_call_ptr, DialogId dialog_id); void on_user_speaking_in_group_call(GroupCallId group_call_id, DialogId dialog_id, int32 date, - bool recursive = false); + bool is_recursive = false); void on_get_group_call_participants(InputGroupCallId input_group_call_id, tl_object_ptr &&participants, bool is_load, @@ -107,7 +107,7 @@ class GroupCallManager : public Actor { void on_update_group_call_participants(InputGroupCallId input_group_call_id, vector> &&participants, - int32 version); + int32 version, bool is_recursive = false); void process_join_group_call_response(InputGroupCallId input_group_call_id, uint64 generation, tl_object_ptr &&updates, Promise &&promise); diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index 0eeaca35b..ba383eea9 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -2836,7 +2836,7 @@ void UpdatesManager::on_update(tl_object_ptr upda void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { send_closure(G()->group_call_manager(), &GroupCallManager::on_update_group_call_participants, - InputGroupCallId(update->call_), std::move(update->participants_), update->version_); + InputGroupCallId(update->call_), std::move(update->participants_), update->version_, false); promise.set_value(Unit()); } From 0a23e2bd7b97e25803c8377b53b62b19b764e68a Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 18 Mar 2021 22:55:15 +0300 Subject: [PATCH 081/281] Fix CHECK. --- td/telegram/GroupCallManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 8d5535f91..7100f9c42 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1755,7 +1755,7 @@ void GroupCallManager::process_group_call_participants( for (auto &participant : participants_it->second->participants) { auto real_order = get_real_participant_order(can_manage, participant, participants_it->second.get()); if (old_min_order > real_order && real_order >= min_order) { - CHECK(!participant.order.is_valid() || participant.order == old_min_order); + CHECK(!participant.order.is_valid() || participant.is_self); participant.order = real_order; send_update_group_call_participant(input_group_call_id, participant); } From 93ae3dc2f6525cb1f724a49b651ba363c2d01cba Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 18 Mar 2021 23:18:16 +0300 Subject: [PATCH 082/281] Improve logging. --- td/telegram/GroupCallParticipant.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index 8b479bb06..d63ecf20b 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -95,7 +95,8 @@ bool GroupCallParticipant::get_is_hand_raised() const { void GroupCallParticipant::update_from(const GroupCallParticipant &old_participant) { CHECK(!old_participant.is_min); if (joined_date < old_participant.joined_date) { - LOG(ERROR) << "Join date decreased from " << old_participant.joined_date << " to " << joined_date; + LOG(ERROR) << "Join date of " << old_participant.dialog_id << " decreased from " << old_participant.joined_date + << " to " << joined_date; joined_date = old_participant.joined_date; } if (active_date < old_participant.active_date) { From 504ecbeed79885c6738e0fffd2084a3044c4efea Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 18 Mar 2021 23:31:49 +0300 Subject: [PATCH 083/281] Fix group call participant count by updates. --- td/telegram/GroupCallManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 7100f9c42..c09f2409f 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -3427,6 +3427,10 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrversion && call.participant_count != group_call->participant_count) { + LOG(INFO) << "Fix " << call.group_call_id << " participant count to " << call.participant_count; + group_call->participant_count = call.participant_count; + need_update = true; } } } From 35250a91bd5bcfbea766fb3142ff6bd8748c6d9f Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 00:03:34 +0300 Subject: [PATCH 084/281] Keep active date while adjusting min-order. --- td/telegram/GroupCallManager.cpp | 9 +++------ td/telegram/GroupCallParticipant.cpp | 5 +++-- td/telegram/GroupCallParticipant.h | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index c09f2409f..1f05b1a18 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1383,9 +1383,6 @@ void GroupCallManager::on_update_group_call_participants( LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); continue; } - if (participant.dialog_id.get_type() != DialogType::User) { - td_->messages_manager_->force_create_dialog(participant.dialog_id, "on_update_group_call_participants 1"); - } if (participant.joined_date == 0) { diff--; remove_recent_group_call_speaker(input_group_call_id, participant.dialog_id); @@ -1631,7 +1628,7 @@ void GroupCallManager::on_sync_group_call_participants_failed(InputGroupCallId i GroupCallParticipantOrder GroupCallManager::get_real_participant_order( bool can_manage, const GroupCallParticipant &participant, const GroupCallParticipants *participants) const { - auto real_order = participant.get_real_order(can_manage, participants->joined_date_asc); + auto real_order = participant.get_real_order(can_manage, participants->joined_date_asc, false); if (real_order >= participants->min_order) { return real_order; } @@ -1695,7 +1692,7 @@ void GroupCallManager::process_group_call_participants( td_->messages_manager_->force_create_dialog(participant.dialog_id, "process_group_call_participants"); } - auto real_order = participant.get_real_order(can_manage, joined_date_asc); + auto real_order = participant.get_real_order(can_manage, joined_date_asc, true); if (real_order > min_order) { LOG(ERROR) << "Receive call participant with order " << real_order << " after call participant with order " << min_order; @@ -3488,7 +3485,7 @@ void GroupCallManager::on_participant_speaking_in_group_call(InputGroupCallId in return; } - on_user_speaking_in_group_call(group_call->group_call_id, participant.dialog_id, active_date, true); + on_user_speaking_in_group_call(group_call->group_call_id, participant.dialog_id, active_date, !participant.is_min); } void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, DialogId dialog_id, int32 date, diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index d63ecf20b..c079fe249 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -58,9 +58,10 @@ bool GroupCallParticipant::is_versioned_update(const tl_object_ptrjust_joined_ || participant->left_ || participant->versioned_; } -GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_manage, bool joined_date_asc) const { +GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_manage, bool joined_date_asc, + bool keep_active_date) const { auto sort_active_date = td::max(active_date, local_active_date); - if (sort_active_date < G()->unix_time() - 300) { + if (!keep_active_date && sort_active_date < G()->unix_time() - 300) { sort_active_date = 0; } auto sort_raise_hand_rating = can_manage ? raise_hand_rating : 0; diff --git a/td/telegram/GroupCallParticipant.h b/td/telegram/GroupCallParticipant.h index 41f1b1a41..488b7c71b 100644 --- a/td/telegram/GroupCallParticipant.h +++ b/td/telegram/GroupCallParticipant.h @@ -72,7 +72,7 @@ struct GroupCallParticipant { bool set_pending_is_muted(bool is_muted, bool can_manage, bool is_admin); - GroupCallParticipantOrder get_real_order(bool can_manage, bool joined_date_asc) const; + GroupCallParticipantOrder get_real_order(bool can_manage, bool joined_date_asc, bool keep_active_date) const; bool is_valid() const { return dialog_id.is_valid(); From ea5a7bade7029771c2930e71b0bb5b66ffa222ad Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 00:18:55 +0300 Subject: [PATCH 085/281] Add set_group_call_participant_count method. --- td/telegram/GroupCallManager.cpp | 37 +++++++++++++++++--------------- td/telegram/GroupCallManager.h | 2 ++ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 1f05b1a18..b967ee985 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1307,7 +1307,7 @@ void GroupCallManager::on_get_group_call_participants( LOG(ERROR) << "Have participant count " << group_call->participant_count << " instead of " << real_participant_count << " in " << input_group_call_id << " from " << group_call->dialog_id; } - group_call->participant_count = real_participant_count; + set_group_call_participant_count(group_call, real_participant_count, "on_get_group_call_participants"); need_update = true; update_group_call_dialog(group_call, "on_get_group_call_participants"); @@ -1396,12 +1396,8 @@ void GroupCallManager::on_update_group_call_participants( if (group_call != nullptr && group_call->is_inited && group_call->is_active && group_call->version == -1) { if (diff != 0 && (group_call->participant_count != 0 || diff > 0)) { - group_call->participant_count += diff; - if (group_call->participant_count < 0) { - LOG(ERROR) << "Participant count became negative in " << input_group_call_id << " from " - << group_call->dialog_id << " after applying " << to_string(participants); - group_call->participant_count = 0; - } + set_group_call_participant_count(group_call, group_call->participant_count + diff, + "on_update_group_call_participants"); update_group_call_dialog(group_call, "on_update_group_call_participants"); need_update = true; } @@ -1566,11 +1562,8 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup bool need_update = false; if (diff != 0 && (group_call->participant_count != 0 || diff > 0)) { - group_call->participant_count += diff; - if (group_call->participant_count < 0) { - LOG(ERROR) << "Participant count became negative in " << input_group_call_id << " from " << group_call->dialog_id; - group_call->participant_count = 0; - } + set_group_call_participant_count(group_call, group_call->participant_count + diff, + "process_pending_group_call_participant_updates"); need_update = true; update_group_call_dialog(group_call, "process_pending_group_call_participant_updates"); } @@ -2151,7 +2144,7 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di int diff = process_group_call_participant(input_group_call_id, std::move(participant)); if (diff != 0) { CHECK(diff == 1); - group_call->participant_count++; + set_group_call_participant_count(group_call, group_call->participant_count + diff, "join_group_call"); need_update = true; update_group_call_dialog(group_call, "join_group_call", true); } @@ -3411,8 +3404,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrparticipant_count) { - LOG(INFO) << "Set " << call.group_call_id << " participant count to " << call.participant_count; - group_call->participant_count = call.participant_count; + set_group_call_participant_count(group_call, call.participant_count, "update_group_call"); need_update = true; } if (need_group_call_participants(input_group_call_id, group_call) && !join_params.empty() && @@ -3425,8 +3417,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrversion && call.participant_count != group_call->participant_count) { - LOG(INFO) << "Fix " << call.group_call_id << " participant count to " << call.participant_count; - group_call->participant_count = call.participant_count; + set_group_call_participant_count(group_call, call.participant_count, "update_group_call fix"); need_update = true; } } @@ -3633,6 +3624,18 @@ DialogId GroupCallManager::set_group_call_participant_is_speaking_by_source(Inpu return DialogId(); } +void GroupCallManager::set_group_call_participant_count(GroupCall *group_call, int32 count, const char *source) { + CHECK(group_call != nullptr); + LOG(DEBUG) << "Set " << group_call->group_call_id << " participant count to " << count << " from " << source; + if (count < 0) { + LOG(ERROR) << "Participant count became negative in " << group_call->group_call_id << " in " + << group_call->dialog_id << " from " << source; + group_call->participant_count = 0; + } else { + group_call->participant_count = count; + } +} + void GroupCallManager::update_group_call_dialog(const GroupCall *group_call, const char *source, bool force) { if (!group_call->dialog_id.is_valid()) { return; diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index ddf926431..4dd0ed5e0 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -277,6 +277,8 @@ class GroupCallManager : public Actor { void try_clear_group_call_participants(InputGroupCallId input_group_call_id); + static void set_group_call_participant_count(GroupCall *group_call, int32 count, const char *source); + void update_group_call_dialog(const GroupCall *group_call, const char *source, bool force = false); vector> get_recent_speakers(const GroupCall *group_call, From a6337c2d3772dbce64846455e1c3b3ec5f41993b Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 00:41:35 +0300 Subject: [PATCH 086/281] Improve logging. --- td/telegram/GroupCallManager.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index b967ee985..51e52dfa4 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1669,6 +1669,7 @@ void GroupCallManager::process_group_call_participants( } auto min_order = GroupCallParticipantOrder::max(); + DialogId min_order_dialog_id; bool can_manage = can_manage_group_call(input_group_call_id); bool joined_date_asc = get_group_call_joined_date_asc(input_group_call_id); for (auto &group_call_participant : participants) { @@ -1685,12 +1686,15 @@ void GroupCallManager::process_group_call_participants( td_->messages_manager_->force_create_dialog(participant.dialog_id, "process_group_call_participants"); } - auto real_order = participant.get_real_order(can_manage, joined_date_asc, true); - if (real_order > min_order) { - LOG(ERROR) << "Receive call participant with order " << real_order << " after call participant with order " - << min_order; - } else { - min_order = real_order; + if (is_load) { + auto real_order = participant.get_real_order(can_manage, joined_date_asc, true); + if (real_order > min_order) { + LOG(ERROR) << "Receive call participant " << participant.dialog_id << " with order " << real_order + << " after call participant " << min_order_dialog_id << " with order " << min_order; + } else { + min_order = real_order; + min_order_dialog_id = participant.dialog_id; + } } if (is_sync) { old_participant_dialog_ids.erase(participant.dialog_id); From 81f20ae4ec26923bb20680c2d76fe1810982c6df Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 01:24:57 +0300 Subject: [PATCH 087/281] Ignore FLOOD_WAIT errors got getGroupCallStreamSegment. --- td/telegram/GroupCallManager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 51e52dfa4..08861a924 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -42,9 +42,11 @@ class GetGroupCallStreamQuery : public Td::ResultHandler { auto input_stream = make_tl_object(input_group_call_id.get_input_group_call(), time_offset, scale); int32 flags = 0; - send_query(G()->net_query_creator().create( + auto query = G()->net_query_creator().create( telegram_api::upload_getFile(flags, false /*ignored*/, false /*ignored*/, std::move(input_stream), 0, 1 << 20), - stream_dc_id, NetQuery::Type::DownloadSmall)); + stream_dc_id, NetQuery::Type::DownloadSmall); + query->total_timeout_limit_ = 0; + send_query(std::move(query)); } void on_result(uint64 id, BufferSlice packet) override { From 12a755d921e1b28052b852df5b39c024f9901406 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 01:28:18 +0300 Subject: [PATCH 088/281] Don't ignore update about ended group call if group call is being joined. --- td/telegram/MessagesManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index bd3546da6..7f1259a98 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -29786,7 +29786,7 @@ void MessagesManager::on_update_dialog_group_call(DialogId dialog_id, bool has_a if (d->has_active_group_call == has_active_group_call && d->is_group_call_empty == is_group_call_empty) { return; } - if (!force && d->active_group_call_id.is_valid() && + if (!force && d->active_group_call_id.is_valid() && has_active_group_call && td_->group_call_manager_->is_group_call_being_joined(d->active_group_call_id)) { LOG(INFO) << "Ignore update in a being joined group call"; return; From f670aeb2b3ebc6fdd169769707ac25eb5e64b0df Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 02:20:22 +0300 Subject: [PATCH 089/281] Simplify mute_updates processing. --- td/telegram/GroupCallManager.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 08861a924..8fc23e5e2 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1543,19 +1543,20 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup while (!pending_mute_updates.empty()) { auto it = pending_mute_updates.begin(); auto version = it->first; - if (version <= group_call->version) { - auto &participants = it->second.updates; - for (auto &participant_it : participants) { - auto &participant = participant_it.second; - on_participant_speaking_in_group_call(input_group_call_id, participant); - int mute_diff = process_group_call_participant(input_group_call_id, std::move(participant)); - CHECK(mute_diff == 0); - } - pending_mute_updates.erase(it); - continue; + if (version > group_call->version) { + break; } - on_receive_group_call_version(input_group_call_id, version); - break; + auto &participants = it->second.updates; + for (auto &participant_it : participants) { + auto &participant = participant_it.second; + on_participant_speaking_in_group_call(input_group_call_id, participant); + int mute_diff = process_group_call_participant(input_group_call_id, std::move(participant)); + CHECK(mute_diff == 0); + } + pending_mute_updates.erase(it); + } + if (!pending_mute_updates.empty()) { + on_receive_group_call_version(input_group_call_id, pending_mute_updates.begin()->first); } if (pending_version_updates.empty() && pending_mute_updates.empty()) { From b6f900b74ff7f0af313f5d4c41b43bc745cf7c79 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 02:25:54 +0300 Subject: [PATCH 090/281] Process mute updates as soon as possible. --- td/telegram/GroupCallManager.cpp | 40 +++++++++++++++++++------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 8fc23e5e2..e23790f95 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1498,7 +1498,29 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup bool is_left = false; bool need_rejoin = true; auto &pending_version_updates = participants_it->second->pending_version_updates_; + auto &pending_mute_updates = participants_it->second->pending_mute_updates_; + + auto process_mute_updates = [&] { + while (!pending_mute_updates.empty()) { + auto it = pending_mute_updates.begin(); + auto version = it->first; + if (version > group_call->version) { + return; + } + auto &participants = it->second.updates; + for (auto &participant_it : participants) { + auto &participant = participant_it.second; + on_participant_speaking_in_group_call(input_group_call_id, participant); + int mute_diff = process_group_call_participant(input_group_call_id, std::move(participant)); + CHECK(mute_diff == 0); + } + pending_mute_updates.erase(it); + } + }; + while (!pending_version_updates.empty()) { + process_mute_updates(); + auto it = pending_version_updates.begin(); auto version = it->first; auto &participants = it->second.updates; @@ -1539,22 +1561,8 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup } } - auto &pending_mute_updates = participants_it->second->pending_mute_updates_; - while (!pending_mute_updates.empty()) { - auto it = pending_mute_updates.begin(); - auto version = it->first; - if (version > group_call->version) { - break; - } - auto &participants = it->second.updates; - for (auto &participant_it : participants) { - auto &participant = participant_it.second; - on_participant_speaking_in_group_call(input_group_call_id, participant); - int mute_diff = process_group_call_participant(input_group_call_id, std::move(participant)); - CHECK(mute_diff == 0); - } - pending_mute_updates.erase(it); - } + process_mute_updates(); + if (!pending_mute_updates.empty()) { on_receive_group_call_version(input_group_call_id, pending_mute_updates.begin()->first); } From 6656cd29f9b634c54bbec75bf46d96220421e4a4 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 02:44:20 +0300 Subject: [PATCH 091/281] Add version to GroupCallParticipant. --- td/telegram/GroupCallManager.cpp | 24 ++++++++++++++---------- td/telegram/GroupCallManager.h | 2 +- td/telegram/GroupCallParticipant.cpp | 4 +++- td/telegram/GroupCallParticipant.h | 3 ++- td/telegram/MessagesManager.cpp | 6 +++--- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index e23790f95..3055e6baf 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1148,7 +1148,11 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i } auto call = result.move_as_ok(); - process_group_call_participants(input_group_call_id, std::move(call->participants_), string(), true, false); + int32 version = 0; + if (call->call_->get_id() == telegram_api::groupCall::ID) { + version = static_cast(call->call_.get())->version_; + } + process_group_call_participants(input_group_call_id, std::move(call->participants_), version, string(), true, false); if (need_group_call_participants(input_group_call_id)) { auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it != group_call_participants_.end()) { @@ -1267,8 +1271,8 @@ void GroupCallManager::on_get_group_call_participants( } auto is_empty = participants->participants_.empty(); - process_group_call_participants(input_group_call_id, std::move(participants->participants_), offset, is_load, - is_sync); + process_group_call_participants(input_group_call_id, std::move(participants->participants_), participants->version_, + offset, is_load, is_sync); if (!is_sync) { on_receive_group_call_version(input_group_call_id, participants->version_); @@ -1380,7 +1384,7 @@ void GroupCallManager::on_update_group_call_participants( bool need_update = false; auto group_call = get_group_call(input_group_call_id); for (auto &group_call_participant : participants) { - GroupCallParticipant participant(group_call_participant); + GroupCallParticipant participant(group_call_participant, version); if (!participant.is_valid()) { LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); continue; @@ -1425,7 +1429,7 @@ void GroupCallManager::on_update_group_call_participants( if (!is_recursive) { vector missing_participants; for (auto &group_call_participant : participants) { - GroupCallParticipant participant(group_call_participant); + GroupCallParticipant participant(group_call_participant, version); if (participant.is_valid() && participant.is_min && participant.joined_date != 0 && get_group_call_participant(group_call_participants, participant.dialog_id) == nullptr) { missing_participants.push_back(participant.dialog_id); @@ -1448,7 +1452,7 @@ void GroupCallManager::on_update_group_call_participants( auto &pending_version_updates = group_call_participants->pending_version_updates_[version].updates; auto &pending_mute_updates = group_call_participants->pending_mute_updates_[version].updates; for (auto &group_call_participant : participants) { - GroupCallParticipant participant(group_call_participant); + GroupCallParticipant participant(group_call_participant, version); if (!participant.is_valid()) { LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); continue; @@ -1644,9 +1648,9 @@ GroupCallParticipantOrder GroupCallManager::get_real_participant_order( void GroupCallManager::process_group_call_participants( InputGroupCallId input_group_call_id, vector> &&participants, - const string &offset, bool is_load, bool is_sync) { + int32 version, const string &offset, bool is_load, bool is_sync) { if (offset.empty() && is_load && !participants.empty() && participants[0]->self_) { - GroupCallParticipant participant(participants[0]); + GroupCallParticipant participant(participants[0], version); if (participant.is_valid()) { process_my_group_call_participant(input_group_call_id, std::move(participant)); } @@ -1654,7 +1658,7 @@ void GroupCallManager::process_group_call_participants( } if (!need_group_call_participants(input_group_call_id)) { for (auto &group_call_participant : participants) { - GroupCallParticipant participant(group_call_participant); + GroupCallParticipant participant(group_call_participant, version); if (!participant.is_valid()) { LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); continue; @@ -1684,7 +1688,7 @@ void GroupCallManager::process_group_call_participants( bool can_manage = can_manage_group_call(input_group_call_id); bool joined_date_asc = get_group_call_joined_date_asc(input_group_call_id); for (auto &group_call_participant : participants) { - GroupCallParticipant participant(group_call_participant); + GroupCallParticipant participant(group_call_participant, version); if (!participant.is_valid()) { LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); continue; diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 4dd0ed5e0..018a6413d 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -197,7 +197,7 @@ class GroupCallManager : public Actor { void process_group_call_participants(InputGroupCallId group_call_id, vector> &&participants, - const string &offset, bool is_load, bool is_sync); + int32 version, const string &offset, bool is_load, bool is_sync); bool update_group_call_participant_can_be_muted(bool can_manage, const GroupCallParticipants *participants, GroupCallParticipant &participant); diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index c079fe249..aedcfe37b 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -14,7 +14,8 @@ namespace td { -GroupCallParticipant::GroupCallParticipant(const tl_object_ptr &participant) { +GroupCallParticipant::GroupCallParticipant(const tl_object_ptr &participant, + int32 call_version) { CHECK(participant != nullptr); dialog_id = DialogId(participant->peer_); about = std::move(participant->about_); @@ -51,6 +52,7 @@ GroupCallParticipant::GroupCallParticipant(const tl_object_ptrjust_joined_; is_min = participant->min_; + version = call_version; } bool GroupCallParticipant::is_versioned_update(const tl_object_ptr &participant) { diff --git a/td/telegram/GroupCallParticipant.h b/td/telegram/GroupCallParticipant.h index 488b7c71b..7044ddee9 100644 --- a/td/telegram/GroupCallParticipant.h +++ b/td/telegram/GroupCallParticipant.h @@ -43,6 +43,7 @@ struct GroupCallParticipant { bool is_speaking = false; int32 local_active_date = 0; GroupCallParticipantOrder order; + int32 version = 0; int32 pending_volume_level = 0; uint64 pending_volume_level_generation = 0; @@ -62,7 +63,7 @@ struct GroupCallParticipant { GroupCallParticipant() = default; - explicit GroupCallParticipant(const tl_object_ptr &participant); + GroupCallParticipant(const tl_object_ptr &participant, int32 call_version); static bool is_versioned_update(const tl_object_ptr &participant); diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 7f1259a98..69a05d968 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -31573,7 +31573,7 @@ tl_object_ptr MessagesManager::get_chat_event_action_ob } case telegram_api::channelAdminLogEventActionParticipantMute::ID: { auto action = move_tl_object_as(action_ptr); - GroupCallParticipant participant(std::move(action->participant_)); + GroupCallParticipant participant(std::move(action->participant_), 0); if (!participant.is_valid()) { return nullptr; } @@ -31582,7 +31582,7 @@ tl_object_ptr MessagesManager::get_chat_event_action_ob } case telegram_api::channelAdminLogEventActionParticipantUnmute::ID: { auto action = move_tl_object_as(action_ptr); - GroupCallParticipant participant(std::move(action->participant_)); + GroupCallParticipant participant(std::move(action->participant_), 0); if (!participant.is_valid()) { return nullptr; } @@ -31591,7 +31591,7 @@ tl_object_ptr MessagesManager::get_chat_event_action_ob } case telegram_api::channelAdminLogEventActionParticipantVolume::ID: { auto action = move_tl_object_as(action_ptr); - GroupCallParticipant participant(std::move(action->participant_)); + GroupCallParticipant participant(std::move(action->participant_), 0); if (!participant.is_valid()) { return nullptr; } From af7e26bc49b441a4d008073fe8b857b4cdf5e198 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 02:51:50 +0300 Subject: [PATCH 092/281] Try to process versioned updates with old version. --- td/telegram/GroupCallManager.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 3055e6baf..bc776131d 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1532,8 +1532,8 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup for (auto &participant_it : participants) { auto &participant = participant_it.second; on_participant_speaking_in_group_call(input_group_call_id, participant); - if (participant.is_self) { - process_my_group_call_participant(input_group_call_id, std::move(participant)); + if (participant.is_self || participant.joined_date != 0) { + diff += process_group_call_participant(input_group_call_id, std::move(participant)); } } LOG(INFO) << "Ignore already applied updateGroupCallParticipants with version " << version << " in " @@ -1856,6 +1856,11 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou return -1; } + if (old_participant.version > participant.version) { + LOG(INFO) << "Ignore outdated update of " << old_participant.dialog_id; + return 0; + } + if (old_participant.dialog_id != participant.dialog_id) { on_remove_group_call_participant(input_group_call_id, old_participant.dialog_id); on_add_group_call_participant(input_group_call_id, participant.dialog_id); From cebcdbd88bea26d96388ced2138428c7fc9b62dc Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 03:30:39 +0300 Subject: [PATCH 093/281] Automatically call update_group_call_dialog in set_group_call_participant_count. --- td/telegram/GroupCallManager.cpp | 13 +++++-------- td/telegram/GroupCallManager.h | 5 +++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index bc776131d..c533b695e 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1315,8 +1315,6 @@ void GroupCallManager::on_get_group_call_participants( } set_group_call_participant_count(group_call, real_participant_count, "on_get_group_call_participants"); need_update = true; - - update_group_call_dialog(group_call, "on_get_group_call_participants"); } if (!is_empty && is_sync && group_call->loaded_all_participants && group_call->participant_count > 50) { group_call->loaded_all_participants = false; @@ -1404,7 +1402,6 @@ void GroupCallManager::on_update_group_call_participants( if (diff != 0 && (group_call->participant_count != 0 || diff > 0)) { set_group_call_participant_count(group_call, group_call->participant_count + diff, "on_update_group_call_participants"); - update_group_call_dialog(group_call, "on_update_group_call_participants"); need_update = true; } } @@ -1580,7 +1577,6 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup set_group_call_participant_count(group_call, group_call->participant_count + diff, "process_pending_group_call_participant_updates"); need_update = true; - update_group_call_dialog(group_call, "process_pending_group_call_participant_updates"); } if (is_left && group_call->is_joined) { on_group_call_left_impl(group_call, need_rejoin); @@ -2168,9 +2164,8 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di int diff = process_group_call_participant(input_group_call_id, std::move(participant)); if (diff != 0) { CHECK(diff == 1); - set_group_call_participant_count(group_call, group_call->participant_count + diff, "join_group_call"); + set_group_call_participant_count(group_call, group_call->participant_count + diff, "join_group_call", true); need_update = true; - update_group_call_dialog(group_call, "join_group_call", true); } } @@ -3452,7 +3447,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrgroup_call_id << " participant count to " << count << " from " << source; if (count < 0) { @@ -3658,6 +3654,7 @@ void GroupCallManager::set_group_call_participant_count(GroupCall *group_call, i } else { group_call->participant_count = count; } + update_group_call_dialog(group_call, source, force_update); } void GroupCallManager::update_group_call_dialog(const GroupCall *group_call, const char *source, bool force) { diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 018a6413d..a6618bfe3 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -277,9 +277,10 @@ class GroupCallManager : public Actor { void try_clear_group_call_participants(InputGroupCallId input_group_call_id); - static void set_group_call_participant_count(GroupCall *group_call, int32 count, const char *source); + void set_group_call_participant_count(GroupCall *group_call, int32 count, const char *source, + bool force_update = false); - void update_group_call_dialog(const GroupCall *group_call, const char *source, bool force = false); + void update_group_call_dialog(const GroupCall *group_call, const char *source, bool force); vector> get_recent_speakers(const GroupCall *group_call, bool for_update); From 78f5b24f359b3394e6f527b930115cda9e4b1e28 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 04:02:53 +0300 Subject: [PATCH 094/281] Synchronize group call participant_count with known number of participants. --- td/telegram/GroupCallManager.cpp | 72 +++++++++++++++++++------------- td/telegram/GroupCallManager.h | 2 +- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index c533b695e..8008264e8 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1308,17 +1308,17 @@ void GroupCallManager::on_get_group_call_participants( real_participant_count = known_participant_count; } } + if (!is_empty && is_sync && group_call->loaded_all_participants && real_participant_count > 50) { + group_call->loaded_all_participants = false; + need_update = true; + } if (real_participant_count != group_call->participant_count) { if (!is_sync) { LOG(ERROR) << "Have participant count " << group_call->participant_count << " instead of " << real_participant_count << " in " << input_group_call_id << " from " << group_call->dialog_id; } - set_group_call_participant_count(group_call, real_participant_count, "on_get_group_call_participants"); - need_update = true; - } - if (!is_empty && is_sync && group_call->loaded_all_participants && group_call->participant_count > 50) { - group_call->loaded_all_participants = false; - need_update = true; + need_update |= + set_group_call_participant_count(group_call, real_participant_count, "on_get_group_call_participants"); } if (process_pending_group_call_participant_updates(input_group_call_id)) { need_update = false; @@ -1399,11 +1399,8 @@ void GroupCallManager::on_update_group_call_participants( } if (group_call != nullptr && group_call->is_inited && group_call->is_active && group_call->version == -1) { - if (diff != 0 && (group_call->participant_count != 0 || diff > 0)) { - set_group_call_participant_count(group_call, group_call->participant_count + diff, - "on_update_group_call_participants"); - need_update = true; - } + need_update |= set_group_call_participant_count(group_call, group_call->participant_count + diff, + "on_update_group_call_participants"); } if (need_update) { send_update_group_call(group_call, "on_update_group_call_participants"); @@ -1572,12 +1569,8 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup sync_participants_timeout_.cancel_timeout(group_call->group_call_id.get()); } - bool need_update = false; - if (diff != 0 && (group_call->participant_count != 0 || diff > 0)) { - set_group_call_participant_count(group_call, group_call->participant_count + diff, - "process_pending_group_call_participant_updates"); - need_update = true; - } + bool need_update = set_group_call_participant_count(group_call, group_call->participant_count + diff, + "process_pending_group_call_participant_updates"); if (is_left && group_call->is_joined) { on_group_call_left_impl(group_call, need_rejoin); need_update = true; @@ -2164,8 +2157,8 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di int diff = process_group_call_participant(input_group_call_id, std::move(participant)); if (diff != 0) { CHECK(diff == 1); - set_group_call_participant_count(group_call, group_call->participant_count + diff, "join_group_call", true); - need_update = true; + need_update |= + set_group_call_participant_count(group_call, group_call->participant_count + diff, "join_group_call", true); } } @@ -3422,10 +3415,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrparticipant_count) { - set_group_call_participant_count(group_call, call.participant_count, "update_group_call"); - need_update = true; - } + need_update |= set_group_call_participant_count(group_call, call.participant_count, "update_group_call"); if (need_group_call_participants(input_group_call_id, group_call) && !join_params.empty() && group_call->version == -1) { LOG(INFO) << "Init " << call.group_call_id << " version to " << call.version; @@ -3435,7 +3425,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrversion && call.participant_count != group_call->participant_count) { + } else if (call.version == group_call->version) { set_group_call_participant_count(group_call, call.participant_count, "update_group_call fix"); need_update = true; } @@ -3643,18 +3633,44 @@ DialogId GroupCallManager::set_group_call_participant_is_speaking_by_source(Inpu return DialogId(); } -void GroupCallManager::set_group_call_participant_count(GroupCall *group_call, int32 count, const char *source, +bool GroupCallManager::set_group_call_participant_count(GroupCall *group_call, int32 count, const char *source, bool force_update) { CHECK(group_call != nullptr); + CHECK(group_call->is_inited); + if (group_call->participant_count == count) { + return false; + } + LOG(DEBUG) << "Set " << group_call->group_call_id << " participant count to " << count << " from " << source; if (count < 0) { LOG(ERROR) << "Participant count became negative in " << group_call->group_call_id << " in " << group_call->dialog_id << " from " << source; - group_call->participant_count = 0; - } else { - group_call->participant_count = count; + count = 0; } + + auto input_group_call_id = get_input_group_call_id(group_call->group_call_id).ok(); + if (need_group_call_participants(input_group_call_id, group_call)) { + auto known_participant_count = + static_cast(add_group_call_participants(input_group_call_id)->participants.size()); + if (count < known_participant_count) { + if (group_call->is_joined) { + LOG(ERROR) << "Participant count became " << count << " from " << source << ", which is less than known " + << known_participant_count << " number of participants in " << input_group_call_id << " from " + << group_call->dialog_id; + } + count = known_participant_count; + } else if (group_call->loaded_all_participants && count > known_participant_count) { + count = known_participant_count; + } + } + + if (group_call->participant_count == count) { + return false; + } + + group_call->participant_count = count; update_group_call_dialog(group_call, source, force_update); + return true; } void GroupCallManager::update_group_call_dialog(const GroupCall *group_call, const char *source, bool force) { diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index a6618bfe3..12cf6bb7e 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -277,7 +277,7 @@ class GroupCallManager : public Actor { void try_clear_group_call_participants(InputGroupCallId input_group_call_id); - void set_group_call_participant_count(GroupCall *group_call, int32 count, const char *source, + bool set_group_call_participant_count(GroupCall *group_call, int32 count, const char *source, bool force_update = false); void update_group_call_dialog(const GroupCall *group_call, const char *source, bool force); From 2f2d2004e6931f1a282ac76b961dcc92605c5f6b Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 04:28:00 +0300 Subject: [PATCH 095/281] Create Dialog for recently speaking channels. --- td/telegram/GroupCallManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 8008264e8..7ea5e8a31 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -3549,6 +3549,9 @@ void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, for (size_t i = 0; i <= recent_speakers->users.size(); i++) { if (i == recent_speakers->users.size() || recent_speakers->users[i].second <= date) { + if (dialog_id.get_type() != DialogType::User) { + td_->messages_manager_->force_create_dialog(dialog_id, "on_user_speaking_in_group_call"); + } recent_speakers->users.insert(recent_speakers->users.begin() + i, {dialog_id, date}); break; } From 302e5940d4bf6c1299673dd05ee926f945d82cc3 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 15:30:40 +0300 Subject: [PATCH 096/281] Update version to 1.7.3. --- CMakeLists.txt | 2 +- README.md | 2 +- example/cpp/CMakeLists.txt | 2 +- example/uwp/extension.vsixmanifest | 2 +- td/telegram/Td.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d8ef3a17..1f1d7ac71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) -project(TDLib VERSION 1.7.2 LANGUAGES CXX C) +project(TDLib VERSION 1.7.3 LANGUAGES CXX C) if (NOT DEFINED CMAKE_MODULE_PATH) set(CMAKE_MODULE_PATH "") diff --git a/README.md b/README.md index 6f8e88024..d1801d891 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ target_link_libraries(YourTarget PRIVATE Td::TdStatic) Or you could install `TDLib` and then reference it in your CMakeLists.txt like this: ``` -find_package(Td 1.7.2 REQUIRED) +find_package(Td 1.7.3 REQUIRED) target_link_libraries(YourTarget PRIVATE Td::TdStatic) ``` See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/tree/master/example/cpp/CMakeLists.txt). diff --git a/example/cpp/CMakeLists.txt b/example/cpp/CMakeLists.txt index 642bbb07a..5e4c4dfbd 100644 --- a/example/cpp/CMakeLists.txt +++ b/example/cpp/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR) project(TdExample VERSION 1.0 LANGUAGES CXX) -find_package(Td 1.7.2 REQUIRED) +find_package(Td 1.7.3 REQUIRED) add_executable(tdjson_example tdjson_example.cpp) target_link_libraries(tdjson_example PRIVATE Td::TdJson) diff --git a/example/uwp/extension.vsixmanifest b/example/uwp/extension.vsixmanifest index 5d7989ac2..bafff2361 100644 --- a/example/uwp/extension.vsixmanifest +++ b/example/uwp/extension.vsixmanifest @@ -1,6 +1,6 @@ - + TDLib for Universal Windows Platform TDLib is a library for building Telegram clients https://core.telegram.org/tdlib diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 47d4b4516..1b39d9420 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -237,7 +237,7 @@ class Td final : public NetQueryCallback { static td_api::object_ptr static_request(td_api::object_ptr function); private: - static constexpr const char *TDLIB_VERSION = "1.7.2"; + static constexpr const char *TDLIB_VERSION = "1.7.3"; static constexpr int64 ONLINE_ALARM_ID = 0; static constexpr int64 PING_SERVER_ALARM_ID = -1; static constexpr int32 PING_SERVER_TIMEOUT = 300; From efd7838c686025435e9174cf1bbd391a7da68496 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 18:01:25 +0300 Subject: [PATCH 097/281] Add HTTP-gzip test. --- test/data.cpp | 8 ++++++++ test/data.h | 3 +++ test/http.cpp | 31 +++++++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/test/data.cpp b/test/data.cpp index 5f93dda27..a44c163b2 100644 --- a/test/data.cpp +++ b/test/data.cpp @@ -67,6 +67,14 @@ static const char gzip_bomb_arr[] = const char *gzip_bomb = gzip_bomb_arr; const size_t gzip_bomb_size = sizeof(gzip_bomb_arr) - 1; +static const char gzip_arr[] = + "eJztxT1LQmEAgNGXMJEIukNI0pDS0hAUSiCa4uZfELqgQwUFuQjXhkDFisrARajBocmISFA0GstBg4owopuIgdAiKE0SfkSBf6HB5TnLmYnpxMBv89" + "ExVnBN7pWvll_ePZqMpPo2Fg6dT-GQdfbA_zH_eftzVE16g8l9Ze7cP33ZTn2dlPP9XEfpXbyeqtnrm50HS7G0dbzyZpPNSkW_" + "tLmeCCT0pbrzO21otbfjqqyNuIySTjNCRERERERERERERERERERERERERERERERERERE_2k3ZA8YhRBhcb_" + "2XHN7zoR5alwbvfMtEhERERERERERERERERER0ZCqTzREVzKNyvlV8Qf1dzn-"; +const char *gzip = gzip_arr; +const size_t gzip_size = sizeof(gzip_arr) - 1; + static const char sqlite_sample_db_v3_arr[] = "olFZ1MdfY0Abj+LtR9ft6DTZgEHW7/" "z7yAhC07NKr7pBAHWkbQyMPtyVSIW7PLdVaQIHYwLgd7ovQSzD7eTINxZh6Nxpwa8HTynvjhHIdQhtysRL9m3mTEj4mbjU48zq+jcFdsnzG+" diff --git a/test/data.h b/test/data.h index f725f56ea..7f3dacaa4 100644 --- a/test/data.h +++ b/test/data.h @@ -14,6 +14,9 @@ extern const size_t thumbnail_size; extern const char *gzip_bomb; extern const size_t gzip_bomb_size; +extern const char *gzip; +extern const size_t gzip_size; + extern const char *sqlite_sample_db_v3; extern const size_t sqlite_sample_db_v3_size; diff --git a/test/http.cpp b/test/http.cpp index d3549140c..1cc5de26a 100644 --- a/test/http.cpp +++ b/test/http.cpp @@ -68,11 +68,14 @@ static string gen_http_content() { return rand_string(std::numeric_limits::min(), std::numeric_limits::max(), len); } -static string make_http_query(string content, bool is_chunked, bool is_gzip, double gzip_k = 5, +static string make_http_query(string content, bool is_json, bool is_chunked, bool is_gzip, double gzip_k = 5, string zip_override = "") { HttpHeaderCreator hc; hc.init_post("/"); hc.add_header("jfkdlsahhjk", rand_string('a', 'z', Random::fast(1, 2000))); + if (is_json) { + hc.add_header("content-type", "application/json"); + } if (is_gzip) { BufferSlice zip; if (zip_override.empty()) { @@ -102,7 +105,7 @@ static string make_http_query(string content, bool is_chunked, bool is_gzip, dou static string rand_http_query(string content) { bool is_chunked = Random::fast_bool(); bool is_gzip = Random::fast_bool(); - return make_http_query(std::move(content), is_chunked, is_gzip); + return make_http_query(std::move(content), false, is_chunked, is_gzip); } static string join(const std::vector &v) { @@ -216,7 +219,7 @@ TEST(Http, gzip_bomb) { auto gzip_bomb_str = gzdecode(gzdecode(base64url_decode(Slice(gzip_bomb, gzip_bomb_size)).ok()).as_slice()).as_slice().str(); - auto query = make_http_query("", false, true, 0.01, gzip_bomb_str); + auto query = make_http_query("", false, false, true, 0.01, gzip_bomb_str); auto parts = rand_split(query); td::ChainBufferWriter input_writer; auto input = input_writer.extract_reader(); @@ -235,6 +238,26 @@ TEST(Http, gzip_bomb) { } } +TEST(Http, gzip) { + return; + auto gzip_str = gzdecode(base64url_decode(Slice(gzip, gzip_size)).ok()).as_slice().str(); + + td::ChainBufferWriter input_writer; + auto input = input_writer.extract_reader(); + + HttpReader reader; + reader.init(&input, 0, 0); + + auto query = make_http_query("", true, false, true, 0.01, gzip_str); + input_writer.append(query); + input.sync_with_writer(); + + HttpQuery q; + auto r_state = reader.read_next(&q); + ASSERT_TRUE(r_state.is_error()); + ASSERT_EQ(413, r_state.error().code()); +} + TEST(Http, aes_ctr_encode_decode_flow) { auto str = rand_string('a', 'z', 1000000); auto parts = rand_split(str); @@ -418,7 +441,7 @@ TEST(Http, gzip_bomb_with_limit) { gzip_bomb_str = sink.result()->move_as_buffer_slice().as_slice().str(); } - auto query = make_http_query("", false, true, 0.01, gzip_bomb_str); + auto query = make_http_query("", false, false, true, 0.01, gzip_bomb_str); auto parts = rand_split(query); td::ChainBufferWriter input_writer; auto input = input_writer.extract_reader(); From 70b71d569b81c66b25f8f77d9536b1d41fbf091d Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 19 Mar 2021 23:41:19 +0300 Subject: [PATCH 098/281] Use AccessRights::Know when edit channel participants. --- td/telegram/GroupCallManager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 7ea5e8a31..9e21bee55 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -500,8 +500,10 @@ class EditGroupCallParticipantQuery : public Td::ResultHandler { void send(InputGroupCallId input_group_call_id, DialogId dialog_id, bool is_muted, int32 volume_level, bool set_raise_hand, bool raise_hand) { - auto input_peer = MessagesManager::get_input_peer_force(dialog_id); - CHECK(input_peer != nullptr); + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Know); + if (input_peer == nullptr) { + return on_error(0, Status::Error(400, "Can't access the chat")); + } int32 flags = 0; if (set_raise_hand) { From f0e7b211c3cfdd0a4944c1926433f8d448c9549c Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 20 Mar 2021 22:57:34 +0300 Subject: [PATCH 099/281] Use case-insensitive comparison for short mention entities. --- td/telegram/MessageEntity.cpp | 3 ++- test/message_entities.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/td/telegram/MessageEntity.cpp b/td/telegram/MessageEntity.cpp index 0c2469459..79556ac5b 100644 --- a/td/telegram/MessageEntity.cpp +++ b/td/telegram/MessageEntity.cpp @@ -1126,7 +1126,8 @@ vector find_mentions(Slice str) { if (mention.size() >= 5) { return false; } - return get_valid_short_usernames().count(mention) == 0; + auto lowered_mention = to_lower(mention); + return get_valid_short_usernames().count(lowered_mention) == 0; }); return mentions; } diff --git a/test/message_entities.cpp b/test/message_entities.cpp index d65bc320f..18d3a3f4c 100644 --- a/test/message_entities.cpp +++ b/test/message_entities.cpp @@ -44,8 +44,9 @@ TEST(MessageEntities, mention) { check_mention("@abcdefghijklmnopqrstuvwxyz123456", {"@abcdefghijklmnopqrstuvwxyz123456"}); check_mention("@abcdefghijklmnopqrstuvwxyz1234567", {}); check_mention("нет@mention", {}); - check_mention("@ya @gif @wiki @vid @bing @pic @bold @imdb @coub @like @vote @giff @cap ya cap @y @yar @bingg @bin", - {"@gif", "@wiki", "@vid", "@bing", "@pic", "@bold", "@imdb", "@coub", "@like", "@vote", "@bingg"}); + check_mention( + "@ya @gif @wiki @vid @bing @pic @bold @imdb @ImDb @coub @like @vote @giff @cap ya cap @y @yar @bingg @bin", + {"@gif", "@wiki", "@vid", "@bing", "@pic", "@bold", "@imdb", "@ImDb", "@coub", "@like", "@vote", "@bingg"}); }; static void check_bot_command(const td::string &str, const td::vector &expected) { From 9d0f1eaaffdf1b28fb8932321250c191434f2921 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 21 Mar 2021 00:46:36 +0300 Subject: [PATCH 100/281] HttpReader: gix Gzip high watermark. --- tdnet/td/net/HttpReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tdnet/td/net/HttpReader.cpp b/tdnet/td/net/HttpReader.cpp index e302e7a33..59fb703d7 100644 --- a/tdnet/td/net/HttpReader.cpp +++ b/tdnet/td/net/HttpReader.cpp @@ -87,7 +87,7 @@ Result HttpReader::read_next(HttpQuery *query, bool can_be_slow) { gzip_flow_ = GzipByteFlow(Gzip::Mode::Decode); GzipByteFlow::Options options; options.write_watermark.low = 0; - options.write_watermark.high = max(max_post_size_, static_cast(1 << 16)); + options.write_watermark.high = max(max_post_size_, MAX_TOTAL_PARAMETERS_LENGTH + 1); gzip_flow_.set_options(options); gzip_flow_.set_max_output_size(MAX_CONTENT_SIZE); *source >> gzip_flow_; From e1771fa7de1864727fcebf151e7cf81bdd0e5732 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sun, 21 Mar 2021 00:27:18 +0100 Subject: [PATCH 101/281] Add an experimental option to delay get_channel_difference --- README.md | 2 ++ td/telegram/MessagesManager.cpp | 21 ++++++++++++++++++++- td/telegram/MessagesManager.h | 6 ++++-- td/telegram/Td.cpp | 5 +++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 26a226abc..47e67aa9a 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ We added some options: * **delete_file_reference_after_seconds** (positive number) During cleanup, free the memory of the files that have not been touched for more than X seconds * **experiment_enable_file_reference_cleanup** (**true**/false) During cleanup, free the memory of the file references * **experiment_enable_chat_access_hash_cleanup** (**true**/false) During cleanup, clean chats and channels access hash +* **get_channel_difference_delay_milliseconds** (**0**) Delay get_channel_difference n milliseconds every ~3000pts (~300msg). + Don't modify this option unless you have a very large bot that struggles to keep up with start-up updates throughput. ## Custom API functions ### TdApi.OptimizeMemory diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index ac4b49f1a..7ea99f7bd 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -35641,6 +35641,23 @@ class MessagesManager::GetChannelDifferenceLogEvent { } }; +void MessagesManager::get_channel_difference_delayed(DialogId dialog_id, int32 pts, + bool force, double delay_seconds, const char *source) { + if (delay_seconds <= 0.0) { + // Execute get_channel_difference immediatly + get_channel_difference(dialog_id,pts, force, "on_get_channel_difference"); + } else { + // Schedule get_channel_difference + create_actor( + "GetChannelDifferenceDelayedActor", delay_seconds, + PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, pts, force](Result result) { + send_closure(actor_id, &MessagesManager::get_channel_difference, dialog_id, pts, force, + "on_get_channel_difference"); + })) + .release(); + } +} + void MessagesManager::get_channel_difference(DialogId dialog_id, int32 pts, bool force, const char *source) { if (channel_get_difference_retry_timeout_.has_timeout(dialog_id.get())) { LOG(INFO) << "Skip running channels.getDifference for " << dialog_id << " from " << source @@ -36057,7 +36074,9 @@ void MessagesManager::on_get_channel_difference( if (!is_final) { LOG_IF(ERROR, timeout > 0) << "Have timeout in not final ChannelDifference in " << dialog_id; - get_channel_difference(dialog_id, d->pts, true, "on_get_channel_difference"); + auto delay_seconds = static_cast(G()->shared_config() + .get_option_integer("get_channel_difference_delay_milliseconds", 0)) / 1000.0; + get_channel_difference_delayed(dialog_id, d->pts, true, delay_seconds, "on_get_channel_difference"); return; } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index a76aa53ce..b04aa62b2 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1646,8 +1646,8 @@ class MessagesManager : public Actor { static constexpr int32 MAX_SEARCH_MESSAGES = 100; // server side limit static constexpr int32 MIN_SEARCH_PUBLIC_DIALOG_PREFIX_LEN = 4; // server side limit static constexpr int32 MIN_CHANNEL_DIFFERENCE = 10; - static constexpr int32 MAX_CHANNEL_DIFFERENCE = 100; - static constexpr int32 MAX_BOT_CHANNEL_DIFFERENCE = 100000; // server side limit + static constexpr int32 MAX_BOT_CHANNEL_DIFFERENCE = 1000000; // server side limit + static constexpr int32 MAX_CHANNEL_DIFFERENCE = MAX_BOT_CHANNEL_DIFFERENCE; static constexpr int32 MAX_RECENTLY_FOUND_DIALOGS = 30; // some reasonable value static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for chat title static constexpr size_t MAX_DESCRIPTION_LENGTH = 255; // server side limit for chat description @@ -2774,6 +2774,8 @@ class MessagesManager : public Actor { void on_channel_get_difference_timeout(DialogId dialog_id); + void get_channel_difference_delayed(DialogId dialog_id, int32 pts, bool force, double timeout, const char *source); + void get_channel_difference(DialogId dialog_id, int32 pts, bool force, const char *source); void do_get_channel_difference(DialogId dialog_id, int32 pts, bool force, diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 0d32b3111..cb5fa9533 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -7462,6 +7462,11 @@ void Td::on_request(uint64 id, td_api::setOption &request) { return; } break; + case 'g': + if (set_integer_option("get_channel_difference_delay_milliseconds")) { + return; + } + break; case 'i': if (set_boolean_option("ignore_background_updates")) { return; From 48aecf88371a8f27517ff2fc817a9b64b38714ab Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 21 Mar 2021 02:58:29 +0300 Subject: [PATCH 102/281] Improve quoted-string parsing in Content-Disposition header. --- tdnet/td/net/HttpReader.cpp | 64 ++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/tdnet/td/net/HttpReader.cpp b/tdnet/td/net/HttpReader.cpp index 59fb703d7..0b7878800 100644 --- a/tdnet/td/net/HttpReader.cpp +++ b/tdnet/td/net/HttpReader.cpp @@ -270,7 +270,7 @@ Result HttpReader::parse_multipart_form_data(bool can_be_slow) { return Status::Error(431, "Request Header Fields Too Large: total headers size exceeded"); } if (form_data_read_length_ == 0) { - // there is no headers at all + // there are no headers at all return Status::Error(400, "Bad Request: headers in multipart/form-data are empty"); } @@ -324,24 +324,58 @@ Result HttpReader::parse_multipart_form_data(bool can_be_slow) { break; } size_t key_size = key_end - header_value.data(); - auto key = header_value.substr(0, key_size); - key = trim(key); + auto key = trim(header_value.substr(0, key_size)); header_value.remove_prefix(key_size + 1); - const char *value_end = - static_cast(std::memchr(header_value.data(), ';', header_value.size())); - size_t value_size; - if (value_end == nullptr) { - value_size = header_value.size(); - } else { - value_size = value_end - header_value.data(); + + while (!header_value.empty() && is_space(header_value[0])) { + header_value.remove_prefix(1); } - auto value = header_value.substr(0, value_size); - value = trim(value); - if (value.size() > 1u && value[0] == '"' && value.back() == '"') { - value = {value.data() + 1, value.size() - 2}; + + MutableSlice value; + if (!header_value.empty() && header_value[0] == '"') { // quoted-string + char *value_end = header_value.data() + 1; + const char *pos = value_end; + while (true) { + if (pos == header_value.data() + header_value.size()) { + return Status::Error(400, "Bad Request: unclosed quoted string in Content-Disposition header"); + } + char c = *pos++; + if (c == '"') { + break; + } + if (c == '\\') { + if (pos == header_value.data() + header_value.size()) { + return Status::Error(400, "Bad Request: wrong escape sequence in Content-Disposition header"); + } + c = *pos++; + } + *value_end++ = c; + } + value = header_value.substr(1, value_end - header_value.data() - 1); + header_value.remove_prefix(pos - header_value.data()); + + while (!header_value.empty() && is_space(header_value[0])) { + header_value.remove_prefix(1); + } + if (!header_value.empty()) { + if (header_value[0] != ';') { + return Status::Error(400, "Bad Request: expected ';' in Content-Disposition header"); + } + header_value.remove_prefix(1); + } + } else { // token + auto value_end = + static_cast(std::memchr(header_value.data(), ';', header_value.size())); + if (value_end != nullptr) { + auto value_size = static_cast(value_end - header_value.data()); + value = trim(header_value.substr(0, value_size)); + header_value.remove_prefix(value_size + 1); + } else { + value = trim(header_value); + header_value = MutableSlice(); + } } - header_value.remove_prefix(value_size + (header_value.size() > value_size)); if (key == "name") { field_name_ = value; From c6dec21cb691f1a47b2f97f1c2fb4217af6a154d Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 21 Mar 2021 03:13:43 +0300 Subject: [PATCH 103/281] Improve getExternalLinkInfo documentation. --- td/generate/scheme/td_api.tl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index aa7dcf8bb..c647ed31a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4228,7 +4228,7 @@ viewMessages chat_id:int53 message_thread_id:int53 message_ids:vector for //@description Informs TDLib that the message content has been opened (e.g., the user has opened a photo, video, document, location or venue, or has listened to an audio file or voice note message). An updateMessageContentOpened update will be generated if something has changed @chat_id Chat identifier of the message @message_id Identifier of the message with the opened content openMessageContent chat_id:int53 message_id:int53 = Ok; -//@description Returns information about an action to be done when the current user clicks an HTTP link. This method can be used to automatically authorize the current user on a website @link The HTTP link +//@description Returns information about an action to be done when the current user clicks an HTTP link. This method can be used to automatically authorize the current user on a website. Don't use this method for links from secret chats if link preview is disabled in secret chats @link The HTTP link getExternalLinkInfo link:string = LoginUrlInfo; //@description Returns an HTTP URL which can be used to automatically authorize the current user on a website after clicking an HTTP link. Use the method getExternalLinkInfo to find whether a prior user confirmation is needed From 316d87af777687d203d8efedbf1840a251bb64ce Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sun, 21 Mar 2021 13:00:55 +0100 Subject: [PATCH 104/281] Avoid printing an error when delaying get_difference --- td/telegram/MessagesManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 814751bdf..1b4eb3bc0 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -32718,14 +32718,18 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq auto next_message = *it; if (next_message != nullptr) { if (next_message->message_id.is_server()) { + if (G()->shared_config().get_option_integer("get_channel_difference_delay_milliseconds", 0) <= 0) { LOG(ERROR) << "Attach " << message_id << " from " << source << " before " << next_message->message_id << " and after " << previous_message_id << " in " << dialog_id; dump_debug_message_op(d); + } } } else { + if (G()->shared_config().get_option_integer("get_channel_difference_delay_milliseconds", 0) <= 0) { LOG(ERROR) << "Have_next is true, but there is no next message after " << previous_message_id << " from " << source << " in " << dialog_id; dump_debug_message_op(d); + } } } From 06791bbbf3a5c5a5a9ae190739f8ae5355f36954 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 21 Mar 2021 21:55:21 +0300 Subject: [PATCH 105/281] Update layer to 126. --- td/generate/scheme/telegram_api.tl | 12 +++++----- td/telegram/ContactsManager.cpp | 37 ++++++++++++++++++------------ td/telegram/DialogParticipant.cpp | 13 +++++++++-- td/telegram/Version.h | 2 +- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/td/generate/scheme/telegram_api.tl b/td/generate/scheme/telegram_api.tl index b908d8528..03a50c28f 100644 --- a/td/generate/scheme/telegram_api.tl +++ b/td/generate/scheme/telegram_api.tl @@ -607,8 +607,8 @@ channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#447dca4b flags:# user_id:int admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; channelParticipantAdmin#ccbebbaf flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; -channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant; -channelParticipantLeft#c3c6796b user_id:int = ChannelParticipant; +channelParticipantBanned#50a1dfd6 flags:# left:flags.0?true peer:Peer kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant; +channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; @@ -619,10 +619,10 @@ channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; -channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; +channels.channelParticipants#9ab0feaf count:int participants:Vector chats:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; -channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; +channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector users:Vector = channels.ChannelParticipant; help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; @@ -1544,7 +1544,7 @@ channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = mes channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; -channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; +channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates; @@ -1560,7 +1560,7 @@ channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true = messages.Chats; -channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates; +channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index ef5230fa8..9035a6bbd 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -2346,12 +2346,12 @@ class EditChannelBannedQuery : public Td::ResultHandler { explicit EditChannelBannedQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(ChannelId channel_id, tl_object_ptr &&input_user, DialogParticipantStatus status) { + void send(ChannelId channel_id, tl_object_ptr &&input_peer, DialogParticipantStatus status) { channel_id_ = channel_id; auto input_channel = td->contacts_manager_->get_input_channel(channel_id); CHECK(input_channel != nullptr); send_query(G()->net_query_creator().create(telegram_api::channels_editBanned( - std::move(input_channel), std::move(input_user), status.get_chat_banned_rights()))); + std::move(input_channel), std::move(input_peer), status.get_chat_banned_rights()))); } void on_result(uint64 id, BufferSlice packet) override { @@ -2911,18 +2911,18 @@ class GetChannelParticipantQuery : public Td::ResultHandler { explicit GetChannelParticipantQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(ChannelId channel_id, UserId user_id, tl_object_ptr &&input_user) { + void send(ChannelId channel_id, UserId user_id, tl_object_ptr &&input_peer) { auto input_channel = td->contacts_manager_->get_input_channel(channel_id); if (input_channel == nullptr) { return promise_.set_error(Status::Error(3, "Supergroup not found")); } - CHECK(input_user != nullptr); + CHECK(input_peer != nullptr); channel_id_ = channel_id; user_id_ = user_id; send_query(G()->net_query_creator().create( - telegram_api::channels_getParticipant(std::move(input_channel), std::move(input_user)))); + telegram_api::channels_getParticipant(std::move(input_channel), std::move(input_peer)))); } void on_result(uint64 id, BufferSlice packet) override { @@ -2935,6 +2935,7 @@ class GetChannelParticipantQuery : public Td::ResultHandler { LOG(INFO) << "Receive result for GetChannelParticipantQuery: " << to_string(participant); td->contacts_manager_->on_get_users(std::move(participant->users_), "GetChannelParticipantQuery"); + td->contacts_manager_->on_get_chats(std::move(participant->chats_), "GetChannelParticipantQuery"); DialogParticipant result(std::move(participant->participant_)); if (!result.is_valid()) { LOG(ERROR) << "Receive invalid " << result; @@ -3035,6 +3036,7 @@ class GetChannelAdministratorsQuery : public Td::ResultHandler { case telegram_api::channels_channelParticipants::ID: { auto participants = telegram_api::move_object_as(participants_ptr); td->contacts_manager_->on_get_users(std::move(participants->users_), "GetChannelAdministratorsQuery"); + td->contacts_manager_->on_get_chats(std::move(participants->chats_), "GetChannelAdministratorsQuery"); vector administrators; administrators.reserve(participants->participants_.size()); for (auto &participant : participants->participants_) { @@ -4530,6 +4532,10 @@ tl_object_ptr ContactsManager::get_input_peer_user(User } const User *u = get_user(user_id); if (!have_input_peer_user(u, access_rights)) { + if ((u == nullptr || u->access_hash == -1 || u->is_min_access_hash) && td_->auth_manager_->is_bot() && + user_id.is_valid()) { + return make_tl_object(user_id.get(), 0); + } return nullptr; } @@ -6842,8 +6848,8 @@ void ContactsManager::change_channel_participant_status(ChannelId channel_id, Us return promise.set_error(Status::Error(6, "Chat info not found")); } - auto input_user = get_input_user(user_id); - if (input_user == nullptr) { + auto input_peer = get_input_peer_user(user_id, AccessRights::Read); + if (input_peer == nullptr) { return promise.set_error(Status::Error(6, "User not found")); } @@ -6866,7 +6872,7 @@ void ContactsManager::change_channel_participant_status(ChannelId channel_id, Us }); td_->create_handler(std::move(on_result_promise)) - ->send(channel_id, user_id, std::move(input_user)); + ->send(channel_id, user_id, std::move(input_peer)); } void ContactsManager::change_channel_participant_status_impl(ChannelId channel_id, UserId user_id, @@ -7390,8 +7396,8 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, UserId return promise.set_error(Status::Error(3, "Not in the chat")); } } - auto input_user = get_input_user(user_id); - if (input_user == nullptr) { + auto input_peer = get_input_peer_user(user_id, AccessRights::Read); + if (input_peer == nullptr) { return promise.set_error(Status::Error(3, "User not found")); } @@ -7442,7 +7448,7 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, UserId } speculative_add_channel_user(channel_id, user_id, status, old_status); - td_->create_handler(std::move(promise))->send(channel_id, std::move(input_user), status); + td_->create_handler(std::move(promise))->send(channel_id, std::move(input_peer), status); } ChannelId ContactsManager::migrate_chat_to_megagroup(ChatId chat_id, Promise &promise) { @@ -11591,6 +11597,7 @@ void ContactsManager::on_get_channel_participants( } on_get_users(std::move(channel_participants->users_), "on_get_channel_participants"); + on_get_chats(std::move(channel_participants->chats_), "on_get_channel_participants"); int32 total_count = channel_participants->count_; auto participants = std::move(channel_participants->participants_); LOG(INFO) << "Receive " << participants.size() << " members in " << channel_id; @@ -14763,8 +14770,8 @@ DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id, return result; } - auto input_user = get_input_user(user_id); - if (input_user == nullptr) { + auto input_peer = get_input_peer_user(user_id, AccessRights::Read); + if (input_peer == nullptr) { promise.set_error(Status::Error(6, "User not found")); return DialogParticipant(); } @@ -14776,7 +14783,7 @@ DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id, if (force) { LOG(ERROR) << "Can't find cached BotInfo"; } else { - send_get_user_full_query(user_id, std::move(input_user), std::move(promise), "get_channel_participant"); + send_get_user_full_query(user_id, get_input_user(user_id), std::move(promise), "get_channel_participant"); return DialogParticipant(); } } @@ -14807,7 +14814,7 @@ DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id, }); td_->create_handler(std::move(on_result_promise)) - ->send(channel_id, user_id, std::move(input_user)); + ->send(channel_id, user_id, std::move(input_peer)); return DialogParticipant(); } diff --git a/td/telegram/DialogParticipant.cpp b/td/telegram/DialogParticipant.cpp index 339ea3a37..28a069f05 100644 --- a/td/telegram/DialogParticipant.cpp +++ b/td/telegram/DialogParticipant.cpp @@ -683,6 +683,15 @@ DialogParticipant::DialogParticipant(tl_object_ptr &&participant_ptr) { CHECK(participant_ptr != nullptr); + + auto get_peer_user_id = [](const tl_object_ptr &peer) { + DialogId dialog_id(peer); + if (dialog_id.get_type() == DialogType::User) { + return dialog_id.get_user_id(); + } + return UserId(); + }; + switch (participant_ptr->get_id()) { case telegram_api::channelParticipant::ID: { auto participant = move_tl_object_as(participant_ptr); @@ -712,13 +721,13 @@ DialogParticipant::DialogParticipant(tl_object_ptr(participant_ptr); - *this = {UserId(participant->user_id_), UserId(), 0, DialogParticipantStatus::Left()}; + *this = {get_peer_user_id(participant->peer_), UserId(), 0, DialogParticipantStatus::Left()}; break; } case telegram_api::channelParticipantBanned::ID: { auto participant = move_tl_object_as(participant_ptr); auto is_member = (participant->flags_ & telegram_api::channelParticipantBanned::LEFT_MASK) == 0; - *this = {UserId(participant->user_id_), UserId(participant->kicked_by_), participant->date_, + *this = {get_peer_user_id(participant->peer_), UserId(participant->kicked_by_), participant->date_, get_dialog_participant_status(is_member, std::move(participant->banned_rights_))}; break; } diff --git a/td/telegram/Version.h b/td/telegram/Version.h index 86bbcc059..4a54ad214 100644 --- a/td/telegram/Version.h +++ b/td/telegram/Version.h @@ -8,7 +8,7 @@ namespace td { -constexpr int32 MTPROTO_LAYER = 125; +constexpr int32 MTPROTO_LAYER = 126; enum class Version : int32 { Initial, // 0 From adedc7ad4fdfd723f1620bfd76031d2d11008595 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 22 Mar 2021 04:03:24 +0300 Subject: [PATCH 106/281] Support chats as members of other chats. --- td/generate/scheme/td_api.tl | 15 +-- td/telegram/ContactsManager.cpp | 173 ++++++++++++++++++------------ td/telegram/DialogParticipant.cpp | 35 +++--- td/telegram/DialogParticipant.h | 21 ++-- td/telegram/GroupCallManager.cpp | 21 ++-- td/telegram/MessagesManager.cpp | 21 ++-- td/telegram/Version.h | 1 + 7 files changed, 164 insertions(+), 123 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 70fe209a9..8e30b2f2a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -477,20 +477,21 @@ chatMemberStatusMember = ChatMemberStatus; //@permissions User permissions in the chat chatMemberStatusRestricted is_member:Bool restricted_until_date:int32 permissions:chatPermissions = ChatMemberStatus; -//@description The user is not a chat member +//@description The user or the chat is not a chat member chatMemberStatusLeft = ChatMemberStatus; -//@description The user was banned (and hence is not a member of the chat). Implies the user can't return to the chat or view messages +//@description The user or the chat was banned (and hence is not a member of the chat). Implies the user can't return to the chat, view messages, or be used as an alias to join a voice chat of the chat //@banned_until_date Point in time (Unix timestamp) when the user will be unbanned; 0 if never. If the user is banned for more than 366 days or for less than 30 seconds from the current time, the user is considered to be banned forever. Always 0 in basic groups chatMemberStatusBanned banned_until_date:int32 = ChatMemberStatus; -//@description A user with information about joining/leaving a chat @user_id User identifier of the chat member +//@description Information about a user or a chat as a member of another chat +//@member_id Identifier of the chat member. Currently, other chats can be only Left or Banned. Only supergroups and channels can have other chats as Left or Banned members and these chats must be supergroups or channels //@inviter_user_id Identifier of a user that invited/promoted/banned this member in the chat; 0 if unknown //@joined_chat_date Point in time (Unix timestamp) when the user joined the chat //@status Status of the member in the chat //@bot_info If the user is a bot, information about the bot; may be null. Can be null even for a bot if the bot is not the chat member -chatMember user_id:int32 inviter_user_id:int32 joined_chat_date:int32 status:ChatMemberStatus bot_info:botInfo = ChatMember; +chatMember member_id:MessageSender inviter_user_id:int32 joined_chat_date:int32 status:ChatMemberStatus bot_info:botInfo = ChatMember; //@description Contains a list of chat members @total_count Approximate total count of chat members found @members A list of chat members chatMembers total_count:int32 members:vector = ChatMembers; @@ -2411,11 +2412,11 @@ chatEventMemberLeft = ChatEventAction; //@description A new chat member was invited @user_id New member user identifier @status New member status chatEventMemberInvited user_id:int32 status:ChatMemberStatus = ChatEventAction; -//@description A chat member has gained/lost administrator status, or the list of their administrator privileges has changed @user_id Chat member user identifier @old_status Previous status of the chat member @new_status New status of the chat member +//@description A chat member has gained/lost administrator status, or the list of their administrator privileges has changed @user_id Affected chat member user identifier @old_status Previous status of the chat member @new_status New status of the chat member chatEventMemberPromoted user_id:int32 old_status:ChatMemberStatus new_status:ChatMemberStatus = ChatEventAction; -//@description A chat member was restricted/unrestricted or banned/unbanned, or the list of their restrictions has changed @user_id Chat member user identifier @old_status Previous status of the chat member @new_status New status of the chat member -chatEventMemberRestricted user_id:int32 old_status:ChatMemberStatus new_status:ChatMemberStatus = ChatEventAction; +//@description A chat member was restricted/unrestricted or banned/unbanned, or the list of their restrictions has changed @member_id Affected chat member identifier @old_status Previous status of the chat member @new_status New status of the chat member +chatEventMemberRestricted member_id:MessageSender old_status:ChatMemberStatus new_status:ChatMemberStatus = ChatEventAction; //@description The chat title was changed @old_title Previous chat title @new_title New chat title chatEventTitleChanged old_title:string new_title:string = ChatEventAction; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 9035a6bbd..143a3c0d0 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -2946,7 +2946,7 @@ class GetChannelParticipantQuery : public Td::ResultHandler { void on_error(uint64 id, Status status) override { if (status.message() == "USER_NOT_PARTICIPANT") { - promise_.set_value(DialogParticipant::left(user_id_)); + promise_.set_value(DialogParticipant::left(DialogId(user_id_))); return; } @@ -3041,11 +3041,12 @@ class GetChannelAdministratorsQuery : public Td::ResultHandler { administrators.reserve(participants->participants_.size()); for (auto &participant : participants->participants_) { DialogParticipant dialog_participant(std::move(participant)); - if (!dialog_participant.is_valid() || !dialog_participant.status.is_administrator()) { + if (!dialog_participant.is_valid() || !dialog_participant.status.is_administrator() || + dialog_participant.dialog_id.get_type() != DialogType::User) { LOG(ERROR) << "Receive " << dialog_participant << " as an administrator of " << channel_id_; continue; } - administrators.emplace_back(dialog_participant.user_id, dialog_participant.status.get_rank(), + administrators.emplace_back(dialog_participant.dialog_id.get_user_id(), dialog_participant.status.get_rank(), dialog_participant.status.is_creator()); } @@ -9428,7 +9429,7 @@ void ContactsManager::on_load_chat_full_from_database(ChatId chat_id, string val dependencies.chat_ids.insert(chat_id); dependencies.user_ids.insert(chat_full->creator_user_id); for (auto &participant : chat_full->participants) { - dependencies.user_ids.insert(participant.user_id); + add_message_sender_dependencies(dependencies, participant.dialog_id); dependencies.user_ids.insert(participant.inviter_user_id); } dependencies.user_ids.insert(chat_full->invite_link.get_creator_user_id()); @@ -9439,7 +9440,9 @@ void ContactsManager::on_load_chat_full_from_database(ChatId chat_id, string val } for (auto &participant : chat_full->participants) { - get_bot_info_force(participant.user_id); + if (participant.dialog_id.get_type() == DialogType::User) { + get_bot_info_force(participant.dialog_id.get_user_id()); + } } Chat *c = get_chat(chat_id); @@ -9978,12 +9981,15 @@ void ContactsManager::update_chat_full(ChatFull *chat_full, ChatId chat_id, bool vector administrators; vector bot_user_ids; for (const auto &participant : chat_full->participants) { - auto user_id = participant.user_id; - if (participant.status.is_administrator()) { - administrators.emplace_back(user_id, participant.status.get_rank(), participant.status.is_creator()); + if (participant.status.is_administrator() && participant.dialog_id.get_type() == DialogType::User) { + administrators.emplace_back(participant.dialog_id.get_user_id(), participant.status.get_rank(), + participant.status.is_creator()); } - if (is_user_bot(user_id)) { - bot_user_ids.push_back(user_id); + if (participant.dialog_id.get_type() == DialogType::User) { + auto user_id = participant.dialog_id.get_user_id(); + if (is_user_bot(user_id)) { + bot_user_ids.push_back(user_id); + } } } on_update_dialog_administrators(DialogId(chat_id), std::move(administrators), chat_full->version != -1, @@ -11388,9 +11394,13 @@ void ContactsManager::update_dialog_online_member_count(const vectorunix_time(); for (const auto &participant : participants) { - auto u = get_user(participant.user_id); + if (participant.dialog_id.get_type() != DialogType::User) { + continue; + } + auto user_id = participant.dialog_id.get_user_id(); + auto u = get_user(user_id); if (u != nullptr && !u->is_deleted && !u->is_bot) { - if (get_user_was_online(u, participant.user_id) > time) { + if (get_user_was_online(u, user_id) > time) { online_member_count++; } if (is_from_server) { @@ -11453,18 +11463,18 @@ void ContactsManager::on_get_chat_participants(tl_object_ptrmessages_manager_->have_dialog_info(dialog_participant.dialog_id)) + << "Have no information about " << dialog_participant.dialog_id << " as a member of " << chat_id; LOG_IF(ERROR, !have_user(dialog_participant.inviter_user_id)) << "Have no information about " << dialog_participant.inviter_user_id << " as a member of " << chat_id; if (dialog_participant.joined_date < c->date) { LOG_IF(ERROR, dialog_participant.joined_date < c->date - 30 && c->date >= 1486000000) - << "Wrong join date = " << dialog_participant.joined_date << " for " << dialog_participant.user_id << ", " - << chat_id << " was created at " << c->date; + << "Wrong join date = " << dialog_participant.joined_date << " for " << dialog_participant.dialog_id + << ", " << chat_id << " was created at " << c->date; dialog_participant.joined_date = c->date; } - if (dialog_participant.status.is_creator()) { - new_creator_user_id = dialog_participant.user_id; + if (dialog_participant.status.is_creator() && dialog_participant.dialog_id.get_type() == DialogType::User) { + new_creator_user_id = dialog_participant.dialog_id.get_user_id(); } new_participants.push_back(std::move(dialog_participant)); } @@ -11498,7 +11508,7 @@ const DialogParticipant *ContactsManager::get_chat_participant(ChatId chat_id, U const DialogParticipant *ContactsManager::get_chat_full_participant(const ChatFull *chat_full, UserId user_id) { for (const auto &dialog_participant : chat_full->participants) { - if (dialog_participant.user_id == user_id) { + if (dialog_participant.dialog_id == DialogId(user_id)) { return &dialog_participant; } } @@ -11507,9 +11517,12 @@ const DialogParticipant *ContactsManager::get_chat_full_participant(const ChatFu tl_object_ptr ContactsManager::get_chat_member_object( const DialogParticipant &dialog_participant) const { - UserId participant_user_id = dialog_participant.user_id; + UserId participant_user_id; + if (dialog_participant.dialog_id.get_type() == DialogType::User) { + participant_user_id = dialog_participant.dialog_id.get_user_id(); + } return td_api::make_object( - get_user_id_object(participant_user_id, "chatMember.user_id"), + td_->messages_manager_->get_message_sender_object_const(dialog_participant.dialog_id), get_user_id_object(dialog_participant.inviter_user_id, "chatMember.inviter_user_id"), dialog_participant.joined_date, dialog_participant.status.get_chat_member_status_object(), get_bot_info_object(participant_user_id)); @@ -11609,14 +11622,18 @@ void ContactsManager::on_get_channel_participants( auto debug_participant = to_string(participant_ptr); result.emplace_back(std::move(participant_ptr)); const auto &participant = result.back(); - if (!participant.is_valid() || (filter.is_bots() && !is_user_bot(participant.user_id)) || + UserId participant_user_id; + if (participant.dialog_id.get_type() == DialogType::User) { + participant_user_id = participant.dialog_id.get_user_id(); + } + if (!participant.is_valid() || (filter.is_bots() && !is_user_bot(participant_user_id)) || (filter.is_administrators() && !participant.status.is_administrator()) || ((filter.is_recent() || filter.is_contacts() || filter.is_search()) && !participant.status.is_member()) || - (filter.is_contacts() && !is_user_contact(participant.user_id)) || + (filter.is_contacts() && !is_user_contact(participant_user_id)) || (filter.is_restricted() && !participant.status.is_restricted()) || (filter.is_banned() && !participant.status.is_banned())) { - bool skip_error = ((filter.is_administrators() || filter.is_bots()) && is_user_deleted(participant.user_id)) || - (filter.is_contacts() && participant.user_id == get_my_id()); + bool skip_error = ((filter.is_administrators() || filter.is_bots()) && is_user_deleted(participant_user_id)) || + (filter.is_contacts() && participant_user_id == get_my_id()); if (!skip_error) { LOG(ERROR) << "Receive " << participant << ", while searching for " << filter << " in " << channel_id << " with offset " << offset << " and limit " << limit << ": " << oneline(debug_participant); @@ -11645,12 +11662,15 @@ void ContactsManager::on_get_channel_participants( { if (filter.is_recent()) { for (const auto &participant : result) { - if (participant.status.is_administrator()) { - administrators.emplace_back(participant.user_id, participant.status.get_rank(), - participant.status.is_creator()); - } - if (is_user_bot(participant.user_id)) { - bot_user_ids.push_back(participant.user_id); + if (participant.dialog_id.get_type() == DialogType::User) { + auto participant_user_id = participant.dialog_id.get_user_id(); + if (participant.status.is_administrator()) { + administrators.emplace_back(participant_user_id, participant.status.get_rank(), + participant.status.is_creator()); + } + if (is_user_bot(participant_user_id)) { + bot_user_ids.push_back(participant_user_id); + } } } administrator_count = narrow_cast(administrators.size()); @@ -11661,11 +11681,16 @@ void ContactsManager::on_get_channel_participants( } } else if (filter.is_administrators()) { for (const auto &participant : result) { - administrators.emplace_back(participant.user_id, participant.status.get_rank(), - participant.status.is_creator()); + if (participant.dialog_id.get_type() == DialogType::User) { + administrators.emplace_back(participant.dialog_id.get_user_id(), participant.status.get_rank(), + participant.status.is_creator()); + } } } else if (filter.is_bots()) { - bot_user_ids = transform(result, [](const DialogParticipant &participant) { return participant.user_id; }); + bot_user_ids = transform(result, [](const DialogParticipant &participant) { + CHECK(participant.dialog_id.get_type() == DialogType::User); + return participant.dialog_id.get_user_id(); + }); } } if (filter.is_administrators() || filter.is_recent()) { @@ -11709,7 +11734,9 @@ void ContactsManager::on_get_channel_participants( } if (!additional_query.empty()) { - auto user_ids = transform(result, [](const auto &participant) { return participant.user_id; }); + auto dialog_ids = transform(result, [](const DialogParticipant &participant) { return participant.dialog_id; }); + td::remove_if(dialog_ids, [](DialogId dialog_id) { return dialog_id.get_type() != DialogType::User; }); + auto user_ids = transform(dialog_ids, [](DialogId dialog_id) { return dialog_id.get_user_id(); }); std::pair> result_user_ids = search_among_users(user_ids, additional_query, additional_limit); total_count = result_user_ids.first; @@ -11718,9 +11745,12 @@ void ContactsManager::on_get_channel_participants( auto all_participants = std::move(result); result.clear(); for (auto &participant : all_participants) { - if (result_user_ids_set.count(participant.user_id)) { + if (participant.dialog_id.get_type() != DialogType::User) { + continue; + } + if (result_user_ids_set.count(participant.dialog_id.get_user_id())) { + result_user_ids_set.erase(participant.dialog_id.get_user_id()); result.push_back(std::move(participant)); - result_user_ids_set.erase(participant.user_id); } } } @@ -11759,14 +11789,14 @@ void ContactsManager::speculative_add_channel_participants(ChannelId channel_id, auto &participants = it->second; bool is_found = false; for (auto &participant : participants) { - if (participant.user_id == user_id) { + if (participant.dialog_id == DialogId(user_id)) { is_found = true; break; } } if (!is_found) { is_participants_cache_changed = true; - participants.emplace_back(user_id, inviter_user_id, date, DialogParticipantStatus::Member()); + participants.emplace_back(DialogId(user_id), inviter_user_id, date, DialogParticipantStatus::Member()); } } @@ -11797,7 +11827,7 @@ void ContactsManager::speculative_delete_channel_participant(ChannelId channel_i if (it != cached_channel_participants_.end()) { auto &participants = it->second; for (size_t i = 0; i < participants.size(); i++) { - if (participants[i].user_id == deleted_user_id) { + if (participants[i].dialog_id == DialogId(deleted_user_id)) { participants.erase(participants.begin() + i); update_channel_online_member_count(channel_id, false); break; @@ -11909,7 +11939,7 @@ void ContactsManager::speculative_add_channel_user(ChannelId channel_id, UserId auto &participants = it->second; bool is_found = false; for (size_t i = 0; i < participants.size(); i++) { - if (participants[i].user_id == user_id) { + if (participants[i].dialog_id == DialogId(user_id)) { if (!new_status.is_member()) { participants.erase(participants.begin() + i); update_channel_online_member_count(channel_id, false); @@ -11921,7 +11951,7 @@ void ContactsManager::speculative_add_channel_user(ChannelId channel_id, UserId } } if (!is_found && new_status.is_member()) { - participants.emplace_back(user_id, get_my_id(), G()->unix_time(), new_status); + participants.emplace_back(DialogId(user_id), get_my_id(), G()->unix_time(), new_status); update_channel_online_member_count(channel_id, false); } } @@ -12473,7 +12503,7 @@ void ContactsManager::on_update_chat_add_user(ChatId chat_id, UserId inviter_use } if (on_update_chat_full_participants_short(chat_full, chat_id, version)) { for (auto &participant : chat_full->participants) { - if (participant.user_id == user_id) { + if (participant.dialog_id == DialogId(user_id)) { if (participant.inviter_user_id != inviter_user_id) { LOG(ERROR) << user_id << " was readded to " << chat_id << " by " << inviter_user_id << ", previously invited by " << participant.inviter_user_id; @@ -12487,7 +12517,7 @@ void ContactsManager::on_update_chat_add_user(ChatId chat_id, UserId inviter_use return; } } - chat_full->participants.push_back(DialogParticipant{user_id, inviter_user_id, date, + chat_full->participants.push_back(DialogParticipant{DialogId(user_id), inviter_user_id, date, user_id == chat_full->creator_user_id ? DialogParticipantStatus::Creator(true, false, string()) : DialogParticipantStatus::Member()}); @@ -12562,7 +12592,7 @@ void ContactsManager::on_update_chat_edit_administrator(ChatId chat_id, UserId u if (chat_full != nullptr) { if (chat_full->version + 1 == version) { for (auto &participant : chat_full->participants) { - if (participant.user_id == user_id) { + if (participant.dialog_id == DialogId(user_id)) { participant.status = std::move(status); chat_full->is_changed = true; update_chat_full(chat_full, chat_id); @@ -12613,7 +12643,7 @@ void ContactsManager::on_update_chat_delete_user(ChatId chat_id, UserId user_id, } if (on_update_chat_full_participants_short(chat_full, chat_id, version)) { for (size_t i = 0; i < chat_full->participants.size(); i++) { - if (chat_full->participants[i].user_id == user_id) { + if (chat_full->participants[i].dialog_id == DialogId(user_id)) { chat_full->participants[i] = chat_full->participants.back(); chat_full->participants.resize(chat_full->participants.size() - 1); chat_full->is_changed = true; @@ -13220,8 +13250,8 @@ void ContactsManager::on_update_bot_stopped(UserId user_id, int32 date, bool is_ return; } - DialogParticipant old_dialog_participant(get_my_id(), user_id, date, DialogParticipantStatus::Banned(0)); - DialogParticipant new_dialog_participant(get_my_id(), user_id, date, DialogParticipantStatus::Member()); + DialogParticipant old_dialog_participant(DialogId(get_my_id()), user_id, date, DialogParticipantStatus::Banned(0)); + DialogParticipant new_dialog_participant(DialogId(get_my_id()), user_id, date, DialogParticipantStatus::Member()); if (is_stopped) { std::swap(old_dialog_participant.status, new_dialog_participant.status); } @@ -13256,15 +13286,15 @@ void ContactsManager::on_update_chat_participant(ChatId chat_id, UserId user_id, if (old_participant != nullptr) { old_dialog_participant = DialogParticipant(std::move(old_participant), c->date, c->status.is_creator()); if (new_participant == nullptr) { - new_dialog_participant = DialogParticipant::left(old_dialog_participant.user_id); + new_dialog_participant = DialogParticipant::left(old_dialog_participant.dialog_id); } else { new_dialog_participant = DialogParticipant(std::move(new_participant), c->date, c->status.is_creator()); } } else { new_dialog_participant = DialogParticipant(std::move(new_participant), c->date, c->status.is_creator()); - old_dialog_participant = DialogParticipant::left(new_dialog_participant.user_id); + old_dialog_participant = DialogParticipant::left(new_dialog_participant.dialog_id); } - if (old_dialog_participant.user_id != new_dialog_participant.user_id || !old_dialog_participant.is_valid() || + if (old_dialog_participant.dialog_id != new_dialog_participant.dialog_id || !old_dialog_participant.is_valid() || !new_dialog_participant.is_valid()) { LOG(ERROR) << "Receive wrong updateChannelParticipant: " << old_dialog_participant << " -> " << new_dialog_participant; @@ -13295,15 +13325,15 @@ void ContactsManager::on_update_channel_participant(ChannelId channel_id, UserId if (old_participant != nullptr) { old_dialog_participant = DialogParticipant(std::move(old_participant)); if (new_participant == nullptr) { - new_dialog_participant = DialogParticipant::left(old_dialog_participant.user_id); + new_dialog_participant = DialogParticipant::left(old_dialog_participant.dialog_id); } else { new_dialog_participant = DialogParticipant(std::move(new_participant)); } } else { new_dialog_participant = DialogParticipant(std::move(new_participant)); - old_dialog_participant = DialogParticipant::left(new_dialog_participant.user_id); + old_dialog_participant = DialogParticipant::left(new_dialog_participant.dialog_id); } - if (old_dialog_participant.user_id != new_dialog_participant.user_id || !old_dialog_participant.is_valid() || + if (old_dialog_participant.dialog_id != new_dialog_participant.dialog_id || !old_dialog_participant.is_valid() || !new_dialog_participant.is_valid()) { LOG(ERROR) << "Receive wrong updateChannelParticipant: " << old_dialog_participant << " -> " << new_dialog_participant; @@ -13884,11 +13914,14 @@ bool ContactsManager::is_chat_full_outdated(const ChatFull *chat_full, const Cha } for (const auto &participant : chat_full->participants) { - auto u = get_user(participant.user_id); - if (u != nullptr && is_bot_info_expired(participant.user_id, u->bot_info_version)) { - LOG(INFO) << "Have outdated botInfo for " << participant.user_id << " in " << chat_id << "; expected version " - << u->bot_info_version; - return true; + if (participant.dialog_id.get_type() == DialogType::User) { + auto user_id = participant.dialog_id.get_user_id(); + auto u = get_user(user_id); + if (u != nullptr && is_bot_info_expired(user_id, u->bot_info_version)) { + LOG(INFO) << "Have outdated botInfo for " << user_id << " in " << chat_id << "; expected version " + << u->bot_info_version; + return true; + } } } @@ -14512,11 +14545,11 @@ DialogParticipant ContactsManager::get_dialog_participant(DialogId dialog_id, Us auto peer_user_id = dialog_id.get_user_id(); if (user_id == get_my_id()) { promise.set_value(Unit()); - return {user_id, peer_user_id, 0, DialogParticipantStatus::Member()}; + return {DialogId(user_id), peer_user_id, 0, DialogParticipantStatus::Member()}; } if (user_id == peer_user_id) { promise.set_value(Unit()); - return {peer_user_id, user_id, 0, DialogParticipantStatus::Member()}; + return {DialogId(peer_user_id), user_id, 0, DialogParticipantStatus::Member()}; } promise.set_error(Status::Error(3, "User is not a member of the private chat")); @@ -14530,11 +14563,12 @@ DialogParticipant ContactsManager::get_dialog_participant(DialogId dialog_id, Us auto peer_user_id = get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (user_id == get_my_id()) { promise.set_value(Unit()); - return {user_id, peer_user_id.is_valid() ? peer_user_id : user_id, 0, DialogParticipantStatus::Member()}; + return {DialogId(user_id), peer_user_id.is_valid() ? peer_user_id : user_id, 0, + DialogParticipantStatus::Member()}; } if (peer_user_id.is_valid() && user_id == peer_user_id) { promise.set_value(Unit()); - return {peer_user_id, user_id, 0, DialogParticipantStatus::Member()}; + return {DialogId(peer_user_id), user_id, 0, DialogParticipantStatus::Member()}; } promise.set_error(Status::Error(3, "User is not a member of the secret chat")); @@ -14585,7 +14619,7 @@ DialogParticipants ContactsManager::search_private_chat_participants(UserId my_u auto result = search_among_users(user_ids, query, limit); return {result.first, transform(result.second, [&](UserId user_id) { - return DialogParticipant(user_id, + return DialogParticipant(DialogId(user_id), user_id == my_user_id && peer_user_id.is_valid() ? peer_user_id : my_user_id, 0, DialogParticipantStatus::Member()); })}; @@ -14685,7 +14719,7 @@ DialogParticipant ContactsManager::get_chat_participant(ChatId chat_id, UserId u auto result = get_chat_participant(chat_id, user_id); if (result == nullptr) { - return DialogParticipant::left(user_id); + return DialogParticipant::left(DialogId(user_id)); } return *result; @@ -14722,9 +14756,12 @@ void ContactsManager::do_search_chat_participants(ChatId chat_id, const string & } auto is_dialog_participant_suitable = [this, filter](const DialogParticipant &participant) { + if (participant.dialog_id.get_type() != DialogType::User) { + return false; + } switch (filter.type) { case DialogParticipantsFilter::Type::Contacts: - return is_user_contact(participant.user_id); + return is_user_contact(participant.dialog_id.get_user_id()); case DialogParticipantsFilter::Type::Administrators: return participant.status.is_administrator(); case DialogParticipantsFilter::Type::Members: @@ -14736,7 +14773,7 @@ void ContactsManager::do_search_chat_participants(ChatId chat_id, const string & case DialogParticipantsFilter::Type::Mention: return true; case DialogParticipantsFilter::Type::Bots: - return is_user_bot(participant.user_id); + return is_user_bot(participant.dialog_id.get_user_id()); default: UNREACHABLE(); return false; @@ -14746,7 +14783,7 @@ void ContactsManager::do_search_chat_participants(ChatId chat_id, const string & vector user_ids; for (const auto &participant : chat_full->participants) { if (is_dialog_participant_suitable(participant)) { - user_ids.push_back(participant.user_id); + user_ids.push_back(participant.dialog_id.get_user_id()); } } diff --git a/td/telegram/DialogParticipant.cpp b/td/telegram/DialogParticipant.cpp index 28a069f05..c27000de4 100644 --- a/td/telegram/DialogParticipant.cpp +++ b/td/telegram/DialogParticipant.cpp @@ -642,9 +642,9 @@ RestrictedRights get_restricted_rights(const td_api::object_ptrcan_pin_messages_); } -DialogParticipant::DialogParticipant(UserId user_id, UserId inviter_user_id, int32 joined_date, +DialogParticipant::DialogParticipant(DialogId dialog_id, UserId inviter_user_id, int32 joined_date, DialogParticipantStatus status) - : user_id(user_id), inviter_user_id(inviter_user_id), joined_date(joined_date), status(status) { + : dialog_id(dialog_id), inviter_user_id(inviter_user_id), joined_date(joined_date), status(status) { if (!inviter_user_id.is_valid() && inviter_user_id != UserId()) { LOG(ERROR) << "Receive inviter " << inviter_user_id; inviter_user_id = UserId(); @@ -660,19 +660,19 @@ DialogParticipant::DialogParticipant(tl_object_ptrget_id()) { case telegram_api::chatParticipant::ID: { auto participant = move_tl_object_as(participant_ptr); - *this = {UserId(participant->user_id_), UserId(participant->inviter_id_), participant->date_, + *this = {DialogId(UserId(participant->user_id_)), UserId(participant->inviter_id_), participant->date_, DialogParticipantStatus::Member()}; break; } case telegram_api::chatParticipantCreator::ID: { auto participant = move_tl_object_as(participant_ptr); - *this = {UserId(participant->user_id_), UserId(participant->user_id_), chat_creation_date, + *this = {DialogId(UserId(participant->user_id_)), UserId(participant->user_id_), chat_creation_date, DialogParticipantStatus::Creator(true, false, string())}; break; } case telegram_api::chatParticipantAdmin::ID: { auto participant = move_tl_object_as(participant_ptr); - *this = {UserId(participant->user_id_), UserId(participant->inviter_id_), participant->date_, + *this = {DialogId(UserId(participant->user_id_)), UserId(participant->inviter_id_), participant->date_, DialogParticipantStatus::GroupAdministrator(is_creator)}; break; } @@ -684,50 +684,43 @@ DialogParticipant::DialogParticipant(tl_object_ptr &&participant_ptr) { CHECK(participant_ptr != nullptr); - auto get_peer_user_id = [](const tl_object_ptr &peer) { - DialogId dialog_id(peer); - if (dialog_id.get_type() == DialogType::User) { - return dialog_id.get_user_id(); - } - return UserId(); - }; - switch (participant_ptr->get_id()) { case telegram_api::channelParticipant::ID: { auto participant = move_tl_object_as(participant_ptr); - *this = {UserId(participant->user_id_), UserId(), participant->date_, DialogParticipantStatus::Member()}; + *this = {DialogId(UserId(participant->user_id_)), UserId(), participant->date_, + DialogParticipantStatus::Member()}; break; } case telegram_api::channelParticipantSelf::ID: { auto participant = move_tl_object_as(participant_ptr); - *this = {UserId(participant->user_id_), UserId(participant->inviter_id_), participant->date_, + *this = {DialogId(UserId(participant->user_id_)), UserId(participant->inviter_id_), participant->date_, DialogParticipantStatus::Member()}; break; } case telegram_api::channelParticipantCreator::ID: { auto participant = move_tl_object_as(participant_ptr); bool is_anonymous = (participant->admin_rights_->flags_ & telegram_api::chatAdminRights::ANONYMOUS_MASK) != 0; - *this = {UserId(participant->user_id_), UserId(), 0, + *this = {DialogId(UserId(participant->user_id_)), UserId(), 0, DialogParticipantStatus::Creator(true, is_anonymous, std::move(participant->rank_))}; break; } case telegram_api::channelParticipantAdmin::ID: { auto participant = move_tl_object_as(participant_ptr); bool can_be_edited = (participant->flags_ & telegram_api::channelParticipantAdmin::CAN_EDIT_MASK) != 0; - *this = {UserId(participant->user_id_), UserId(participant->promoted_by_), participant->date_, + *this = {DialogId(UserId(participant->user_id_)), UserId(participant->promoted_by_), participant->date_, get_dialog_participant_status(can_be_edited, std::move(participant->admin_rights_), std::move(participant->rank_))}; break; } case telegram_api::channelParticipantLeft::ID: { auto participant = move_tl_object_as(participant_ptr); - *this = {get_peer_user_id(participant->peer_), UserId(), 0, DialogParticipantStatus::Left()}; + *this = {DialogId(participant->peer_), UserId(), 0, DialogParticipantStatus::Left()}; break; } case telegram_api::channelParticipantBanned::ID: { auto participant = move_tl_object_as(participant_ptr); auto is_member = (participant->flags_ & telegram_api::channelParticipantBanned::LEFT_MASK) == 0; - *this = {get_peer_user_id(participant->peer_), UserId(participant->kicked_by_), participant->date_, + *this = {DialogId(participant->peer_), UserId(participant->kicked_by_), participant->date_, get_dialog_participant_status(is_member, std::move(participant->banned_rights_))}; break; } @@ -738,7 +731,7 @@ DialogParticipant::DialogParticipant(tl_object_ptr &&participant_ptr, int32 chat_creation_date, bool is_creator); explicit DialogParticipant(tl_object_ptr &&participant_ptr); - static DialogParticipant left(UserId user_id) { - return {user_id, UserId(), 0, DialogParticipantStatus::Left()}; + static DialogParticipant left(DialogId dialog_id) { + return {dialog_id, UserId(), 0, DialogParticipantStatus::Left()}; } bool is_valid() const; template void store(StorerT &storer) const { - td::store(user_id, storer); + td::store(dialog_id, storer); td::store(inviter_user_id, storer); td::store(joined_date, storer); td::store(status, storer); @@ -418,7 +419,13 @@ struct DialogParticipant { template void parse(ParserT &parser) { - td::parse(user_id, parser); + if (parser.version() >= static_cast(Version::SupportBannedChannels)) { + td::parse(dialog_id, parser); + } else { + UserId user_id; + td::parse(user_id, parser); + dialog_id = DialogId(user_id); + } td::parse(inviter_user_id, parser); td::parse(joined_date, parser); td::parse(status, parser); diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index b5f3f6dc2..745c7515c 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -675,7 +675,7 @@ struct GroupCallManager::GroupCallParticipants { bool joined_date_asc = false; bool are_administrators_loaded = false; - vector administrator_user_ids; + vector administrator_dialog_ids; struct PendingUpdates { std::unordered_map updates; @@ -1790,8 +1790,7 @@ void GroupCallManager::process_group_call_participants( bool GroupCallManager::update_group_call_participant_can_be_muted(bool can_manage, const GroupCallParticipants *participants, GroupCallParticipant &participant) { - bool is_admin = participant.dialog_id.get_type() == DialogType::User && - td::contains(participants->administrator_user_ids, participant.dialog_id.get_user_id()); + bool is_admin = td::contains(participants->administrator_dialog_ids, participant.dialog_id); return participant.update_can_be_muted(can_manage, is_admin); } @@ -2233,23 +2232,24 @@ void GroupCallManager::finish_load_group_call_administrators(InputGroupCallId in return; } - vector administrator_user_ids; + vector administrator_dialog_ids; auto participants = result.move_as_ok(); for (auto &administrator : participants.participants_) { - if (administrator.status.can_manage_calls() && administrator.user_id != td_->contacts_manager_->get_my_id()) { - administrator_user_ids.push_back(administrator.user_id); + if (administrator.status.can_manage_calls() && + administrator.dialog_id != DialogId(td_->contacts_manager_->get_my_id())) { + administrator_dialog_ids.push_back(administrator.dialog_id); } } auto *group_call_participants = add_group_call_participants(input_group_call_id); if (group_call_participants->are_administrators_loaded && - group_call_participants->administrator_user_ids == administrator_user_ids) { + group_call_participants->administrator_dialog_ids == administrator_dialog_ids) { return; } - LOG(INFO) << "Set administrators of " << input_group_call_id << " to " << administrator_user_ids; + LOG(INFO) << "Set administrators of " << input_group_call_id << " to " << administrator_dialog_ids; group_call_participants->are_administrators_loaded = true; - group_call_participants->administrator_user_ids = std::move(administrator_user_ids); + group_call_participants->administrator_dialog_ids = std::move(administrator_dialog_ids); update_group_call_participants_can_be_muted(input_group_call_id, true, group_call_participants); } @@ -2884,8 +2884,7 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ } bool can_manage = can_manage_group_call(input_group_call_id); - bool is_admin = dialog_id.get_type() == DialogType::User && - td::contains(participants->administrator_user_ids, dialog_id.get_user_id()); + bool is_admin = td::contains(participants->administrator_dialog_ids, dialog_id); auto participant_copy = *participant; if (!participant_copy.set_pending_is_muted(is_muted, can_manage, is_admin)) { diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 0d7d36ac1..9bac60842 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -31369,20 +31369,21 @@ tl_object_ptr MessagesManager::get_chat_event_action_ob case telegram_api::channelAdminLogEventActionParticipantInvite::ID: { auto action = move_tl_object_as(action_ptr); DialogParticipant dialog_participant(std::move(action->participant_)); - if (!dialog_participant.is_valid()) { + if (!dialog_participant.is_valid() || dialog_participant.dialog_id.get_type() != DialogType::User) { LOG(ERROR) << "Wrong invite: " << dialog_participant; return nullptr; } return make_tl_object( - td_->contacts_manager_->get_user_id_object(dialog_participant.user_id, "chatEventMemberInvited"), + td_->contacts_manager_->get_user_id_object(dialog_participant.dialog_id.get_user_id(), + "chatEventMemberInvited"), dialog_participant.status.get_chat_member_status_object()); } case telegram_api::channelAdminLogEventActionParticipantToggleBan::ID: { auto action = move_tl_object_as(action_ptr); DialogParticipant old_dialog_participant(std::move(action->prev_participant_)); DialogParticipant new_dialog_participant(std::move(action->new_participant_)); - if (old_dialog_participant.user_id != new_dialog_participant.user_id) { - LOG(ERROR) << old_dialog_participant.user_id << " VS " << new_dialog_participant.user_id; + if (old_dialog_participant.dialog_id != new_dialog_participant.dialog_id) { + LOG(ERROR) << old_dialog_participant.dialog_id << " VS " << new_dialog_participant.dialog_id; return nullptr; } if (!old_dialog_participant.is_valid() || !new_dialog_participant.is_valid()) { @@ -31390,7 +31391,7 @@ tl_object_ptr MessagesManager::get_chat_event_action_ob return nullptr; } return make_tl_object( - td_->contacts_manager_->get_user_id_object(old_dialog_participant.user_id, "chatEventMemberRestricted"), + get_message_sender_object(old_dialog_participant.dialog_id), old_dialog_participant.status.get_chat_member_status_object(), new_dialog_participant.status.get_chat_member_status_object()); } @@ -31398,16 +31399,18 @@ tl_object_ptr MessagesManager::get_chat_event_action_ob auto action = move_tl_object_as(action_ptr); DialogParticipant old_dialog_participant(std::move(action->prev_participant_)); DialogParticipant new_dialog_participant(std::move(action->new_participant_)); - if (old_dialog_participant.user_id != new_dialog_participant.user_id) { - LOG(ERROR) << old_dialog_participant.user_id << " VS " << new_dialog_participant.user_id; + if (old_dialog_participant.dialog_id != new_dialog_participant.dialog_id) { + LOG(ERROR) << old_dialog_participant.dialog_id << " VS " << new_dialog_participant.dialog_id; return nullptr; } - if (!old_dialog_participant.is_valid() || !new_dialog_participant.is_valid()) { + if (!old_dialog_participant.is_valid() || !new_dialog_participant.is_valid() || + old_dialog_participant.dialog_id.get_type() != DialogType::User) { LOG(ERROR) << "Wrong edit administrator: " << old_dialog_participant << " -> " << new_dialog_participant; return nullptr; } return make_tl_object( - td_->contacts_manager_->get_user_id_object(old_dialog_participant.user_id, "chatEventMemberPromoted"), + td_->contacts_manager_->get_user_id_object(old_dialog_participant.dialog_id.get_user_id(), + "chatEventMemberPromoted"), old_dialog_participant.status.get_chat_member_status_object(), new_dialog_participant.status.get_chat_member_status_object()); } diff --git a/td/telegram/Version.h b/td/telegram/Version.h index 4a54ad214..d9f28e617 100644 --- a/td/telegram/Version.h +++ b/td/telegram/Version.h @@ -42,6 +42,7 @@ enum class Version : int32 { AddPhotoProgressiveSizes, AddLiveLocationHeading, AddLiveLocationProximityAlertDistance, // 30 + SupportBannedChannels, Next }; From a95c23206ad415189c04862ba0de0f59d345ad69 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Wed, 24 Mar 2021 13:46:32 +0100 Subject: [PATCH 107/281] Update README --- README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 948f91760..75b777968 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ TDLib developers strongly advise against the use of this feature, since it is no ### Memory cleanup TDLight can clean itself and release some ram to the OS if you want. Look at **TdApi.OptimizeMemory** in "Modified features" paragraph to see how. -### (Almost) constant memory usage -TDLight if used with care doesn't grow in memory usage with time. Look at **TdApi.OptimizeMemory** in "Modified features" paragraph to see how +### Constant memory usage without restarting +TDLight, if used with care, doesn't grow in memory usage with time. Look at **TdApi.OptimizeMemory** in "Modified features" paragraph to see how ![memory usage](info/memory-usage.jpg) @@ -38,7 +38,10 @@ We added some options: This method is used to optimize the memory usage, but it must be used carefully. It removes almost all cached values and releases the memory back to the OS. -Removing cached values can cause problems if you don't take the following precautions: +You can call TdApi.OptimizeMemory normally, but removing cached values +can cause problems if you don't take some precautions. + +If you want to avoid receiving data with missing fields during cleanup: 1. Before calling *TdApi.OptimizeMemory* you must: 1. Read all the pending updates to empty the pending updates queue. 2. Disable internet connection using *TdApi.SetNetworkType(TdApi.NetworkTypeNone)* @@ -51,12 +54,6 @@ Removing cached values can cause problems if you don't take the following precau This method is used to read the size of all the biggest data maps inside tdlib implementation. The output contains a string that can be parsed as a JSON. -## Removed features -### Local databases encryption -Local databases are no longer encrypted and deleted data is no longer overwritten with zeroes. This reduces IOPS and helps TDLight preserving SSDs life. -### Local text indicization -TDLight removed completely local text indicization, so if you search for some text it will search it through telegram servers. - ## Other reccomended options * Options: * ignore_inline_thumbnails: true @@ -64,6 +61,8 @@ TDLight removed completely local text indicization, so if you search for some te * ignore_platform_restrictions: true * ignore_sensitive_content_restrictions: true * Disable all the databases (messages_db, users_db, files_db) + + ⚠️ If you use the databases, TDLight memory cleanup feature will be automatically disabled, because databases will lose some data when cleaning up the memory. ----- From 206cd55479c9ddf44ee855190717ae2d65795b34 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 24 Mar 2021 23:40:13 +0300 Subject: [PATCH 108/281] Support chat-members in getChatMember. --- td/generate/scheme/td_api.tl | 4 +- td/telegram/ContactsManager.cpp | 94 ++++++++++++++++++++++----------- td/telegram/ContactsManager.h | 9 ++-- td/telegram/Td.cpp | 22 +++++--- td/telegram/Td.h | 2 +- td/telegram/cli.cpp | 6 +-- 6 files changed, 87 insertions(+), 50 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 8e30b2f2a..d42fd0018 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4393,8 +4393,8 @@ canTransferOwnership = CanTransferOwnershipResult; //@chat_id Chat identifier @user_id Identifier of the user to which transfer the ownership. The ownership can't be transferred to a bot or to a deleted user @password The password of the current user transferChatOwnership chat_id:int53 user_id:int32 password:string = Ok; -//@description Returns information about a single member of a chat @chat_id Chat identifier @user_id User identifier -getChatMember chat_id:int53 user_id:int32 = ChatMember; +//@description Returns information about a single member of a chat @chat_id Chat identifier @member_id Member identifier +getChatMember chat_id:int53 member_id:MessageSender = ChatMember; //@description Searches for a specified query in the first name, last name and username of the members of a specified chat. Requires administrator rights in channels @chat_id Chat identifier @query Query to search for @limit The maximum number of users to be returned @filter The type of users to return. By default, chatMembersFilterMembers searchChatMembers chat_id:int53 query:string limit:int32 filter:ChatMembersFilter = ChatMembers; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 143a3c0d0..2b9e5cfe5 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -2905,13 +2905,13 @@ class GetFullChannelQuery : public Td::ResultHandler { class GetChannelParticipantQuery : public Td::ResultHandler { Promise promise_; ChannelId channel_id_; - UserId user_id_; + DialogId participant_dialog_id_; public: explicit GetChannelParticipantQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(ChannelId channel_id, UserId user_id, tl_object_ptr &&input_peer) { + void send(ChannelId channel_id, DialogId participant_dialog_id, tl_object_ptr &&input_peer) { auto input_channel = td->contacts_manager_->get_input_channel(channel_id); if (input_channel == nullptr) { return promise_.set_error(Status::Error(3, "Supergroup not found")); @@ -2920,7 +2920,7 @@ class GetChannelParticipantQuery : public Td::ResultHandler { CHECK(input_peer != nullptr); channel_id_ = channel_id; - user_id_ = user_id; + participant_dialog_id_ = participant_dialog_id; send_query(G()->net_query_creator().create( telegram_api::channels_getParticipant(std::move(input_channel), std::move(input_peer)))); } @@ -2946,11 +2946,11 @@ class GetChannelParticipantQuery : public Td::ResultHandler { void on_error(uint64 id, Status status) override { if (status.message() == "USER_NOT_PARTICIPANT") { - promise_.set_value(DialogParticipant::left(DialogId(user_id_))); + promise_.set_value(DialogParticipant::left(participant_dialog_id_)); return; } - td->contacts_manager_->on_get_channel_error(channel_id_, status, "GetChannelParticipantQuery"); + // td->contacts_manager_->on_get_channel_error(channel_id_, status, "GetChannelParticipantQuery"); promise_.set_error(std::move(status)); } }; @@ -6873,7 +6873,7 @@ void ContactsManager::change_channel_participant_status(ChannelId channel_id, Us }); td_->create_handler(std::move(on_result_promise)) - ->send(channel_id, user_id, std::move(input_peer)); + ->send(channel_id, DialogId(user_id), std::move(input_peer)); } void ContactsManager::change_channel_participant_status_impl(ChannelId channel_id, UserId user_id, @@ -14531,47 +14531,73 @@ void ContactsManager::ban_dialog_participant(DialogId dialog_id, UserId user_id, } } -DialogParticipant ContactsManager::get_dialog_participant(DialogId dialog_id, UserId user_id, int64 &random_id, - bool force, Promise &&promise) { - LOG(INFO) << "Receive GetChatMember request to get " << user_id << " in " << dialog_id << " with random_id " - << random_id; +DialogParticipant ContactsManager::get_dialog_participant(DialogId dialog_id, + const td_api::object_ptr &member_id, + int64 &random_id, bool force, Promise &&promise) { + LOG(INFO) << "Receive GetChatMember request to get " << to_string(member_id) << " in " << dialog_id + << " with random_id " << random_id; if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_dialog_participant")) { promise.set_error(Status::Error(3, "Chat not found")); return DialogParticipant(); } + if (member_id == nullptr) { + promise.set_error(Status::Error(3, "Member must be non-empty")); + return DialogParticipant(); + } + DialogId participant_dialog_id; + switch (member_id->get_id()) { + case td_api::messageSenderUser::ID: + participant_dialog_id = + DialogId(UserId(static_cast(member_id.get())->user_id_)); + break; + case td_api::messageSenderChat::ID: + participant_dialog_id = DialogId(static_cast(member_id.get())->chat_id_); + break; + default: + UNREACHABLE(); + } + if (!participant_dialog_id.is_valid()) { + promise.set_error(Status::Error(3, "Invalid member identifier specified")); + return DialogParticipant(); + } + switch (dialog_id.get_type()) { - case DialogType::User: { - auto peer_user_id = dialog_id.get_user_id(); - if (user_id == get_my_id()) { + case DialogType::User: + if (participant_dialog_id == DialogId(get_my_id())) { promise.set_value(Unit()); - return {DialogId(user_id), peer_user_id, 0, DialogParticipantStatus::Member()}; + return {participant_dialog_id, dialog_id.get_user_id(), 0, DialogParticipantStatus::Member()}; } - if (user_id == peer_user_id) { + if (participant_dialog_id == dialog_id) { promise.set_value(Unit()); - return {DialogId(peer_user_id), user_id, 0, DialogParticipantStatus::Member()}; + return {participant_dialog_id, get_my_id(), 0, DialogParticipantStatus::Member()}; } - promise.set_error(Status::Error(3, "User is not a member of the private chat")); + promise.set_error(Status::Error(3, "Member not found")); break; - } case DialogType::Chat: - return get_chat_participant(dialog_id.get_chat_id(), user_id, force, std::move(promise)); + if (participant_dialog_id.get_type() != DialogType::User) { + promise.set_value(Unit()); + return DialogParticipant::left(participant_dialog_id); + } + return get_chat_participant(dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), force, + std::move(promise)); case DialogType::Channel: - return get_channel_participant(dialog_id.get_channel_id(), user_id, random_id, force, std::move(promise)); + return get_channel_participant(dialog_id.get_channel_id(), participant_dialog_id, random_id, force, + std::move(promise)); case DialogType::SecretChat: { auto peer_user_id = get_secret_chat_user_id(dialog_id.get_secret_chat_id()); - if (user_id == get_my_id()) { + if (participant_dialog_id == DialogId(get_my_id())) { promise.set_value(Unit()); - return {DialogId(user_id), peer_user_id.is_valid() ? peer_user_id : user_id, 0, + return {participant_dialog_id, peer_user_id.is_valid() ? peer_user_id : get_my_id(), 0, DialogParticipantStatus::Member()}; } - if (peer_user_id.is_valid() && user_id == peer_user_id) { + if (participant_dialog_id == DialogId(peer_user_id)) { promise.set_value(Unit()); - return {DialogId(peer_user_id), user_id, 0, DialogParticipantStatus::Member()}; + return {participant_dialog_id, get_my_id(), 0, DialogParticipantStatus::Member()}; } - promise.set_error(Status::Error(3, "User is not a member of the secret chat")); + promise.set_error(Status::Error(3, "Member not found")); break; } case DialogType::None: @@ -14794,9 +14820,10 @@ void ContactsManager::do_search_chat_participants(ChatId chat_id, const string & })}); } -DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id, UserId user_id, int64 &random_id, - bool force, Promise &&promise) { - LOG(INFO) << "Trying to get " << user_id << " as member of " << channel_id << " with random_id " << random_id; +DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id, DialogId participant_dialog_id, + int64 &random_id, bool force, Promise &&promise) { + LOG(INFO) << "Trying to get " << participant_dialog_id << " as member of " << channel_id << " with random_id " + << random_id; if (random_id != 0) { // request has already been sent before auto it = received_channel_participant_.find(random_id); @@ -14807,13 +14834,15 @@ DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id, return result; } - auto input_peer = get_input_peer_user(user_id, AccessRights::Read); + auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Read); if (input_peer == nullptr) { promise.set_error(Status::Error(6, "User not found")); return DialogParticipant(); } - if (!td_->auth_manager_->is_bot() && is_user_bot(user_id)) { + if (!td_->auth_manager_->is_bot() && participant_dialog_id.get_type() == DialogType::User && + is_user_bot(participant_dialog_id.get_user_id())) { + auto user_id = participant_dialog_id.get_user_id(); auto u = get_user(user_id); CHECK(u != nullptr); if (is_bot_info_expired(user_id, u->bot_info_version)) { @@ -14831,7 +14860,8 @@ DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id, } while (random_id == 0 || received_channel_participant_.find(random_id) != received_channel_participant_.end()); received_channel_participant_[random_id]; // reserve place for result - LOG(DEBUG) << "Get info about " << user_id << " membership in the " << channel_id << " with random_id " << random_id; + LOG(DEBUG) << "Get info about " << participant_dialog_id << " membership in the " << channel_id << " with random_id " + << random_id; auto on_result_promise = PromiseCreator::lambda( [this, random_id, promise = std::move(promise)](Result r_dialog_participant) mutable { @@ -14851,7 +14881,7 @@ DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id, }); td_->create_handler(std::move(on_result_promise)) - ->send(channel_id, user_id, std::move(input_peer)); + ->send(channel_id, participant_dialog_id, std::move(input_peer)); return DialogParticipant(); } diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 241ea3874..2aa4c895c 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -525,8 +525,9 @@ class ContactsManager : public Actor { void ban_dialog_participant(DialogId dialog_id, UserId user_id, int32 banned_until_date, bool revoke_messages, Promise &&promise); - DialogParticipant get_dialog_participant(DialogId dialog_id, UserId user_id, int64 &random_id, bool force, - Promise &&promise); + DialogParticipant get_dialog_participant(DialogId dialog_id, + const td_api::object_ptr &member_id, int64 &random_id, + bool force, Promise &&promise); void search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, DialogParticipantsFilter filter, bool without_bot_info, Promise &&promise); @@ -1425,8 +1426,8 @@ class ContactsManager : public Actor { DialogParticipant get_chat_participant(ChatId chat_id, UserId user_id, bool force, Promise &&promise); - DialogParticipant get_channel_participant(ChannelId channel_id, UserId user_id, int64 &random_id, bool force, - Promise &&promise); + DialogParticipant get_channel_participant(ChannelId channel_id, DialogId participant_dialog_id, int64 &random_id, + bool force, Promise &&promise); static string get_dialog_administrators_database_key(DialogId dialog_id); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 4f9f1c3bf..c89722df9 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -1940,26 +1940,32 @@ class UpgradeGroupChatToSupergroupChatRequest : public RequestActor<> { class GetChatMemberRequest : public RequestActor<> { DialogId dialog_id_; - UserId user_id_; + td_api::object_ptr member_id_; int64 random_id_; DialogParticipant dialog_participant_; void do_run(Promise &&promise) override { - dialog_participant_ = td->contacts_manager_->get_dialog_participant(dialog_id_, user_id_, random_id_, + dialog_participant_ = td->contacts_manager_->get_dialog_participant(dialog_id_, member_id_, random_id_, get_tries() < 3, std::move(promise)); } void do_send_result() override { - if (!td->contacts_manager_->have_user(user_id_)) { - return send_error(Status::Error(3, "User not found")); + auto dialog_id = dialog_participant_.dialog_id; + if ((dialog_id.get_type() == DialogType::User && !td->contacts_manager_->have_user(dialog_id.get_user_id())) || + !td->messages_manager_->have_dialog(dialog_id)) { + return send_error(Status::Error(3, "Member not found")); } send_result(td->contacts_manager_->get_chat_member_object(dialog_participant_)); } public: - GetChatMemberRequest(ActorShared td, uint64 request_id, int64 dialog_id, int32 user_id) - : RequestActor(std::move(td), request_id), dialog_id_(dialog_id), user_id_(user_id), random_id_(0) { + GetChatMemberRequest(ActorShared td, uint64 request_id, int64 dialog_id, + td_api::object_ptr &&member_id) + : RequestActor(std::move(td), request_id) + , dialog_id_(dialog_id) + , member_id_(std::move(member_id)) + , random_id_(0) { set_tries(3); } }; @@ -6370,8 +6376,8 @@ void Td::on_request(uint64 id, td_api::transferChatOwnership &request) { std::move(promise)); } -void Td::on_request(uint64 id, const td_api::getChatMember &request) { - CREATE_REQUEST(GetChatMemberRequest, request.chat_id_, request.user_id_); +void Td::on_request(uint64 id, td_api::getChatMember &request) { + CREATE_REQUEST(GetChatMemberRequest, request.chat_id_, std::move(request.member_id_)); } void Td::on_request(uint64 id, td_api::searchChatMembers &request) { diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 1b39d9420..8061c38bc 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -809,7 +809,7 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::transferChatOwnership &request); - void on_request(uint64 id, const td_api::getChatMember &request); + void on_request(uint64 id, td_api::getChatMember &request); void on_request(uint64 id, td_api::searchChatMembers &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 9609df64d..d6b5ecbdf 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2452,9 +2452,9 @@ class CliClient final : public Actor { get_chat_members_filter(filter))); } else if (op == "gcm") { string chat_id; - string user_id; - get_args(args, chat_id, user_id); - send_request(td_api::make_object(as_chat_id(chat_id), as_user_id(user_id))); + string member_id; + get_args(args, chat_id, member_id); + send_request(td_api::make_object(as_chat_id(chat_id), as_message_sender(member_id))); } else if (op == "GetChatAdministrators") { string chat_id = args; send_request(td_api::make_object(as_chat_id(chat_id))); From b349696e7fd51f162dded779cccf125942bb785d Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 25 Mar 2021 01:10:34 +0300 Subject: [PATCH 109/281] Force inputPeerChannel creation for bots. --- td/telegram/ContactsManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 2b9e5cfe5..1eb003520 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -4585,6 +4585,9 @@ tl_object_ptr ContactsManager::get_input_peer_channel(C AccessRights access_rights) const { const Channel *c = get_channel(channel_id); if (!have_input_peer_channel(c, channel_id, access_rights)) { + if (c == nullptr && td_->auth_manager_->is_bot() && channel_id.is_valid()) { + return make_tl_object(channel_id.get(), 0); + } return nullptr; } From ffc847dbf59da26afc1eca3afdbd7aa607ea53e2 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 26 Mar 2021 02:39:24 +0300 Subject: [PATCH 110/281] Replace search_among_users with search_among_dialogs. --- td/telegram/ContactsManager.cpp | 103 +++++++++++++++++--------------- td/telegram/ContactsManager.h | 6 +- td/telegram/MessagesManager.h | 4 +- 3 files changed, 60 insertions(+), 53 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 1eb003520..43001f22e 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -11506,12 +11506,12 @@ const DialogParticipant *ContactsManager::get_chat_participant(ChatId chat_id, U if (chat_full == nullptr) { return nullptr; } - return get_chat_full_participant(chat_full, user_id); + return get_chat_full_participant(chat_full, DialogId(user_id)); } -const DialogParticipant *ContactsManager::get_chat_full_participant(const ChatFull *chat_full, UserId user_id) { +const DialogParticipant *ContactsManager::get_chat_full_participant(const ChatFull *chat_full, DialogId dialog_id) { for (const auto &dialog_participant : chat_full->participants) { - if (dialog_participant.dialog_id == DialogId(user_id)) { + if (dialog_participant.dialog_id == dialog_id) { return &dialog_participant; } } @@ -11738,21 +11738,17 @@ void ContactsManager::on_get_channel_participants( if (!additional_query.empty()) { auto dialog_ids = transform(result, [](const DialogParticipant &participant) { return participant.dialog_id; }); - td::remove_if(dialog_ids, [](DialogId dialog_id) { return dialog_id.get_type() != DialogType::User; }); - auto user_ids = transform(dialog_ids, [](DialogId dialog_id) { return dialog_id.get_user_id(); }); - std::pair> result_user_ids = search_among_users(user_ids, additional_query, additional_limit); + std::pair> result_dialog_ids = + search_among_dialogs(dialog_ids, additional_query, additional_limit); - total_count = result_user_ids.first; - std::unordered_set result_user_ids_set(result_user_ids.second.begin(), - result_user_ids.second.end()); + total_count = result_dialog_ids.first; + std::unordered_set result_dialog_ids_set(result_dialog_ids.second.begin(), + result_dialog_ids.second.end()); auto all_participants = std::move(result); result.clear(); for (auto &participant : all_participants) { - if (participant.dialog_id.get_type() != DialogType::User) { - continue; - } - if (result_user_ids_set.count(participant.dialog_id.get_user_id())) { - result_user_ids_set.erase(participant.dialog_id.get_user_id()); + if (result_dialog_ids_set.count(participant.dialog_id)) { + result_dialog_ids_set.erase(participant.dialog_id); result.push_back(std::move(participant)); } } @@ -14420,26 +14416,39 @@ void ContactsManager::on_update_secret_chat(SecretChatId secret_chat_id, int64 a update_secret_chat(secret_chat, secret_chat_id); } -std::pair> ContactsManager::search_among_users(const vector &user_ids, - const string &query, int32 limit) const { +std::pair> ContactsManager::search_among_dialogs(const vector &dialog_ids, + const string &query, int32 limit) const { Hints hints; // TODO cache Hints - for (auto user_id : user_ids) { - auto u = get_user(user_id); - if (u == nullptr) { - continue; - } - if (query.empty()) { - hints.add(user_id.get(), Slice(" ")); + for (auto dialog_id : dialog_ids) { + int64 rating = 0; + if (dialog_id.get_type() == DialogType::User) { + auto user_id = dialog_id.get_user_id(); + auto u = get_user(user_id); + if (u == nullptr) { + continue; + } + if (query.empty()) { + hints.add(dialog_id.get(), Slice(" ")); + } else { + hints.add(dialog_id.get(), PSLICE() << u->first_name << ' ' << u->last_name << ' ' << u->username); + } + rating = -get_user_was_online(u, user_id); } else { - hints.add(user_id.get(), PSLICE() << u->first_name << ' ' << u->last_name << ' ' << u->username); + if (!td_->messages_manager_->have_dialog_info(dialog_id)) { + continue; + } + if (query.empty()) { + hints.add(dialog_id.get(), Slice(" ")); + } else { + hints.add(dialog_id.get(), td_->messages_manager_->get_dialog_title(dialog_id)); + } } - hints.set_rating(user_id.get(), -get_user_was_online(u, user_id)); + hints.set_rating(dialog_id.get(), rating); } auto result = hints.search(query, limit, true); - return {narrow_cast(result.first), - transform(result.second, [](int64 key) { return UserId(narrow_cast(key)); })}; + return {narrow_cast(result.first), transform(result.second, [](int64 key) { return DialogId(key); })}; } void ContactsManager::add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, @@ -14614,20 +14623,20 @@ DialogParticipant ContactsManager::get_dialog_participant(DialogId dialog_id, DialogParticipants ContactsManager::search_private_chat_participants(UserId my_user_id, UserId peer_user_id, const string &query, int32 limit, DialogParticipantsFilter filter) const { - vector user_ids; + vector dialog_ids; switch (filter.type) { case DialogParticipantsFilter::Type::Contacts: if (peer_user_id.is_valid() && is_user_contact(peer_user_id)) { - user_ids.push_back(peer_user_id); + dialog_ids.push_back(DialogId(peer_user_id)); } break; case DialogParticipantsFilter::Type::Administrators: break; case DialogParticipantsFilter::Type::Members: case DialogParticipantsFilter::Type::Mention: - user_ids.push_back(my_user_id); + dialog_ids.push_back(DialogId(my_user_id)); if (peer_user_id.is_valid() && peer_user_id != my_user_id) { - user_ids.push_back(peer_user_id); + dialog_ids.push_back(DialogId(peer_user_id)); } break; case DialogParticipantsFilter::Type::Restricted: @@ -14636,21 +14645,21 @@ DialogParticipants ContactsManager::search_private_chat_participants(UserId my_u break; case DialogParticipantsFilter::Type::Bots: if (td_->auth_manager_->is_bot()) { - user_ids.push_back(my_user_id); + dialog_ids.push_back(DialogId(my_user_id)); } if (peer_user_id.is_valid() && is_user_bot(peer_user_id) && peer_user_id != my_user_id) { - user_ids.push_back(peer_user_id); + dialog_ids.push_back(DialogId(peer_user_id)); } break; default: UNREACHABLE(); } - auto result = search_among_users(user_ids, query, limit); - return {result.first, transform(result.second, [&](UserId user_id) { - return DialogParticipant(DialogId(user_id), - user_id == my_user_id && peer_user_id.is_valid() ? peer_user_id : my_user_id, 0, - DialogParticipantStatus::Member()); + auto result = search_among_dialogs(dialog_ids, query, limit); + return {result.first, transform(result.second, [&](DialogId dialog_id) { + return DialogParticipant( + dialog_id, dialog_id == DialogId(my_user_id) && peer_user_id.is_valid() ? peer_user_id : my_user_id, 0, + DialogParticipantStatus::Member()); })}; } @@ -14785,12 +14794,10 @@ void ContactsManager::do_search_chat_participants(ChatId chat_id, const string & } auto is_dialog_participant_suitable = [this, filter](const DialogParticipant &participant) { - if (participant.dialog_id.get_type() != DialogType::User) { - return false; - } switch (filter.type) { case DialogParticipantsFilter::Type::Contacts: - return is_user_contact(participant.dialog_id.get_user_id()); + return participant.dialog_id.get_type() == DialogType::User && + is_user_contact(participant.dialog_id.get_user_id()); case DialogParticipantsFilter::Type::Administrators: return participant.status.is_administrator(); case DialogParticipantsFilter::Type::Members: @@ -14802,24 +14809,24 @@ void ContactsManager::do_search_chat_participants(ChatId chat_id, const string & case DialogParticipantsFilter::Type::Mention: return true; case DialogParticipantsFilter::Type::Bots: - return is_user_bot(participant.dialog_id.get_user_id()); + return participant.dialog_id.get_type() == DialogType::User && is_user_bot(participant.dialog_id.get_user_id()); default: UNREACHABLE(); return false; } }; - vector user_ids; + vector dialog_ids; for (const auto &participant : chat_full->participants) { if (is_dialog_participant_suitable(participant)) { - user_ids.push_back(participant.dialog_id.get_user_id()); + dialog_ids.push_back(participant.dialog_id); } } int32 total_count; - std::tie(total_count, user_ids) = search_among_users(user_ids, query, limit); - promise.set_value(DialogParticipants{total_count, transform(user_ids, [chat_full](UserId user_id) { - return *ContactsManager::get_chat_full_participant(chat_full, user_id); + std::tie(total_count, dialog_ids) = search_among_dialogs(dialog_ids, query, limit); + promise.set_value(DialogParticipants{total_count, transform(dialog_ids, [chat_full](DialogId dialog_id) { + return *ContactsManager::get_chat_full_participant(chat_full, dialog_id); })}); } diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 2aa4c895c..60924c20d 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -1416,10 +1416,10 @@ class ContactsManager : public Actor { const DialogParticipant *get_chat_participant(ChatId chat_id, UserId user_id) const; - static const DialogParticipant *get_chat_full_participant(const ChatFull *chat_full, UserId user_id); + static const DialogParticipant *get_chat_full_participant(const ChatFull *chat_full, DialogId dialog_id); - std::pair> search_among_users(const vector &user_ids, const string &query, - int32 limit) const; + std::pair> search_among_dialogs(const vector &dialog_ids, const string &query, + int32 limit) const; DialogParticipants search_private_chat_participants(UserId my_user_id, UserId peer_user_id, const string &query, int32 limit, DialogParticipantsFilter filter) const; diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 9830896d5..693790421 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -495,6 +495,8 @@ class MessagesManager : public Actor { tl_object_ptr get_chat_events_object(int64 random_id); + string get_dialog_title(DialogId dialog_id) const; + bool have_dialog(DialogId dialog_id) const; bool have_dialog_force(DialogId dialog_id, const char *source = "have_dialog_force"); @@ -2693,8 +2695,6 @@ class MessagesManager : public Actor { const DialogPhoto *get_dialog_photo(DialogId dialog_id) const; - string get_dialog_title(DialogId dialog_id) const; - string get_dialog_username(DialogId dialog_id) const; RestrictedRights get_dialog_permissions(DialogId dialog_id) const; From f28af4ab20d7138dfd5db76586a08acd904e19d0 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 26 Mar 2021 03:17:30 +0300 Subject: [PATCH 111/281] Add ContactsManager::get_participant_dialog_id. --- td/telegram/ContactsManager.cpp | 36 ++++++++++++++++----------------- td/telegram/ContactsManager.h | 5 +++-- td/telegram/Td.cpp | 18 ++++++++--------- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 43001f22e..372667a3a 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -14451,6 +14451,21 @@ std::pair> ContactsManager::search_among_dialogs(const v return {narrow_cast(result.first), transform(result.second, [](int64 key) { return DialogId(key); })}; } +DialogId ContactsManager::get_participant_dialog_id(const td_api::object_ptr &participant_id) { + if (participant_id == nullptr) { + return DialogId(); + } + switch (participant_id->get_id()) { + case td_api::messageSenderUser::ID: + return DialogId(UserId(static_cast(participant_id.get())->user_id_)); + case td_api::messageSenderChat::ID: + return DialogId(static_cast(participant_id.get())->chat_id_); + default: + UNREACHABLE(); + return DialogId(); + } +} + void ContactsManager::add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, Promise &&promise) { if (!td_->messages_manager_->have_dialog_force(dialog_id, "add_dialog_participant")) { @@ -14543,32 +14558,15 @@ void ContactsManager::ban_dialog_participant(DialogId dialog_id, UserId user_id, } } -DialogParticipant ContactsManager::get_dialog_participant(DialogId dialog_id, - const td_api::object_ptr &member_id, +DialogParticipant ContactsManager::get_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id, int64 &random_id, bool force, Promise &&promise) { - LOG(INFO) << "Receive GetChatMember request to get " << to_string(member_id) << " in " << dialog_id + LOG(INFO) << "Receive GetChatMember request to get " << participant_dialog_id << " in " << dialog_id << " with random_id " << random_id; if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_dialog_participant")) { promise.set_error(Status::Error(3, "Chat not found")); return DialogParticipant(); } - if (member_id == nullptr) { - promise.set_error(Status::Error(3, "Member must be non-empty")); - return DialogParticipant(); - } - DialogId participant_dialog_id; - switch (member_id->get_id()) { - case td_api::messageSenderUser::ID: - participant_dialog_id = - DialogId(UserId(static_cast(member_id.get())->user_id_)); - break; - case td_api::messageSenderChat::ID: - participant_dialog_id = DialogId(static_cast(member_id.get())->chat_id_); - break; - default: - UNREACHABLE(); - } if (!participant_dialog_id.is_valid()) { promise.set_error(Status::Error(3, "Invalid member identifier specified")); return DialogParticipant(); diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 60924c20d..f48edb578 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -514,6 +514,8 @@ class ContactsManager : public Actor { ChannelId get_channel_linked_channel_id(ChannelId channel_id); int32 get_channel_slow_mode_delay(ChannelId channel_id); + static DialogId get_participant_dialog_id(const td_api::object_ptr &participant_id); + void add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, Promise &&promise); void add_dialog_participants(DialogId dialog_id, const vector &user_ids, Promise &&promise); @@ -525,8 +527,7 @@ class ContactsManager : public Actor { void ban_dialog_participant(DialogId dialog_id, UserId user_id, int32 banned_until_date, bool revoke_messages, Promise &&promise); - DialogParticipant get_dialog_participant(DialogId dialog_id, - const td_api::object_ptr &member_id, int64 &random_id, + DialogParticipant get_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id, int64 &random_id, bool force, Promise &&promise); void search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, DialogParticipantsFilter filter, diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index c89722df9..d1a071e86 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -1940,31 +1940,30 @@ class UpgradeGroupChatToSupergroupChatRequest : public RequestActor<> { class GetChatMemberRequest : public RequestActor<> { DialogId dialog_id_; - td_api::object_ptr member_id_; + DialogId participant_dialog_id_; int64 random_id_; DialogParticipant dialog_participant_; void do_run(Promise &&promise) override { - dialog_participant_ = td->contacts_manager_->get_dialog_participant(dialog_id_, member_id_, random_id_, + dialog_participant_ = td->contacts_manager_->get_dialog_participant(dialog_id_, participant_dialog_id_, random_id_, get_tries() < 3, std::move(promise)); } void do_send_result() override { - auto dialog_id = dialog_participant_.dialog_id; - if ((dialog_id.get_type() == DialogType::User && !td->contacts_manager_->have_user(dialog_id.get_user_id())) || - !td->messages_manager_->have_dialog(dialog_id)) { + bool is_user = participant_dialog_id_.get_type() == DialogType::User; + if ((is_user && !td->contacts_manager_->have_user(participant_dialog_id_.get_user_id())) || + (!is_user && !td->messages_manager_->have_dialog(participant_dialog_id_))) { return send_error(Status::Error(3, "Member not found")); } send_result(td->contacts_manager_->get_chat_member_object(dialog_participant_)); } public: - GetChatMemberRequest(ActorShared td, uint64 request_id, int64 dialog_id, - td_api::object_ptr &&member_id) + GetChatMemberRequest(ActorShared td, uint64 request_id, int64 dialog_id, DialogId participant_dialog_id) : RequestActor(std::move(td), request_id) , dialog_id_(dialog_id) - , member_id_(std::move(member_id)) + , participant_dialog_id_(participant_dialog_id) , random_id_(0) { set_tries(3); } @@ -6377,7 +6376,8 @@ void Td::on_request(uint64 id, td_api::transferChatOwnership &request) { } void Td::on_request(uint64 id, td_api::getChatMember &request) { - CREATE_REQUEST(GetChatMemberRequest, request.chat_id_, std::move(request.member_id_)); + CREATE_REQUEST(GetChatMemberRequest, request.chat_id_, + ContactsManager::get_participant_dialog_id(request.member_id_)); } void Td::on_request(uint64 id, td_api::searchChatMembers &request) { From 14fc0898ad7be6eae3990c968d865bc8fd051474 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 26 Mar 2021 04:11:30 +0300 Subject: [PATCH 112/281] Support banning and unbanning channels and supergroups. --- td/generate/scheme/td_api.tl | 8 +- td/telegram/ContactsManager.cpp | 131 ++++++++++++++++++-------------- td/telegram/ContactsManager.h | 20 ++--- td/telegram/Td.cpp | 10 ++- td/telegram/cli.cpp | 22 +++--- 5 files changed, 107 insertions(+), 84 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index d42fd0018..e938257a1 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4376,15 +4376,15 @@ addChatMember chat_id:int53 user_id:int32 forward_limit:int32 = Ok; addChatMembers chat_id:int53 user_ids:vector = Ok; //@description Changes the status of a chat member, needs appropriate privileges. This function is currently not suitable for adding new members to the chat and transferring chat ownership; instead, use addChatMember or transferChatOwnership -//@chat_id Chat identifier @user_id User identifier @status The new status of the member in the chat -setChatMemberStatus chat_id:int53 user_id:int32 status:ChatMemberStatus = Ok; +//@chat_id Chat identifier @member_id Member identifier. Chats can be only banned and unbanned in supergroups and channels @status The new status of the member in the chat +setChatMemberStatus chat_id:int53 member_id:MessageSender status:ChatMemberStatus = Ok; //@description Bans a member in a chat. Members can't be banned in private or secret chats. In supergroups and channels, the user will not be able to return to the group on their own using invite links, etc., unless unbanned first //@chat_id Chat identifier -//@user_id Identifier of the user +//@member_id Member identifier //@banned_until_date Point in time (Unix timestamp) when the user will be unbanned; 0 if never. If the user is banned for more than 366 days or for less than 30 seconds from the current time, the user is considered to be banned forever. Ignored in basic groups //@revoke_messages Pass true to delete all messages in the chat for the user. Always true for supergroups and channels -banChatMember chat_id:int53 user_id:int32 banned_until_date:int32 revoke_messages:Bool = Ok; +banChatMember chat_id:int53 member_id:MessageSender banned_until_date:int32 revoke_messages:Bool = Ok; //@description Checks whether the current session can be used to transfer a chat ownership to another user canTransferOwnership = CanTransferOwnershipResult; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 372667a3a..7e09f86fe 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -6845,41 +6845,41 @@ void ContactsManager::add_channel_participants(ChannelId channel_id, const vecto td_->create_handler(std::move(promise))->send(channel_id, std::move(input_users)); } -void ContactsManager::change_channel_participant_status(ChannelId channel_id, UserId user_id, +void ContactsManager::change_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id, DialogParticipantStatus status, Promise &&promise) { auto c = get_channel(channel_id); if (c == nullptr) { return promise.set_error(Status::Error(6, "Chat info not found")); } - auto input_peer = get_input_peer_user(user_id, AccessRights::Read); + auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Read); if (input_peer == nullptr) { - return promise.set_error(Status::Error(6, "User not found")); + return promise.set_error(Status::Error(6, "Member not found")); } - if (user_id == get_my_id()) { + if (participant_dialog_id == DialogId(get_my_id())) { // fast path is needed, because get_channel_status may return Creator, while GetChannelParticipantQuery returning Left - return change_channel_participant_status_impl(channel_id, user_id, std::move(status), get_channel_status(c), - std::move(promise)); + return change_channel_participant_status_impl(channel_id, participant_dialog_id, std::move(status), + get_channel_status(c), std::move(promise)); } auto on_result_promise = - PromiseCreator::lambda([actor_id = actor_id(this), channel_id, user_id, status, + PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id, status, promise = std::move(promise)](Result r_dialog_participant) mutable { // ResultHandlers are cleared before managers, so it is safe to capture this if (r_dialog_participant.is_error()) { return promise.set_error(r_dialog_participant.move_as_error()); } - send_closure(actor_id, &ContactsManager::change_channel_participant_status_impl, channel_id, user_id, - std::move(status), r_dialog_participant.ok().status, std::move(promise)); + send_closure(actor_id, &ContactsManager::change_channel_participant_status_impl, channel_id, + participant_dialog_id, std::move(status), r_dialog_participant.ok().status, std::move(promise)); }); td_->create_handler(std::move(on_result_promise)) - ->send(channel_id, DialogId(user_id), std::move(input_peer)); + ->send(channel_id, participant_dialog_id, std::move(input_peer)); } -void ContactsManager::change_channel_participant_status_impl(ChannelId channel_id, UserId user_id, +void ContactsManager::change_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id, DialogParticipantStatus status, DialogParticipantStatus old_status, Promise &&promise) { @@ -6887,7 +6887,8 @@ void ContactsManager::change_channel_participant_status_impl(ChannelId channel_i return promise.set_value(Unit()); } - LOG(INFO) << "Change status of " << user_id << " in " << channel_id << " from " << old_status << " to " << status; + LOG(INFO) << "Change status of " << participant_dialog_id << " in " << channel_id << " from " << old_status << " to " + << status; bool need_add = false; bool need_promote = false; bool need_restrict = false; @@ -6898,23 +6899,16 @@ void ContactsManager::change_channel_participant_status_impl(ChannelId channel_i if (!status.is_creator()) { return promise.set_error(Status::Error(3, "Can't remove chat owner")); } + if (participant_dialog_id != DialogId(get_my_id())) { + return promise.set_error(Status::Error(3, "Not enough rights to edit chat owner rights")); + } if (status.is_member() == old_status.is_member()) { // change rank and is_anonymous - if (user_id != get_my_id()) { - return promise.set_error(Status::Error(3, "Not enough rights to change chat owner rights")); - } - - auto input_user = get_input_user(user_id); - if (input_user == nullptr) { - return promise.set_error(Status::Error(3, "User not found")); - } - + auto input_user = get_input_user(get_my_id()); + CHECK(input_user != nullptr); td_->create_handler(std::move(promise))->send(channel_id, std::move(input_user), status); return; } - if (user_id != get_my_id()) { - return promise.set_error(Status::Error(3, "Not enough rights to edit chat owner membership")); - } if (status.is_member()) { // creator not member -> creator member need_add = true; @@ -6952,14 +6946,21 @@ void ContactsManager::change_channel_participant_status_impl(ChannelId channel_i } if (need_promote) { - return promote_channel_participant(channel_id, user_id, std::move(status), std::move(old_status), - std::move(promise)); + if (participant_dialog_id.get_type() != DialogType::User) { + return promise.set_error(Status::Error(400, "Can't promote chats to chat administrators")); + } + return promote_channel_participant(channel_id, participant_dialog_id.get_user_id(), std::move(status), + std::move(old_status), std::move(promise)); } else if (need_restrict) { - return restrict_channel_participant(channel_id, user_id, std::move(status), std::move(old_status), + return restrict_channel_participant(channel_id, participant_dialog_id, std::move(status), std::move(old_status), std::move(promise)); } else { CHECK(need_add); - return add_channel_participant(channel_id, user_id, std::move(promise), std::move(old_status)); + if (participant_dialog_id.get_type() != DialogType::User) { + return promise.set_error(Status::Error(400, "Can't add chats as chat members")); + } + return add_channel_participant(channel_id, participant_dialog_id.get_user_id(), std::move(promise), + std::move(old_status)); } } @@ -7383,15 +7384,17 @@ void ContactsManager::delete_chat_participant(ChatId chat_id, UserId user_id, bo td_->create_handler(std::move(promise))->send(chat_id, std::move(input_user), revoke_messages); } -void ContactsManager::restrict_channel_participant(ChannelId channel_id, UserId user_id, DialogParticipantStatus status, - DialogParticipantStatus old_status, Promise &&promise) { - LOG(INFO) << "Restrict " << user_id << " in " << channel_id << " from " << old_status << " to " << status; +void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogId participant_dialog_id, + DialogParticipantStatus status, DialogParticipantStatus old_status, + Promise &&promise) { + LOG(INFO) << "Restrict " << participant_dialog_id << " in " << channel_id << " from " << old_status << " to " + << status; const Channel *c = get_channel(channel_id); if (c == nullptr) { return promise.set_error(Status::Error(3, "Chat info not found")); } if (!c->status.is_member() && !c->status.is_creator()) { - if (user_id == get_my_id()) { + if (participant_dialog_id == DialogId(get_my_id())) { if (status.is_member()) { return promise.set_error(Status::Error(3, "Can't unrestrict self")); } @@ -7400,12 +7403,12 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, UserId return promise.set_error(Status::Error(3, "Not in the chat")); } } - auto input_peer = get_input_peer_user(user_id, AccessRights::Read); + auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Read); if (input_peer == nullptr) { - return promise.set_error(Status::Error(3, "User not found")); + return promise.set_error(Status::Error(3, "Member not found")); } - if (user_id == get_my_id()) { + if (participant_dialog_id == DialogId(get_my_id())) { if (status.is_restricted() || status.is_banned()) { return promise.set_error(Status::Error(3, "Can't restrict self")); } @@ -7414,7 +7417,7 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, UserId } // leave the channel - speculative_add_channel_user(channel_id, user_id, status, c->status); + speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), status, c->status); td_->create_handler(std::move(promise))->send(channel_id); return; } @@ -7428,22 +7431,23 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, UserId if (old_status.is_member() && !status.is_member() && !status.is_banned()) { // we can't make participant Left without kicking it first - auto on_result_promise = PromiseCreator::lambda([channel_id, user_id, status, + auto on_result_promise = PromiseCreator::lambda([channel_id, participant_dialog_id, status, promise = std::move(promise)](Result<> result) mutable { if (result.is_error()) { return promise.set_error(result.move_as_error()); } - create_actor( - "RestrictChannelParticipantSleepActor", 1.0, - PromiseCreator::lambda([channel_id, user_id, status, promise = std::move(promise)](Result<> result) mutable { - if (result.is_error()) { - return promise.set_error(result.move_as_error()); - } + create_actor("RestrictChannelParticipantSleepActor", 1.0, + PromiseCreator::lambda([channel_id, participant_dialog_id, status, + promise = std::move(promise)](Result<> result) mutable { + if (result.is_error()) { + return promise.set_error(result.move_as_error()); + } - send_closure(G()->contacts_manager(), &ContactsManager::restrict_channel_participant, channel_id, user_id, - status, DialogParticipantStatus::Banned(0), std::move(promise)); - })) + send_closure(G()->contacts_manager(), &ContactsManager::restrict_channel_participant, + channel_id, participant_dialog_id, status, + DialogParticipantStatus::Banned(0), std::move(promise)); + })) .release(); }); @@ -7451,7 +7455,9 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, UserId status = DialogParticipantStatus::Banned(0); } - speculative_add_channel_user(channel_id, user_id, status, old_status); + if (participant_dialog_id.get_type() == DialogType::User) { + speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), status, old_status); + } td_->create_handler(std::move(promise))->send(channel_id, std::move(input_peer), status); } @@ -14513,7 +14519,7 @@ void ContactsManager::add_dialog_participants(DialogId dialog_id, const vector &chat_member_status, Promise &&promise) { auto status = get_dialog_participant_status(chat_member_status); @@ -14525,9 +14531,18 @@ void ContactsManager::set_dialog_participant_status(DialogId dialog_id, UserId u case DialogType::User: return promise.set_error(Status::Error(3, "Chat member status can't be changed in private chats")); case DialogType::Chat: - return change_chat_participant_status(dialog_id.get_chat_id(), user_id, status, std::move(promise)); + if (participant_dialog_id.get_type() != DialogType::User) { + if (status == DialogParticipantStatus::Left()) { + return promise.set_value(Unit()); + } else { + return promise.set_error(Status::Error(3, "Chats can't be members of basic groups")); + } + } + return change_chat_participant_status(dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), status, + std::move(promise)); case DialogType::Channel: - return change_channel_participant_status(dialog_id.get_channel_id(), user_id, status, std::move(promise)); + return change_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id, status, + std::move(promise)); case DialogType::SecretChat: return promise.set_error(Status::Error(3, "Chat member status can't be changed in secret chats")); case DialogType::None: @@ -14536,22 +14551,26 @@ void ContactsManager::set_dialog_participant_status(DialogId dialog_id, UserId u } } -void ContactsManager::ban_dialog_participant(DialogId dialog_id, UserId user_id, int32 banned_until_date, - bool revoke_messages, Promise &&promise) { +void ContactsManager::ban_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id, + int32 banned_until_date, bool revoke_messages, Promise &&promise) { if (!td_->messages_manager_->have_dialog_force(dialog_id, "ban_dialog_participant")) { return promise.set_error(Status::Error(3, "Chat not found")); } switch (dialog_id.get_type()) { case DialogType::User: - return promise.set_error(Status::Error(3, "Can't ban members in a private chat")); + return promise.set_error(Status::Error(3, "Can't ban members in private chats")); case DialogType::Chat: - return delete_chat_participant(dialog_id.get_chat_id(), user_id, revoke_messages, std::move(promise)); + if (participant_dialog_id.get_type() != DialogType::User) { + return promise.set_error(Status::Error(3, "Can't ban chats in basic groups")); + } + return delete_chat_participant(dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), revoke_messages, + std::move(promise)); case DialogType::Channel: - return change_channel_participant_status(dialog_id.get_channel_id(), user_id, + return change_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id, DialogParticipantStatus::Banned(banned_until_date), std::move(promise)); case DialogType::SecretChat: - return promise.set_error(Status::Error(3, "Can't ban members in a secret chat")); + return promise.set_error(Status::Error(3, "Can't ban members in secret chats")); case DialogType::None: default: UNREACHABLE(); diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index f48edb578..ba59d8986 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -520,12 +520,12 @@ class ContactsManager : public Actor { void add_dialog_participants(DialogId dialog_id, const vector &user_ids, Promise &&promise); - void set_dialog_participant_status(DialogId dialog_id, UserId user_id, + void set_dialog_participant_status(DialogId dialog_id, DialogId participant_dialog_id, const tl_object_ptr &chat_member_status, Promise &&promise); - void ban_dialog_participant(DialogId dialog_id, UserId user_id, int32 banned_until_date, bool revoke_messages, - Promise &&promise); + void ban_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id, int32 banned_until_date, + bool revoke_messages, Promise &&promise); DialogParticipant get_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id, int64 &random_id, bool force, Promise &&promise); @@ -1488,8 +1488,8 @@ class ContactsManager : public Actor { void change_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status, Promise &&promise); - void change_channel_participant_status(ChannelId channel_id, UserId user_id, DialogParticipantStatus status, - Promise &&promise); + void change_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id, + DialogParticipantStatus status, Promise &&promise); void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise &&promise); @@ -1508,14 +1508,16 @@ class ContactsManager : public Actor { tl_object_ptr &&channel_participants, Promise &&promise); - void change_channel_participant_status_impl(ChannelId channel_id, UserId user_id, DialogParticipantStatus status, - DialogParticipantStatus old_status, Promise &&promise); + void change_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id, + DialogParticipantStatus status, DialogParticipantStatus old_status, + Promise &&promise); void promote_channel_participant(ChannelId channel_id, UserId user_id, DialogParticipantStatus status, DialogParticipantStatus old_status, Promise &&promise); - void restrict_channel_participant(ChannelId channel_id, UserId user_id, DialogParticipantStatus status, - DialogParticipantStatus old_status, Promise &&promise); + void restrict_channel_participant(ChannelId channel_id, DialogId participant_dialog_id, + DialogParticipantStatus status, DialogParticipantStatus old_status, + Promise &&promise); void transfer_channel_ownership(ChannelId channel_id, UserId user_id, tl_object_ptr input_check_password, diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index d1a071e86..565bd5449 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6323,8 +6323,8 @@ void Td::on_request(uint64 id, const td_api::leaveChat &request) { td_api::make_object(status.get_rank(), status.is_anonymous(), false); } } - contacts_manager_->set_dialog_participant_status(dialog_id, contacts_manager_->get_my_id(), std::move(new_status), - std::move(promise)); + contacts_manager_->set_dialog_participant_status(dialog_id, DialogId(contacts_manager_->get_my_id()), + std::move(new_status), std::move(promise)); } void Td::on_request(uint64 id, const td_api::addChatMember &request) { @@ -6343,13 +6343,15 @@ void Td::on_request(uint64 id, const td_api::addChatMembers &request) { void Td::on_request(uint64 id, td_api::setChatMemberStatus &request) { CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->set_dialog_participant_status(DialogId(request.chat_id_), UserId(request.user_id_), + contacts_manager_->set_dialog_participant_status(DialogId(request.chat_id_), + ContactsManager::get_participant_dialog_id(request.member_id_), request.status_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::banChatMember &request) { CREATE_OK_REQUEST_PROMISE(); - contacts_manager_->ban_dialog_participant(DialogId(request.chat_id_), UserId(request.user_id_), + contacts_manager_->ban_dialog_participant(DialogId(request.chat_id_), + ContactsManager::get_participant_dialog_id(request.member_id_), request.banned_until_date_, request.revoke_messages_, std::move(promise)); } diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index d6b5ecbdf..dba8ea74d 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -3646,11 +3646,11 @@ class CliClient final : public Actor { send_request(td_api::make_object(as_chat_id(chat_id), as_user_ids(user_ids))); } else if (op == "bcm") { string chat_id; - string user_id; + string member_id; int32 banned_until_date; bool revoke_messages; - get_args(args, chat_id, user_id, banned_until_date, revoke_messages); - send_request(td_api::make_object(as_chat_id(chat_id), as_user_id(user_id), + get_args(args, chat_id, member_id, banned_until_date, revoke_messages); + send_request(td_api::make_object(as_chat_id(chat_id), as_message_sender(member_id), banned_until_date, revoke_messages)); } else if (op == "spolla") { string chat_id; @@ -3679,10 +3679,10 @@ class CliClient final : public Actor { if (op == "scms") { string chat_id; - string user_id; + string member_id; string status_str; td_api::object_ptr status; - get_args(args, chat_id, user_id, status_str); + get_args(args, chat_id, member_id, status_str); if (status_str == "member") { status = td_api::make_object(); } else if (status_str == "left") { @@ -3738,7 +3738,7 @@ class CliClient final : public Actor { true, 0, td_api::make_object(true, true, true, true, true, true, true, true)); } if (status != nullptr) { - send_request(td_api::make_object(as_chat_id(chat_id), as_user_id(user_id), + send_request(td_api::make_object(as_chat_id(chat_id), as_message_sender(member_id), std::move(status))); } else { LOG(ERROR) << "Unknown status \"" << status_str << "\""; @@ -3764,14 +3764,14 @@ class CliClient final : public Actor { send_request(td_api::make_object(as_chat_id(args))); } else if (op == "dcm") { string chat_id; - string user_id_str; - get_args(args, chat_id, user_id_str); - auto user_id = as_user_id(user_id_str); + string member_id; + get_args(args, chat_id, member_id); td_api::object_ptr status = td_api::make_object(); - if (user_id == my_id_) { + if (as_user_id(member_id) == my_id_) { status = td_api::make_object(); } - send_request(td_api::make_object(as_chat_id(chat_id), user_id, std::move(status))); + send_request(td_api::make_object(as_chat_id(chat_id), as_message_sender(member_id), + std::move(status))); } else if (op == "sn") { string first_name; string last_name; From 7a65988f298e9ffab6b8de005affd23921398f10 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 26 Mar 2021 04:15:13 +0300 Subject: [PATCH 113/281] Check that other chats are only banned or unbanned. --- td/telegram/ContactsManager.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 7e09f86fe..b27492e07 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -7422,6 +7422,19 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogI return; } + switch (participant_dialog_id.get_type()) { + case DialogType::User: + // ok; + break; + case DialogType::Channel: + if (!status.is_banned() && !status.is_left()) { + return promise.set_error(Status::Error(400, "Other chats can be only banned or unbanned")); + } + break; + default: + return promise.set_error(Status::Error(400, "Can't restrict the chat")); + } + CHECK(!old_status.is_creator()); CHECK(!status.is_creator()); From f6b1ea8bdb3ff4b307374a5243ea8afd883ce6ec Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 26 Mar 2021 04:20:11 +0300 Subject: [PATCH 114/281] Forcely create Dialog in get_chat_member_object. --- td/telegram/ContactsManager.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index b27492e07..43caa5323 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -11539,12 +11539,15 @@ const DialogParticipant *ContactsManager::get_chat_full_participant(const ChatFu tl_object_ptr ContactsManager::get_chat_member_object( const DialogParticipant &dialog_participant) const { + DialogId dialog_id = dialog_participant.dialog_id; UserId participant_user_id; - if (dialog_participant.dialog_id.get_type() == DialogType::User) { - participant_user_id = dialog_participant.dialog_id.get_user_id(); + if (dialog_id.get_type() == DialogType::User) { + participant_user_id = dialog_id.get_user_id(); + } else { + td_->messages_manager_->force_create_dialog(dialog_id, "get_chat_member_object", true); } return td_api::make_object( - td_->messages_manager_->get_message_sender_object_const(dialog_participant.dialog_id), + td_->messages_manager_->get_message_sender_object_const(dialog_id), get_user_id_object(dialog_participant.inviter_user_id, "chatMember.inviter_user_id"), dialog_participant.joined_date, dialog_participant.status.get_chat_member_status_object(), get_bot_info_object(participant_user_id)); From f8667294151d336ac77b99e47a7a01d4c3cc8b6e Mon Sep 17 00:00:00 2001 From: Arseny Smirnov Date: Fri, 26 Mar 2021 16:56:30 +0300 Subject: [PATCH 115/281] update architectures for watchOS in example/ios --- CMake/iOS.cmake | 4 ++-- example/ios/Python-Apple-support.patch | 16 ++++++++++++++++ example/ios/build-openssl.sh | 2 ++ example/ios/build.sh | 1 + 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 example/ios/Python-Apple-support.patch diff --git a/CMake/iOS.cmake b/CMake/iOS.cmake index 70f611d57..4a6b213b8 100644 --- a/CMake/iOS.cmake +++ b/CMake/iOS.cmake @@ -197,9 +197,9 @@ if (IOS_PLATFORM STREQUAL "OS") elseif (IOS_PLATFORM STREQUAL "SIMULATOR") set (IOS_ARCH "i386;x86_64") elseif (IOS_PLATFORM STREQUAL "WATCHOS") - set (IOS_ARCH "armv7k") + set (IOS_ARCH "armv7k;arm64_32") elseif (IOS_PLATFORM STREQUAL "WATCHSIMULATOR") - set (IOS_ARCH "i386") + set (IOS_ARCH "i386;x86_64") elseif (IOS_PLATFORM STREQUAL "TVOS") set (IOS_ARCH "arm64") elseif (IOS_PLATFORM STREQUAL "TVSIMULATOR") diff --git a/example/ios/Python-Apple-support.patch b/example/ios/Python-Apple-support.patch new file mode 100644 index 000000000..fc7e9ae01 --- /dev/null +++ b/example/ios/Python-Apple-support.patch @@ -0,0 +1,16 @@ +diff --git a/Makefile b/Makefile +index 695be54..bce31b9 100644 +--- a/Makefile ++++ b/Makefile +@@ -56,9 +56,10 @@ CFLAGS-appletvos.arm64=-fembed-bitcode + PYTHON_CONFIGURE-tvOS=ac_cv_func_sigaltstack=no + + # watchOS targets +-TARGETS-watchOS=watchsimulator.i386 watchos.armv7k ++TARGETS-watchOS=watchsimulator.i386 watchsimulator.x86_64 watchos.armv7k watchos.arm64_32 + CFLAGS-watchOS=-mwatchos-version-min=4.0 + CFLAGS-watchos.armv7k=-fembed-bitcode ++CFLAGS-watchos.arm64_32=-fembed-bitcode + PYTHON_CONFIGURE-watchOS=ac_cv_func_sigaltstack=no + + # override machine types for arm64 diff --git a/example/ios/build-openssl.sh b/example/ios/build-openssl.sh index 8a6df6f83..3477530d6 100755 --- a/example/ios/build-openssl.sh +++ b/example/ios/build-openssl.sh @@ -3,10 +3,12 @@ git clone https://github.com/pybee/Python-Apple-support cd Python-Apple-support git checkout 60b990128d5f1f04c336ff66594574515ab56604 +git apply ../Python-Apple-support.patch cd .. #TODO: change openssl version platforms="macOS iOS watchOS tvOS" +#platforms="watchOS" for platform in $platforms; do echo $platform diff --git a/example/ios/build.sh b/example/ios/build.sh index 7ee8ff2e3..5b4ad9895 100755 --- a/example/ios/build.sh +++ b/example/ios/build.sh @@ -6,6 +6,7 @@ mkdir -p build cd build platforms="macOS iOS watchOS tvOS" +#platforms="watchOS" for platform in $platforms; do echo "Platform = ${platform} Simulator = ${simulator}" From 5c7b7d4c85d1966b248e86c1769fdee4fc151f06 Mon Sep 17 00:00:00 2001 From: Arseny Smirnov Date: Fri, 26 Mar 2021 18:04:01 +0300 Subject: [PATCH 116/281] TD_EXPERIMENTAL_WATCH_OS cmake option --- CMakeLists.txt | 1 + td/mtproto/HandshakeActor.cpp | 4 +- td/mtproto/Ping.cpp | 2 +- td/mtproto/RawConnection.cpp | 530 ++++++++++++++++++++------ td/mtproto/RawConnection.h | 102 +---- td/mtproto/SessionConnection.h | 2 +- td/telegram/Td.cpp | 4 +- td/telegram/net/ConnectionCreator.cpp | 101 ++--- td/telegram/net/ConnectionCreator.h | 6 +- td/telegram/net/Session.cpp | 6 +- tdnet/CMakeLists.txt | 15 + tdnet/td/net/DarwinHttp.h | 13 + tdnet/td/net/DarwinHttp.mm | 57 +++ tdutils/td/utils/config.h.in | 1 + tdutils/td/utils/port/IPAddress.cpp | 6 + tdutils/td/utils/port/SocketFd.cpp | 4 + test/http.cpp | 39 ++ test/mtproto.cpp | 20 +- 18 files changed, 651 insertions(+), 262 deletions(-) create mode 100644 tdnet/td/net/DarwinHttp.h create mode 100644 tdnet/td/net/DarwinHttp.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f1d7ac71..e0e42d552 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ prevent_in_source_build() option(TD_ENABLE_JNI "Use \"ON\" to enable JNI-compatible TDLib API.") option(TD_ENABLE_DOTNET "Use \"ON\" to enable generation of C++/CLI or C++/CX TDLib API bindings.") +option(TD_EXPERIMENTAL_WATCH_OS "Use \"ON\" to enable watch os support.") if (TD_ENABLE_DOTNET AND (CMAKE_VERSION VERSION_LESS "3.1.0")) message(FATAL_ERROR "CMake 3.1.0 or higher is required. You are running version ${CMAKE_VERSION}.") diff --git a/td/mtproto/HandshakeActor.cpp b/td/mtproto/HandshakeActor.cpp index 9afca6ce7..a3cf20745 100644 --- a/td/mtproto/HandshakeActor.cpp +++ b/td/mtproto/HandshakeActor.cpp @@ -55,8 +55,8 @@ void HandshakeActor::return_connection(Status status) { CHECK(!raw_connection_promise_); return; } - if (status.is_error() && !raw_connection->debug_str_.empty()) { - status = Status::Error(status.code(), PSLICE() << status.message() << " : " << raw_connection->debug_str_); + if (status.is_error() && !raw_connection->extra().debug_str.empty()) { + status = Status::Error(status.code(), PSLICE() << status.message() << " : " << raw_connection->extra().debug_str); } Scheduler::unsubscribe(raw_connection->get_poll_info().get_pollable_fd_ref()); if (raw_connection_promise_) { diff --git a/td/mtproto/Ping.cpp b/td/mtproto/Ping.cpp index e4ff9def3..b53181526 100644 --- a/td/mtproto/Ping.cpp +++ b/td/mtproto/Ping.cpp @@ -85,7 +85,7 @@ ActorOwn<> create_ping_actor(string debug, unique_ptr raw_connect raw_connection->close(); promise_.set_error(std::move(status)); } else { - raw_connection->rtt_ = ping_connection_->rtt(); + raw_connection->extra().rtt = ping_connection_->rtt(); if (raw_connection->stats_callback()) { raw_connection->stats_callback()->on_pong(); } diff --git a/td/mtproto/RawConnection.cpp b/td/mtproto/RawConnection.cpp index 835823498..6cefa1faf 100644 --- a/td/mtproto/RawConnection.cpp +++ b/td/mtproto/RawConnection.cpp @@ -15,148 +15,440 @@ #include "td/utils/Status.h" #include "td/utils/StorerBase.h" +#if TD_EXPERIMENTAL_WATCH_OS +#include "td/net/DarwinHttp.h" +#endif + #include namespace td { namespace mtproto { -void RawConnection::send_crypto(const Storer &storer, int64 session_id, int64 salt, const AuthKey &auth_key, - uint64 quick_ack_token) { - PacketInfo info; - info.version = 2; - info.no_crypto_flag = false; - info.salt = salt; - info.session_id = session_id; - info.use_random_padding = transport_->use_random_padding(); - - auto packet = BufferWriter{Transport::write(storer, auth_key, &info), transport_->max_prepend_size(), - transport_->max_append_size()}; - Transport::write(storer, auth_key, &info, packet.as_slice()); - - bool use_quick_ack = false; - if (quick_ack_token != 0 && transport_->support_quick_ack()) { - auto tmp = quick_ack_to_token_.emplace(info.message_ack, quick_ack_token); - if (tmp.second) { - use_quick_ack = true; - } else { - LOG(ERROR) << "Quick ack " << info.message_ack << " collision"; - } +class RawConnectionDefault : public RawConnection { + public: + RawConnectionDefault(SocketFd socket_fd, TransportType transport_type, unique_ptr stats_callback) + : socket_fd_(std::move(socket_fd)) + , transport_(create_transport(transport_type)) + , stats_callback_(std::move(stats_callback)) { + transport_->init(&socket_fd_.input_buffer(), &socket_fd_.output_buffer()); } - transport_->write(std::move(packet), use_quick_ack); -} - -uint64 RawConnection::send_no_crypto(const Storer &storer) { - PacketInfo info; - - info.no_crypto_flag = true; - auto packet = BufferWriter{Transport::write(storer, AuthKey(), &info), transport_->max_prepend_size(), - transport_->max_append_size()}; - Transport::write(storer, AuthKey(), &info, packet.as_slice()); - LOG(INFO) << "Send handshake packet: " << format::as_hex_dump<4>(packet.as_slice()); - transport_->write(std::move(packet), false); - return info.message_id; -} - -Status RawConnection::flush_read(const AuthKey &auth_key, Callback &callback) { - auto r = socket_fd_.flush_read(); - if (r.is_ok()) { - if (stats_callback_) { - stats_callback_->on_read(r.ok()); - } - callback.on_read(r.ok()); + void set_connection_token(StateManager::ConnectionToken connection_token) override { + connection_token_ = std::move(connection_token); } - while (transport_->can_read()) { - BufferSlice packet; - uint32 quick_ack = 0; - TRY_RESULT(wait_size, transport_->read_next(&packet, &quick_ack)); - if (!is_aligned_pointer<4>(packet.as_slice().ubegin())) { - BufferSlice new_packet(packet.size()); - new_packet.as_slice().copy_from(packet.as_slice()); - packet = std::move(new_packet); - } - LOG_CHECK(is_aligned_pointer<4>(packet.as_slice().ubegin())) - << packet.as_slice().ubegin() << ' ' << packet.size() << ' ' << wait_size; - if (wait_size != 0) { - constexpr size_t MAX_PACKET_SIZE = (1 << 22) + 1024; - if (wait_size > MAX_PACKET_SIZE) { - return Status::Error(PSLICE() << "Expected packet size is too big: " << wait_size); - } - break; - } - - if (quick_ack != 0) { - TRY_STATUS(on_quick_ack(quick_ack, callback)); - continue; - } + bool can_send() const override { + return transport_->can_write(); + } + TransportType get_transport_type() const override { + return transport_->get_type(); + } + void send_crypto(const Storer &storer, int64 session_id, int64 salt, const AuthKey &auth_key, + uint64 quick_ack_token) override { PacketInfo info; info.version = 2; + info.no_crypto_flag = false; + info.salt = salt; + info.session_id = session_id; + info.use_random_padding = transport_->use_random_padding(); - TRY_RESULT(read_result, Transport::read(packet.as_slice(), auth_key, &info)); - switch (read_result.type()) { - case Transport::ReadResult::Quickack: { - TRY_STATUS(on_quick_ack(read_result.quick_ack(), callback)); - break; + auto packet = BufferWriter{Transport::write(storer, auth_key, &info), transport_->max_prepend_size(), + transport_->max_append_size()}; + Transport::write(storer, auth_key, &info, packet.as_slice()); + + bool use_quick_ack = false; + if (quick_ack_token != 0 && transport_->support_quick_ack()) { + auto tmp = quick_ack_to_token_.emplace(info.message_ack, quick_ack_token); + if (tmp.second) { + use_quick_ack = true; + } else { + LOG(ERROR) << "Quick ack " << info.message_ack << " collision"; } - case Transport::ReadResult::Error: { - TRY_STATUS(on_read_mtproto_error(read_result.error())); - break; + } + + transport_->write(std::move(packet), use_quick_ack); + } + + uint64 send_no_crypto(const Storer &storer) override { + PacketInfo info; + + info.no_crypto_flag = true; + auto packet = BufferWriter{Transport::write(storer, AuthKey(), &info), transport_->max_prepend_size(), + transport_->max_append_size()}; + Transport::write(storer, AuthKey(), &info, packet.as_slice()); + LOG(INFO) << "Send handshake packet: " << format::as_hex_dump<4>(packet.as_slice()); + transport_->write(std::move(packet), false); + return info.message_id; + } + + PollableFdInfo &get_poll_info() override { + return socket_fd_.get_poll_info(); + } + + StatsCallback *stats_callback() override { + return stats_callback_.get(); + } + + // NB: After first returned error, all subsequent calls will return error too. + Status flush(const AuthKey &auth_key, Callback &callback) override { + auto status = do_flush(auth_key, callback); + if (status.is_error()) { + if (stats_callback_ && status.code() != 2) { + stats_callback_->on_error(); } - case Transport::ReadResult::Packet: { - // If a packet was successfully decrypted, then it is ok to assume that the connection is alive - if (!auth_key.empty()) { - if (stats_callback_) { - stats_callback_->on_pong(); - } + has_error_ = true; + } + return status; + } + + bool has_error() const override { + return has_error_; + } + + void close() override { + transport_.reset(); + socket_fd_.close(); + } + + PublicFields &extra() override { + return extra_; + } + const PublicFields &extra() const override { + return extra_; + } + + private: + PublicFields extra_; + BufferedFd socket_fd_; + unique_ptr transport_; + std::map quick_ack_to_token_; + bool has_error_{false}; + + unique_ptr stats_callback_; + + StateManager::ConnectionToken connection_token_; + + Status flush_read(const AuthKey &auth_key, Callback &callback) { + auto r = socket_fd_.flush_read(); + if (r.is_ok()) { + if (stats_callback_) { + stats_callback_->on_read(r.ok()); + } + callback.on_read(r.ok()); + } + while (transport_->can_read()) { + BufferSlice packet; + uint32 quick_ack = 0; + TRY_RESULT(wait_size, transport_->read_next(&packet, &quick_ack)); + if (!is_aligned_pointer<4>(packet.as_slice().ubegin())) { + BufferSlice new_packet(packet.size()); + new_packet.as_slice().copy_from(packet.as_slice()); + packet = std::move(new_packet); + } + LOG_CHECK(is_aligned_pointer<4>(packet.as_slice().ubegin())) + << packet.as_slice().ubegin() << ' ' << packet.size() << ' ' << wait_size; + if (wait_size != 0) { + constexpr size_t MAX_PACKET_SIZE = (1 << 22) + 1024; + if (wait_size > MAX_PACKET_SIZE) { + return Status::Error(PSLICE() << "Expected packet size is too big: " << wait_size); } - - TRY_STATUS(callback.on_raw_packet(info, packet.from_slice(read_result.packet()))); break; } - case Transport::ReadResult::Nop: - break; - default: - UNREACHABLE(); + + if (quick_ack != 0) { + TRY_STATUS(on_quick_ack(quick_ack, callback)); + continue; + } + + PacketInfo info; + info.version = 2; + + TRY_RESULT(read_result, Transport::read(packet.as_slice(), auth_key, &info)); + switch (read_result.type()) { + case Transport::ReadResult::Quickack: { + TRY_STATUS(on_quick_ack(read_result.quick_ack(), callback)); + break; + } + case Transport::ReadResult::Error: { + TRY_STATUS(on_read_mtproto_error(read_result.error())); + break; + } + case Transport::ReadResult::Packet: { + // If a packet was successfully decrypted, then it is ok to assume that the connection is alive + if (!auth_key.empty()) { + if (stats_callback_) { + stats_callback_->on_pong(); + } + } + + TRY_STATUS(callback.on_raw_packet(info, packet.from_slice(read_result.packet()))); + break; + } + case Transport::ReadResult::Nop: + break; + default: + UNREACHABLE(); + } } - } - TRY_STATUS(std::move(r)); - return Status::OK(); -} - -Status RawConnection::on_read_mtproto_error(int32 error_code) { - if (error_code == -429) { - if (stats_callback_) { - stats_callback_->on_mtproto_error(); - } - return Status::Error(500, PSLICE() << "MTProto error: " << error_code); - } - if (error_code == -404) { - return Status::Error(-404, PSLICE() << "MTProto error: " << error_code); - } - return Status::Error(PSLICE() << "MTProto error: " << error_code); -} - -Status RawConnection::on_quick_ack(uint32 quick_ack, Callback &callback) { - auto it = quick_ack_to_token_.find(quick_ack); - if (it == quick_ack_to_token_.end()) { - LOG(WARNING) << Status::Error(PSLICE() << "Unknown quick_ack " << quick_ack); + TRY_STATUS(std::move(r)); return Status::OK(); - // TODO: return Status::Error(PSLICE() << "Unknown quick_ack " << quick_ack); } - auto token = it->second; - quick_ack_to_token_.erase(it); - callback.on_quick_ack(token).ignore(); - return Status::OK(); -} -Status RawConnection::flush_write() { - TRY_RESULT(size, socket_fd_.flush_write()); - if (size > 0 && stats_callback_) { - stats_callback_->on_write(size); + Status on_read_mtproto_error(int32 error_code) { + if (error_code == -429) { + if (stats_callback_) { + stats_callback_->on_mtproto_error(); + } + return Status::Error(500, PSLICE() << "MTProto error: " << error_code); + } + if (error_code == -404) { + return Status::Error(-404, PSLICE() << "MTProto error: " << error_code); + } + return Status::Error(PSLICE() << "MTProto error: " << error_code); } - return Status::OK(); + + Status on_quick_ack(uint32 quick_ack, Callback &callback) { + auto it = quick_ack_to_token_.find(quick_ack); + if (it == quick_ack_to_token_.end()) { + LOG(WARNING) << Status::Error(PSLICE() << "Unknown quick_ack " << quick_ack); + return Status::OK(); + // TODO: return Status::Error(PSLICE() << "Unknown quick_ack " << quick_ack); + } + auto token = it->second; + quick_ack_to_token_.erase(it); + callback.on_quick_ack(token).ignore(); + return Status::OK(); + } + + Status flush_write() { + TRY_RESULT(size, socket_fd_.flush_write()); + if (size > 0 && stats_callback_) { + stats_callback_->on_write(size); + } + return Status::OK(); + } + + Status do_flush(const AuthKey &auth_key, Callback &callback) TD_WARN_UNUSED_RESULT { + if (has_error_) { + return Status::Error("Connection has already failed"); + } + sync_with_poll(socket_fd_); + + // read/write + // EINVAL may be returned in linux kernel < 2.6.28. And on some new kernels too. + // just close connection and hope that read or write will not return this error too. + TRY_STATUS(socket_fd_.get_pending_error()); + + TRY_STATUS(flush_read(auth_key, callback)); + TRY_STATUS(callback.before_write()); + TRY_STATUS(flush_write()); + if (can_close_local(socket_fd_)) { + return Status::Error("Connection closed"); + } + return Status::OK(); + } +}; + +#if TD_EXPERIMENTAL_WATCH_OS +class RawConnectionHttp : public RawConnection { + public: + RawConnectionHttp(IPAddress ip_address, unique_ptr stats_callback) + : ip_address_(std::move(ip_address)), stats_callback_(std::move(stats_callback)) { + answers_ = std::make_shared>>(); + answers_->init(); + } + + void set_connection_token(StateManager::ConnectionToken connection_token) override { + connection_token_ = std::move(connection_token); + } + + bool can_send() const override { + return mode_ == Send; + } + TransportType get_transport_type() const override { + return mtproto::TransportType{mtproto::TransportType::Http, 0, mtproto::ProxySecret()}; + } + void send_crypto(const Storer &storer, int64 session_id, int64 salt, const AuthKey &auth_key, + uint64 quick_ack_token) override { + PacketInfo info; + info.version = 2; + info.no_crypto_flag = false; + info.salt = salt; + info.session_id = session_id; + info.use_random_padding = false; + + auto packet = BufferWriter{Transport::write(storer, auth_key, &info), 0, 0}; + Transport::write(storer, auth_key, &info, packet.as_slice()); + + send_packet(packet.as_buffer_slice()); + } + + uint64 send_no_crypto(const Storer &storer) override { + PacketInfo info; + + info.no_crypto_flag = true; + auto packet = BufferWriter{Transport::write(storer, AuthKey(), &info), 0, 0}; + Transport::write(storer, AuthKey(), &info, packet.as_slice()); + LOG(INFO) << "Send handshake packet: " << format::as_hex_dump<4>(packet.as_slice()); + send_packet(packet.as_buffer_slice()); + return info.message_id; + } + + PollableFdInfo &get_poll_info() override { + return answers_->reader_get_event_fd().get_poll_info(); + } + + StatsCallback *stats_callback() override { + return stats_callback_.get(); + } + + // NB: After first returned error, all subsequent calls will return error too. + Status flush(const AuthKey &auth_key, Callback &callback) override { + auto status = do_flush(auth_key, callback); + if (status.is_error()) { + if (stats_callback_ && status.code() != 2) { + stats_callback_->on_error(); + } + has_error_ = true; + } + return status; + } + + bool has_error() const override { + return has_error_; + } + + void close() override { + } + + PublicFields &extra() override { + return extra_; + } + const PublicFields &extra() const override { + return extra_; + } + + private: + PublicFields extra_; + IPAddress ip_address_; + bool has_error_{false}; + EventFd event_fd_; + + enum Mode { Send, Receive } mode_{Send}; + + unique_ptr stats_callback_; + + StateManager::ConnectionToken connection_token_; + std::shared_ptr>> answers_; + std::vector to_send_; + + void send_packet(BufferSlice packet) { + CHECK(mode_ == Send); + mode_ = Receive; + to_send_.push_back(std::move(packet)); + } + + Status flush_read(const AuthKey &auth_key, Callback &callback) { + while (true) { + auto packets_n = answers_->reader_wait_nonblock(); + if (packets_n == 0) { + break; + } + for (int i = 0; i < packets_n; i++) { + TRY_RESULT(packet, answers_->reader_get_unsafe()); + if (stats_callback_) { + stats_callback_->on_read(packet.size()); + } + callback.on_read(packet.size()); + CHECK(mode_ == Receive); + mode_ = Send; + + PacketInfo info; + info.version = 2; + + TRY_RESULT(read_result, Transport::read(packet.as_slice(), auth_key, &info)); + switch (read_result.type()) { + case Transport::ReadResult::Quickack: { + break; + } + case Transport::ReadResult::Error: { + TRY_STATUS(on_read_mtproto_error(read_result.error())); + break; + } + case Transport::ReadResult::Packet: { + // If a packet was successfully decrypted, then it is ok to assume that the connection is alive + if (!auth_key.empty()) { + if (stats_callback_) { + stats_callback_->on_pong(); + } + } + + TRY_STATUS(callback.on_raw_packet(info, packet.from_slice(read_result.packet()))); + break; + } + case Transport::ReadResult::Nop: + break; + default: + UNREACHABLE(); + } + } + } + + return Status::OK(); + } + + Status on_read_mtproto_error(int32 error_code) { + if (error_code == -429) { + if (stats_callback_) { + stats_callback_->on_mtproto_error(); + } + return Status::Error(500, PSLICE() << "MTProto error: " << error_code); + } + if (error_code == -404) { + return Status::Error(-404, PSLICE() << "MTProto error: " << error_code); + } + return Status::Error(PSLICE() << "MTProto error: " << error_code); + } + + Status flush_write() { + for (auto &packet : to_send_) { + TRY_STATUS(do_send(packet.as_slice())); + if (packet.size() > 0 && stats_callback_) { + stats_callback_->on_write(packet.size()); + } + } + to_send_.clear(); + return Status::OK(); + } + + Status do_send(Slice data) { + DarwinHttp::post(PSLICE() << "http://" << ip_address_.get_ip_str() << ":" << ip_address_.get_port() << "/api", data, + [answers = answers_](auto res) { answers->writer_put(std::move(res)); }); + return Status::OK(); + } + + Status do_flush(const AuthKey &auth_key, Callback &callback) TD_WARN_UNUSED_RESULT { + if (has_error_) { + return Status::Error("Connection has already failed"); + } + + TRY_STATUS(flush_read(auth_key, callback)); + TRY_STATUS(callback.before_write()); + TRY_STATUS(flush_write()); + return Status::OK(); + } +}; +#endif + +td::unique_ptr RawConnection::create(IPAddress ip_address, SocketFd socket_fd, + TransportType transport_type, + unique_ptr stats_callback) { +#if TD_EXPERIMENTAL_WATCH_OS + return td::make_unique(ip_address, std::move(stats_callback)); +#else + return td::make_unique(std::move(socket_fd), transport_type, std::move(stats_callback)); +#endif } } // namespace mtproto diff --git a/td/mtproto/RawConnection.h b/td/mtproto/RawConnection.h index 924ebab1c..90a602fd6 100644 --- a/td/mtproto/RawConnection.h +++ b/td/mtproto/RawConnection.h @@ -39,34 +39,20 @@ class RawConnection { virtual void on_error() = 0; // called on RawConnection error. Such error should be very rare on good connections. virtual void on_mtproto_error() = 0; }; - RawConnection() = default; - RawConnection(SocketFd socket_fd, TransportType transport_type, unique_ptr stats_callback) - : socket_fd_(std::move(socket_fd)) - , transport_(create_transport(transport_type)) - , stats_callback_(std::move(stats_callback)) { - transport_->init(&socket_fd_.input_buffer(), &socket_fd_.output_buffer()); - } + virtual ~RawConnection() = default; + static td::unique_ptr create(IPAddress ip_address, SocketFd socket_fd, TransportType transport_type, + unique_ptr stats_callback); - void set_connection_token(StateManager::ConnectionToken connection_token) { - connection_token_ = std::move(connection_token); - } + virtual void set_connection_token(StateManager::ConnectionToken connection_token) = 0; - bool can_send() const { - return transport_->can_write(); - } - TransportType get_transport_type() const { - return transport_->get_type(); - } - void send_crypto(const Storer &storer, int64 session_id, int64 salt, const AuthKey &auth_key, - uint64 quick_ack_token = 0); - uint64 send_no_crypto(const Storer &storer); + virtual bool can_send() const = 0; + virtual TransportType get_transport_type() const = 0; + virtual void send_crypto(const Storer &storer, int64 session_id, int64 salt, const AuthKey &auth_key, + uint64 quick_ack_token = 0) = 0; + virtual uint64 send_no_crypto(const Storer &storer) = 0; - PollableFdInfo &get_poll_info() { - return socket_fd_.get_poll_info(); - } - StatsCallback *stats_callback() { - return stats_callback_.get(); - } + virtual PollableFdInfo &get_poll_info() = 0; + virtual StatsCallback *stats_callback() = 0; class Callback { public: @@ -86,65 +72,19 @@ class RawConnection { }; // NB: After first returned error, all subsequent calls will return error too. - Status flush(const AuthKey &auth_key, Callback &callback) TD_WARN_UNUSED_RESULT { - auto status = do_flush(auth_key, callback); - if (status.is_error()) { - if (stats_callback_ && status.code() != 2) { - stats_callback_->on_error(); - } - has_error_ = true; - } - return status; - } + virtual Status flush(const AuthKey &auth_key, Callback &callback) TD_WARN_UNUSED_RESULT = 0; + virtual bool has_error() const = 0; - bool has_error() const { - return has_error_; - } + virtual void close() = 0; - void close() { - transport_.reset(); - socket_fd_.close(); - } + struct PublicFields { + uint32 extra{0}; + string debug_str; + double rtt{0}; + }; - uint32 extra_{0}; - string debug_str_; - double rtt_{0}; - - private: - BufferedFd socket_fd_; - unique_ptr transport_; - std::map quick_ack_to_token_; - bool has_error_{false}; - - unique_ptr stats_callback_; - - StateManager::ConnectionToken connection_token_; - - Status flush_read(const AuthKey &auth_key, Callback &callback); - Status flush_write(); - - Status on_quick_ack(uint32 quick_ack, Callback &callback); - Status on_read_mtproto_error(int32 error_code); - - Status do_flush(const AuthKey &auth_key, Callback &callback) TD_WARN_UNUSED_RESULT { - if (has_error_) { - return Status::Error("Connection has already failed"); - } - sync_with_poll(socket_fd_); - - // read/write - // EINVAL may be returned in linux kernel < 2.6.28. And on some new kernels too. - // just close connection and hope that read or write will not return this error too. - TRY_STATUS(socket_fd_.get_pending_error()); - - TRY_STATUS(flush_read(auth_key, callback)); - TRY_STATUS(callback.before_write()); - TRY_STATUS(flush_write()); - if (can_close_local(socket_fd_)) { - return Status::Error("Connection closed"); - } - return Status::OK(); - } + virtual PublicFields &extra() = 0; + virtual const PublicFields &extra() const = 0; }; } // namespace mtproto diff --git a/td/mtproto/SessionConnection.h b/td/mtproto/SessionConnection.h index 82275ad01..ca9e1fb16 100644 --- a/td/mtproto/SessionConnection.h +++ b/td/mtproto/SessionConnection.h @@ -132,7 +132,7 @@ class SessionConnection bool is_main_ = false; int rtt() const { - return max(2, static_cast(raw_connection_->rtt_ * 1.5 + 1)); + return max(2, static_cast(raw_connection_->extra().rtt * 1.5 + 1)); } int32 read_disconnect_delay() const { diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index daf709ffa..98bb4c44b 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -591,7 +591,7 @@ class TestProxyRequest : public RequestOnceActor { }); child_ = - ConnectionCreator::prepare_connection(r_socket_fd.move_as_ok(), proxy_, mtproto_ip_address, get_transport(), + ConnectionCreator::prepare_connection(ip, r_socket_fd.move_as_ok(), proxy_, mtproto_ip_address, get_transport(), "Test", "TestPingDC2", nullptr, {}, false, std::move(connection_promise)); } @@ -613,7 +613,7 @@ class TestProxyRequest : public RequestOnceActor { }; auto handshake = make_unique(dc_id_, 3600); auto data = r_data.move_as_ok(); - auto raw_connection = make_unique(std::move(data.socket_fd), get_transport(), nullptr); + auto raw_connection = mtproto::RawConnection::create(data.ip_address, std::move(data.socket_fd), get_transport(), nullptr); child_ = create_actor( "HandshakeActor", std::move(handshake), std::move(raw_connection), make_unique(), 10.0, PromiseCreator::lambda([actor_id = actor_id(this)](Result> raw_connection) { diff --git a/td/telegram/net/ConnectionCreator.cpp b/td/telegram/net/ConnectionCreator.cpp index 013d39a3e..63dd6a617 100644 --- a/td/telegram/net/ConnectionCreator.cpp +++ b/td/telegram/net/ConnectionCreator.cpp @@ -323,7 +323,8 @@ void ConnectionCreator::ping_proxy(int32 proxy_id, Promise promise) { continue; } - auto r_socket_fd = SocketFd::open(info.option->get_ip_address()); + auto ip = info.option->get_ip_address(); + auto r_socket_fd = SocketFd::open(ip); if (r_socket_fd.is_error()) { LOG(DEBUG) << "Failed to open socket: " << r_socket_fd.error(); on_ping_main_dc_result(token, r_socket_fd.move_as_error()); @@ -331,7 +332,7 @@ void ConnectionCreator::ping_proxy(int32 proxy_id, Promise promise) { } ping_proxy_socket_fd( - r_socket_fd.move_as_ok(), r_transport_type.move_as_ok(), PSTRING() << info.option->get_ip_address(), + ip, r_socket_fd.move_as_ok(), r_transport_type.move_as_ok(), PSTRING() << info.option->get_ip_address(), PromiseCreator::lambda([actor_id = actor_id(this), token](Result result) { send_closure(actor_id, &ConnectionCreator::on_ping_main_dc_result, token, std::move(result)); })); @@ -371,28 +372,31 @@ void ConnectionCreator::ping_proxy_resolved(int32 proxy_id, IPAddress ip_address auto socket_fd = r_socket_fd.move_as_ok(); auto connection_promise = PromiseCreator::lambda( - [promise = std::move(promise), actor_id = actor_id(this), transport_type = extra.transport_type, + [ip_address, promise = std::move(promise), actor_id = actor_id(this), transport_type = extra.transport_type, debug_str = std::move(extra.debug_str)](Result r_connection_data) mutable { if (r_connection_data.is_error()) { return promise.set_error(Status::Error(400, r_connection_data.error().public_message())); } - send_closure(actor_id, &ConnectionCreator::ping_proxy_socket_fd, r_connection_data.move_as_ok().socket_fd, - std::move(transport_type), std::move(debug_str), std::move(promise)); + send_closure(actor_id, &ConnectionCreator::ping_proxy_socket_fd, ip_address, + r_connection_data.move_as_ok().socket_fd, std::move(transport_type), std::move(debug_str), + std::move(promise)); }); CHECK(proxy.use_proxy()); auto token = next_token(); - auto ref = - prepare_connection(std::move(socket_fd), proxy, extra.mtproto_ip_address, extra.transport_type, "Ping", - extra.debug_str, nullptr, create_reference(token), false, std::move(connection_promise)); + auto ref = prepare_connection(extra.ip_address, std::move(socket_fd), proxy, extra.mtproto_ip_address, + extra.transport_type, "Ping", extra.debug_str, nullptr, create_reference(token), false, + std::move(connection_promise)); if (!ref.empty()) { children_[token] = {false, std::move(ref)}; } } -void ConnectionCreator::ping_proxy_socket_fd(SocketFd socket_fd, mtproto::TransportType transport_type, - string debug_str, Promise promise) { +void ConnectionCreator::ping_proxy_socket_fd(IPAddress ip_address, SocketFd socket_fd, + mtproto::TransportType transport_type, string debug_str, + Promise promise) { auto token = next_token(); - auto raw_connection = make_unique(std::move(socket_fd), std::move(transport_type), nullptr); + auto raw_connection = + mtproto::RawConnection::create(ip_address, std::move(socket_fd), std::move(transport_type), nullptr); children_[token] = { false, create_ping_actor(std::move(debug_str), std::move(raw_connection), nullptr, PromiseCreator::lambda([promise = std::move(promise)]( @@ -400,7 +404,7 @@ void ConnectionCreator::ping_proxy_socket_fd(SocketFd socket_fd, mtproto::Transp if (result.is_error()) { return promise.set_error(Status::Error(400, result.error().public_message())); } - auto ping_time = result.ok()->rtt_; + auto ping_time = result.ok()->extra().rtt; promise.set_value(std::move(ping_time)); }), create_reference(token))}; @@ -643,20 +647,20 @@ void ConnectionCreator::request_raw_connection_by_ip(IPAddress ip_address, mtpro } auto socket_fd = r_socket_fd.move_as_ok(); - auto connection_promise = PromiseCreator::lambda( - [promise = std::move(promise), actor_id = actor_id(this), transport_type, - network_generation = network_generation_](Result r_connection_data) mutable { - if (r_connection_data.is_error()) { - return promise.set_error(Status::Error(400, r_connection_data.error().public_message())); - } - auto raw_connection = - make_unique(r_connection_data.move_as_ok().socket_fd, transport_type, nullptr); - raw_connection->extra_ = network_generation; - promise.set_value(std::move(raw_connection)); - }); + auto connection_promise = PromiseCreator::lambda([promise = std::move(promise), actor_id = actor_id(this), + transport_type, network_generation = network_generation_, + ip_address](Result r_connection_data) mutable { + if (r_connection_data.is_error()) { + return promise.set_error(Status::Error(400, r_connection_data.error().public_message())); + } + auto raw_connection = + mtproto::RawConnection::create(ip_address, r_connection_data.move_as_ok().socket_fd, transport_type, nullptr); + raw_connection->extra().extra = network_generation; + promise.set_value(std::move(raw_connection)); + }); auto token = next_token(); - auto ref = prepare_connection(std::move(socket_fd), Proxy(), IPAddress(), transport_type, "Raw", + auto ref = prepare_connection(ip_address, std::move(socket_fd), Proxy(), IPAddress(), transport_type, "Raw", PSTRING() << "to IP address " << ip_address, nullptr, create_reference(token), false, std::move(connection_promise)); if (!ref.empty()) { @@ -699,6 +703,9 @@ Result ConnectionCreator::find_connection(const Proxy &proxy, const IP bool prefer_ipv6 = G()->shared_config().get_option_boolean("prefer_ipv6") || (proxy.use_proxy() && proxy_ip_address.is_ipv6()); bool only_http = proxy.use_http_caching_proxy(); +#if TD_EXPERIMENTAL_WATCH_OS + only_http = true; +#endif TRY_RESULT(info, dc_options_set_.find_connection( dc_id, allow_media_only, proxy.use_proxy() && proxy.use_socks5_proxy(), prefer_ipv6, only_http)); extra.stat = info.stat; @@ -718,29 +725,33 @@ Result ConnectionCreator::find_connection(const Proxy &proxy, const IP if (proxy.use_proxy()) { extra.mtproto_ip_address = info.option->get_ip_address(); + extra.ip_address = proxy_ip_address; extra.debug_str = PSTRING() << (proxy.use_socks5_proxy() ? "Socks5" : (only_http ? "HTTP_ONLY" : "HTTP_TCP")) << ' ' << proxy_ip_address << " --> " << extra.mtproto_ip_address << extra.debug_str; - VLOG(connections) << "Create: " << extra.debug_str; - return SocketFd::open(proxy_ip_address); } else { + extra.ip_address = info.option->get_ip_address(); extra.debug_str = PSTRING() << info.option->get_ip_address() << extra.debug_str; - VLOG(connections) << "Create: " << extra.debug_str; - return SocketFd::open(info.option->get_ip_address()); } + VLOG(connections) << "Create: " << extra.debug_str; + return SocketFd::open(extra.ip_address); } -ActorOwn<> ConnectionCreator::prepare_connection( - SocketFd socket_fd, const Proxy &proxy, const IPAddress &mtproto_ip_address, mtproto::TransportType transport_type, - Slice actor_name_prefix, Slice debug_str, unique_ptr stats_callback, - ActorShared<> parent, bool use_connection_token, Promise promise) { +ActorOwn<> ConnectionCreator::prepare_connection(IPAddress ip_address, SocketFd socket_fd, const Proxy &proxy, + const IPAddress &mtproto_ip_address, + mtproto::TransportType transport_type, Slice actor_name_prefix, + Slice debug_str, + unique_ptr stats_callback, + ActorShared<> parent, bool use_connection_token, + Promise promise) { if (proxy.use_socks5_proxy() || proxy.use_http_tcp_proxy() || transport_type.secret.emulate_tls()) { VLOG(connections) << "Create new transparent proxy connection " << debug_str; class Callback : public TransparentProxy::Callback { public: - explicit Callback(Promise promise, + explicit Callback(Promise promise, IPAddress ip_address, unique_ptr stats_callback, bool use_connection_token, bool was_connected) : promise_(std::move(promise)) + , ip_address_(std::move(ip_address)) , stats_callback_(std::move(stats_callback)) , use_connection_token_(use_connection_token) , was_connected_(was_connected) { @@ -756,6 +767,7 @@ ActorOwn<> ConnectionCreator::prepare_connection( promise_.set_error(Status::Error(400, result.error().public_message())); } else { ConnectionData data; + data.ip_address = ip_address_; data.socket_fd = result.move_as_ok(); data.connection_token = std::move(connection_token_); data.stats_callback = std::move(stats_callback_); @@ -772,6 +784,7 @@ ActorOwn<> ConnectionCreator::prepare_connection( private: Promise promise_; StateManager::ConnectionToken connection_token_; + IPAddress ip_address_; unique_ptr stats_callback_; bool use_connection_token_; bool was_connected_{false}; @@ -779,8 +792,8 @@ ActorOwn<> ConnectionCreator::prepare_connection( VLOG(connections) << "Start " << (proxy.use_socks5_proxy() ? "Socks5" : (proxy.use_http_tcp_proxy() ? "HTTP" : "TLS")) << ": " << debug_str; - auto callback = make_unique(std::move(promise), std::move(stats_callback), use_connection_token, - !proxy.use_socks5_proxy()); + auto callback = make_unique(std::move(promise), ip_address, std::move(stats_callback), + use_connection_token, !proxy.use_socks5_proxy()); if (proxy.use_socks5_proxy()) { return ActorOwn<>(create_actor(PSLICE() << actor_name_prefix << "Socks5", std::move(socket_fd), mtproto_ip_address, proxy.user().str(), proxy.password().str(), @@ -801,6 +814,7 @@ ActorOwn<> ConnectionCreator::prepare_connection( VLOG(connections) << "Create new direct connection " << debug_str; ConnectionData data; + data.ip_address = ip_address; data.socket_fd = std::move(socket_fd); data.stats_callback = std::move(stats_callback); promise.set_result(std::move(data)); @@ -933,9 +947,9 @@ void ConnectionCreator::client_loop(ClientInfo &client) { td::make_unique(client.is_media ? media_net_stats_callback_ : common_net_stats_callback_, actor_id(this), client.hash, extra.stat); auto token = next_token(); - auto ref = prepare_connection(std::move(socket_fd), proxy, extra.mtproto_ip_address, extra.transport_type, Slice(), - extra.debug_str, std::move(stats_callback), create_reference(token), true, - std::move(promise)); + auto ref = prepare_connection(extra.ip_address, std::move(socket_fd), proxy, extra.mtproto_ip_address, + extra.transport_type, Slice(), extra.debug_str, std::move(stats_callback), + create_reference(token), true, std::move(promise)); if (!ref.empty()) { children_[token] = {true, std::move(ref)}; } @@ -963,7 +977,7 @@ void ConnectionCreator::client_create_raw_connection(Result r_co debug_str](Result> result) mutable { if (result.is_ok()) { VLOG(connections) << "Ready connection (" << (check_mode ? "" : "un") << "checked) " << result.ok().get() << ' ' - << tag("rtt", format::as_time(result.ok()->rtt_)) << ' ' << debug_str; + << tag("rtt", format::as_time(result.ok()->extra().rtt)) << ' ' << debug_str; } else { VLOG(connections) << "Failed connection (" << (check_mode ? "" : "un") << "checked) " << result.error() << ' ' << debug_str; @@ -977,12 +991,13 @@ void ConnectionCreator::client_create_raw_connection(Result r_co } auto connection_data = r_connection_data.move_as_ok(); - auto raw_connection = make_unique( - std::move(connection_data.socket_fd), std::move(transport_type), std::move(connection_data.stats_callback)); + auto raw_connection = + mtproto::RawConnection::create(connection_data.ip_address, std::move(connection_data.socket_fd), + std::move(transport_type), std::move(connection_data.stats_callback)); raw_connection->set_connection_token(std::move(connection_data.connection_token)); - raw_connection->extra_ = network_generation; - raw_connection->debug_str_ = debug_str; + raw_connection->extra().extra = network_generation; + raw_connection->extra().debug_str = debug_str; if (check_mode) { VLOG(connections) << "Start check: " << debug_str << " " << (auth_data ? "with" : "without") << " auth data"; diff --git a/td/telegram/net/ConnectionCreator.h b/td/telegram/net/ConnectionCreator.h index 915d3e8be..8acbfc7d6 100644 --- a/td/telegram/net/ConnectionCreator.h +++ b/td/telegram/net/ConnectionCreator.h @@ -84,6 +84,7 @@ class ConnectionCreator : public NetQueryCallback { void ping_proxy(int32 proxy_id, Promise promise); struct ConnectionData { + IPAddress ip_address; SocketFd socket_fd; StateManager::ConnectionToken connection_token; unique_ptr stats_callback; @@ -91,7 +92,7 @@ class ConnectionCreator : public NetQueryCallback { static DcOptions get_default_dc_options(bool is_test); - static ActorOwn<> prepare_connection(SocketFd socket_fd, const Proxy &proxy, const IPAddress &mtproto_ip_address, + static ActorOwn<> prepare_connection(IPAddress ip_address, SocketFd socket_fd, const Proxy &proxy, const IPAddress &mtproto_ip_address, mtproto::TransportType transport_type, Slice actor_name_prefix, Slice debug_str, unique_ptr stats_callback, ActorShared<> parent, bool use_connection_token, @@ -232,6 +233,7 @@ class ConnectionCreator : public NetQueryCallback { DcOptionsSet::Stat *stat{nullptr}; mtproto::TransportType transport_type; string debug_str; + IPAddress ip_address; IPAddress mtproto_ip_address; bool check_mode{false}; }; @@ -246,7 +248,7 @@ class ConnectionCreator : public NetQueryCallback { void ping_proxy_resolved(int32 proxy_id, IPAddress ip_address, Promise promise); - void ping_proxy_socket_fd(SocketFd socket_fd, mtproto::TransportType transport_type, string debug_str, + void ping_proxy_socket_fd(IPAddress ip_address, SocketFd socket_fd, mtproto::TransportType transport_type, string debug_str, Promise promise); void on_ping_main_dc_result(uint64 token, Result result); diff --git a/td/telegram/net/Session.cpp b/td/telegram/net/Session.cpp index 1c62b7596..d039a5033 100644 --- a/td/telegram/net/Session.cpp +++ b/td/telegram/net/Session.cpp @@ -110,7 +110,7 @@ class GenAuthKeyActor : public Actor { auto raw_connection = r_raw_connection.move_as_ok(); VLOG(dc) << "Receive raw connection " << raw_connection.get(); - network_generation_ = raw_connection->extra_; + network_generation_ = raw_connection->extra().extra; child_ = create_actor_on_scheduler( PSLICE() << name_ + "::HandshakeActor", G()->get_slow_net_scheduler_id(), std::move(handshake_), std::move(raw_connection), std::move(context_), 10, std::move(connection_promise_), @@ -1052,7 +1052,7 @@ void Session::connection_open_finish(ConnectionInfo *info, auto raw_connection = r_raw_connection.move_as_ok(); VLOG(dc) << "Receive raw connection " << raw_connection.get(); - if (raw_connection->extra_ != network_generation_) { + if (raw_connection->extra().extra != network_generation_) { LOG(WARNING) << "Got RawConnection with old network_generation"; info->state = ConnectionInfo::State::Empty; yield(); @@ -1087,7 +1087,7 @@ void Session::connection_open_finish(ConnectionInfo *info, mode_name = Slice("HttpLongPoll"); } } - auto name = PSTRING() << get_name() << "::Connect::" << mode_name << "::" << raw_connection->debug_str_; + auto name = PSTRING() << get_name() << "::Connect::" << mode_name << "::" << raw_connection->extra().debug_str; LOG(INFO) << "Finished to open connection " << name; info->connection = make_unique(mode, std::move(raw_connection), &auth_data_); if (can_destroy_auth_key()) { diff --git a/tdnet/CMakeLists.txt b/tdnet/CMakeLists.txt index fb0319855..bc2b0f6ef 100644 --- a/tdnet/CMakeLists.txt +++ b/tdnet/CMakeLists.txt @@ -44,8 +44,20 @@ set(TDNET_SOURCE td/net/TcpListener.h td/net/TransparentProxy.h td/net/Wget.h + + td/net/DarwinHttp.mm + td/net/DarwinHttp.h ) +if (TD_EXPERIMENTAL_WATCH_OS) +set (TDNET_SOURCE + ${TDNET_SOURCE} + td/net/DarwinHttp.mm + td/net/DarwinHttp.h +) +set_source_files_properties(td/net/DarwinHttp.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) +endif() + #RULES #LIBRARIES @@ -66,6 +78,9 @@ if (WIN32) endif() endif() +find_library(FOUNDATION_LIBRARY Foundation REQUIRED) +target_link_libraries(tdnet PRIVATE ${FOUNDATION_LIBRARY}) + install(TARGETS tdnet EXPORT TdTargets LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" diff --git a/tdnet/td/net/DarwinHttp.h b/tdnet/td/net/DarwinHttp.h new file mode 100644 index 000000000..7dae980eb --- /dev/null +++ b/tdnet/td/net/DarwinHttp.h @@ -0,0 +1,13 @@ +#pragma once + +#include "td/actor/PromiseFuture.h" + +#include "td/utils/buffer.h" + +namespace td { +class DarwinHttp { + public: + static void get(CSlice url, Promise promise); + static void post(CSlice url, Slice data, Promise promise); +}; +} // namespace td diff --git a/tdnet/td/net/DarwinHttp.mm b/tdnet/td/net/DarwinHttp.mm new file mode 100644 index 000000000..df545661a --- /dev/null +++ b/tdnet/td/net/DarwinHttp.mm @@ -0,0 +1,57 @@ +#include "td/net/DarwinHttp.h" + +#import + +namespace td { +namespace { +NSString *to_ns_string(CSlice slice) { + return [NSString stringWithUTF8String:slice.c_str()]; +} + +NSData *to_ns_data(Slice data) { + return [NSData dataWithBytes:static_cast(data.data()) length:data.size()]; +} + +auto http_get(CSlice url) { + auto nsurl = [NSURL URLWithString:to_ns_string(url)]; + auto request = [NSURLRequest requestWithURL:nsurl]; + return request; +} + +auto http_post(CSlice url, Slice data) { + auto nsurl = [NSURL URLWithString:to_ns_string(url)]; + auto request = [NSMutableURLRequest requestWithURL:nsurl]; + [request setHTTPMethod:@"POST"]; + [request setHTTPBody:to_ns_data(data)]; + [request setValue:@"keep-alive" forHTTPHeaderField:@"Connection"]; + [request setValue:@"" forHTTPHeaderField:@"Host"]; + [request setValue:to_ns_string(PSLICE() << data.size()) forHTTPHeaderField:@"Content-Length"]; + [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + return request; +} + +void http_send(NSURLRequest *request, Promise promise) { + __block auto callback = std::move(promise); + NSURLSessionDataTask* dataTask = + [NSURLSession.sharedSession + dataTaskWithRequest:request + completionHandler: + ^(NSData *data, NSURLResponse *response, NSError *error) { + if(error == nil) { + callback(BufferSlice(Slice((const char *)([data bytes]), [data length]))); + } else { + callback(Status::Error(static_cast([error code]))); + } + }]; + [dataTask resume]; +} +} + +void DarwinHttp::get(CSlice url, Promise promise) { + return http_send(http_get(url), std::move(promise)); +} + +void DarwinHttp::post(CSlice url, Slice data, Promise promise) { + return http_send(http_post(url, data), std::move(promise)); +} +} diff --git a/tdutils/td/utils/config.h.in b/tdutils/td/utils/config.h.in index f8b89aeb5..a9fad9efe 100644 --- a/tdutils/td/utils/config.h.in +++ b/tdutils/td/utils/config.h.in @@ -6,3 +6,4 @@ #cmakedefine01 TD_HAVE_COROUTINES #cmakedefine01 TD_HAVE_ABSL #cmakedefine01 TD_FD_DEBUG +#cmakedefine01 TD_EXPERIMENTAL_WATCH_OS diff --git a/tdutils/td/utils/port/IPAddress.cpp b/tdutils/td/utils/port/IPAddress.cpp index aa7fe330a..7206190d2 100644 --- a/tdutils/td/utils/port/IPAddress.cpp +++ b/tdutils/td/utils/port/IPAddress.cpp @@ -499,6 +499,9 @@ Status IPAddress::init_sockaddr(sockaddr *addr, socklen_t len) { Status IPAddress::init_socket_address(const SocketFd &socket_fd) { is_valid_ = false; + if (socket_fd.empty()) { + return Status::Error("Socket is empty"); + } auto socket = socket_fd.get_native_fd().socket(); socklen_t len = storage_size(); int ret = getsockname(socket, &sockaddr_, &len); @@ -511,6 +514,9 @@ Status IPAddress::init_socket_address(const SocketFd &socket_fd) { Status IPAddress::init_peer_address(const SocketFd &socket_fd) { is_valid_ = false; + if (socket_fd.empty()) { + return Status::Error("Socket is empty"); + } auto socket = socket_fd.get_native_fd().socket(); socklen_t len = storage_size(); int ret = getpeername(socket, &sockaddr_, &len); diff --git a/tdutils/td/utils/port/SocketFd.cpp b/tdutils/td/utils/port/SocketFd.cpp index 248623381..a29070859 100644 --- a/tdutils/td/utils/port/SocketFd.cpp +++ b/tdutils/td/utils/port/SocketFd.cpp @@ -590,6 +590,10 @@ Result SocketFd::from_native_fd(NativeFd fd) { } Result SocketFd::open(const IPAddress &address) { +#if TD_EXPERIMENTAL_WATCH_OS + return SocketFd{}; +#endif + NativeFd native_fd{socket(address.get_address_family(), SOCK_STREAM, IPPROTO_TCP)}; if (!native_fd) { return OS_SOCKET_ERROR("Failed to create a socket"); diff --git a/test/http.cpp b/test/http.cpp index 1cc5de26a..6f20dd6ec 100644 --- a/test/http.cpp +++ b/test/http.cpp @@ -11,6 +11,8 @@ #include "td/net/HttpQuery.h" #include "td/net/HttpReader.h" +#include "td/net/DarwinHttp.h" + #include "td/utils/AesCtrByteFlow.h" #include "td/utils/algorithm.h" #include "td/utils/base64.h" @@ -38,6 +40,9 @@ #include #include +#include +#include + REGISTER_TESTS(http) using namespace td; @@ -462,3 +467,37 @@ TEST(Http, gzip_bomb_with_limit) { } ASSERT_TRUE(ok); } + +struct Baton { + std::mutex mutex; + std::condition_variable cond; + bool is_ready{false}; + + void wait() { + std::unique_lock lock(mutex); + cond.wait(lock, [&] { return is_ready; }); + } + + void post() { + { + std::unique_lock lock(mutex); + is_ready = true; + } + cond.notify_all(); + } + + void reset() { + is_ready = false; + } +}; + +TEST(Http, Darwin) { + Baton baton; + //LOG(ERROR) << "???"; + td::DarwinHttp::get("http://example.com", [&](td::BufferSlice data) { + LOG(ERROR) << data.as_slice(); + baton.post(); + }); + //LOG(ERROR) << "!!!"; + baton.wait(); +} diff --git a/test/mtproto.cpp b/test/mtproto.cpp index 812d31d9e..fa737567c 100644 --- a/test/mtproto.cpp +++ b/test/mtproto.cpp @@ -216,8 +216,8 @@ class TestPingActor : public Actor { } ping_connection_ = mtproto::PingConnection::create_req_pq( - make_unique( - r_socket.move_as_ok(), mtproto::TransportType{mtproto::TransportType::Tcp, 0, mtproto::ProxySecret()}, + mtproto::RawConnection::create( + ip_address_, r_socket.move_as_ok(), mtproto::TransportType{mtproto::TransportType::Tcp, 0, mtproto::ProxySecret()}, nullptr), 3); @@ -330,13 +330,15 @@ class HandshakeTestActor : public Actor { } void loop() override { if (!wait_for_raw_connection_ && !raw_connection_) { - auto r_socket = SocketFd::open(get_default_ip_address()); + auto ip_address = get_default_ip_address(); + auto r_socket = SocketFd::open(ip_address); if (r_socket.is_error()) { finish(Status::Error(PSTRING() << "Failed to open socket: " << r_socket.error())); return stop(); } - raw_connection_ = make_unique( + raw_connection_ = mtproto::RawConnection::create( + ip_address, r_socket.move_as_ok(), mtproto::TransportType{mtproto::TransportType::Tcp, 0, mtproto::ProxySecret()}, nullptr); } @@ -535,13 +537,15 @@ class FastPingTestActor : public Actor { void start_up() override { // Run handshake to create key and salt - auto r_socket = SocketFd::open(get_default_ip_address()); + auto ip_address = get_default_ip_address(); + auto r_socket = SocketFd::open(ip_address); if (r_socket.is_error()) { *result_ = Status::Error(PSTRING() << "Failed to open socket: " << r_socket.error()); return stop(); } - auto raw_connection = make_unique( + auto raw_connection = mtproto::RawConnection::create( + ip_address, r_socket.move_as_ok(), mtproto::TransportType{mtproto::TransportType::Tcp, 0, mtproto::ProxySecret()}, nullptr); auto handshake = make_unique(get_default_dc_id(), 60 * 100 /*temp*/); create_actor( @@ -581,8 +585,8 @@ class FastPingTestActor : public Actor { return stop(); } connection_ = r_connection.move_as_ok(); - LOG(INFO) << "RTT: " << connection_->rtt_; - connection_->rtt_ = 0; + LOG(INFO) << "RTT: " << connection_->extra().rtt; + connection_->extra().rtt = 0; loop(); } From 258b6dd3bd50e965bade4150d76ed0c9631f6ca1 Mon Sep 17 00:00:00 2001 From: Arseny Smirnov Date: Fri, 26 Mar 2021 18:09:13 +0300 Subject: [PATCH 117/281] use TD_EXPERIMENTAL_WATCH_OS=ON in example/ios --- example/ios/build.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/example/ios/build.sh b/example/ios/build.sh index 5b4ad9895..34bfe58ea 100755 --- a/example/ios/build.sh +++ b/example/ios/build.sh @@ -46,8 +46,10 @@ do else ios_platform="OS" fi + watchos="" if [[ $platform = "watchOS" ]]; then ios_platform="WATCH${ios_platform}" + watchos="-DTD_EXPERIMENTAL_WATCH_OS=ON" fi if [[ $platform = "tvOS" ]]; then ios_platform="TV${ios_platform}" @@ -57,7 +59,7 @@ do mkdir -p $build mkdir -p $install cd $build - cmake $td_path $options -DIOS_PLATFORM=${ios_platform} -DCMAKE_TOOLCHAIN_FILE=${td_path}/CMake/iOS.cmake -DCMAKE_INSTALL_PREFIX=../${install} + cmake $td_path $options $watchos -DIOS_PLATFORM=${ios_platform} -DCMAKE_TOOLCHAIN_FILE=${td_path}/CMake/iOS.cmake -DCMAKE_INSTALL_PREFIX=../${install} make -j3 install || exit cd .. done From 26dc0ad9300a0fc30197d1d88e91f5e4e0cc128c Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 26 Mar 2021 18:15:21 +0300 Subject: [PATCH 118/281] Update layer to 127. --- td/generate/scheme/telegram_api.tl | 34 ++++++----- td/telegram/ContactsManager.cpp | 2 +- td/telegram/GroupCallManager.cpp | 3 +- td/telegram/MessageContent.cpp | 8 ++- td/telegram/MessagesManager.cpp | 10 ++-- td/telegram/Payments.cpp | 94 ++++++++++++++++++++++-------- td/telegram/Payments.h | 16 +++-- td/telegram/Photo.cpp | 2 +- td/telegram/UpdatesManager.cpp | 1 + td/telegram/Version.h | 2 +- 10 files changed, 118 insertions(+), 54 deletions(-) diff --git a/td/generate/scheme/telegram_api.tl b/td/generate/scheme/telegram_api.tl index 03a50c28f..62919c288 100644 --- a/td/generate/scheme/telegram_api.tl +++ b/td/generate/scheme/telegram_api.tl @@ -55,7 +55,7 @@ inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string pro inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; -inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; +inputMediaInvoice#d9799874 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:flags.1?string = InputMedia; inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector solution:flags.1?string solution_entities:flags.1?Vector = InputMedia; inputMediaDice#e66fbf7b emoticon:string = InputMedia; @@ -100,7 +100,7 @@ userEmpty#200250ba id:int = User; user#938458c1 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#69d3ab26 flags:# has_video:flags.0?true photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto; +userProfilePhoto#cc656077 flags:# has_video:flags.0?true photo_id:long photo_small:FileLocation photo_big:FileLocation stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; @@ -126,7 +126,7 @@ chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0? chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#d20b9f3c flags:# has_video:flags.0?true photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto; +chatPhoto#4790ee05 flags:# has_video:flags.0?true photo_small:FileLocation photo_big:FileLocation stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; message#bce383d2 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true id:int from_id:flags.8?Peer peer_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector ttl_period:flags.25?int = Message; @@ -173,6 +173,7 @@ messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction; messageActionInviteToGroupCall#76b9f11a call:InputGroupCall users:Vector = MessageAction; messageActionSetMessagesTTL#aa1afbfd period:int = MessageAction; +messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; dialog#2c171f72 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; @@ -541,7 +542,7 @@ inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; -stickerSet#40e237a8 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int count:int hash:int = StickerSet; +stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; @@ -635,6 +636,7 @@ inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:f inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; +inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; @@ -646,6 +648,7 @@ botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string ent botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; +botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; @@ -779,7 +782,7 @@ dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; -invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector = Invoice; +invoice#cd886e0 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; @@ -799,14 +802,14 @@ inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; -payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; +payments.paymentForm#8d0b2415 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; -payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; +payments.paymentReceipt#10b555d0 flags:# date:int bot_id:int provider_id:int title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; @@ -1190,11 +1193,11 @@ peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats; groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#c0c2052e flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true id:long access_hash:long participants_count:int params:flags.0?DataJSON title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int version:int = GroupCall; +groupCall#c95c6654 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true id:long access_hash:long participants_count:int params:flags.0?DataJSON title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int version:int = GroupCall; inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; -groupCallParticipant#19adba89 flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long = GroupCallParticipant; +groupCallParticipant#b96b25ee flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long params:flags.6?DataJSON = GroupCallParticipant; phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; @@ -1579,10 +1582,10 @@ bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; bots.setBotCommands#805d46f6 commands:Vector = Bool; -payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; -payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; -payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; -payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; +payments.getPaymentForm#8a333c8d flags:# peer:InputPeer msg_id:int theme_params:flags.0?DataJSON = payments.PaymentForm; +payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; +payments.validateRequestedInfo#db103170 flags:# save:flags.0?true peer:InputPeer msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; +payments.sendPaymentForm#30c3bc9d flags:# form_id:long peer:InputPeer msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; payments.getBankCardData#2e79d779 number:string = payments.BankCardData; @@ -1602,7 +1605,7 @@ phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall durati phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; -phone.createGroupCall#bd3dabe0 peer:InputPeer random_id:int = Updates; +phone.createGroupCall#48cdc6d8 flags:# peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates; phone.joinGroupCall#b132ff7b flags:# muted:flags.0?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string params:DataJSON = Updates; phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; @@ -1616,6 +1619,9 @@ phone.editGroupCallParticipant#d975eb80 flags:# muted:flags.0?true call:InputGro phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; +phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates; +phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates; +phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool; langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 43caa5323..a1299992d 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -8459,7 +8459,7 @@ ContactsManager::User *ContactsManager::get_user_force(UserId user_id) { profile_photo_local_id), telegram_api::make_object(profile_photo_volume_id, profile_photo_local_id + 2), - profile_photo_dc_id); + BufferSlice(), profile_photo_dc_id); } auto user = telegram_api::make_object( diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 745c7515c..d5f4857dd 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -137,8 +137,9 @@ class CreateGroupCallQuery : public Td::ResultHandler { auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); CHECK(input_peer != nullptr); + int32 flags = 0; send_query(G()->net_query_creator().create( - telegram_api::phone_createGroupCall(std::move(input_peer), Random::secure_int32()))); + telegram_api::phone_createGroupCall(flags, std::move(input_peer), Random::secure_int32(), string(), 0))); } void on_result(uint64 id, BufferSlice packet) override { diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 0cd8f6c87..0321e53e3 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -2301,7 +2301,7 @@ static tl_object_ptr get_input_invoice(const Invoice &inv }); return make_tl_object( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, - false /*ignored*/, false /*ignored*/, false /*ignored*/, invoice.currency, std::move(prices)); + false /*ignored*/, false /*ignored*/, false /*ignored*/, invoice.currency, std::move(prices), 0, vector()); } static tl_object_ptr get_input_web_document(const FileManager *file_manager, @@ -2332,7 +2332,7 @@ static tl_object_ptr get_input_web_document(cons static tl_object_ptr get_input_media_invoice(const FileManager *file_manager, const MessageInvoice *message_invoice) { CHECK(message_invoice != nullptr); - int32 flags = 0; + int32 flags = telegram_api::inputMediaInvoice::START_PARAM_MASK; auto input_web_document = get_input_web_document(file_manager, message_invoice->photo); if (input_web_document != nullptr) { flags |= telegram_api::inputMediaInvoice::PHOTO_MASK; @@ -4653,6 +4653,10 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr(set_messages_ttl->period_); } + case telegram_api::messageActionGroupCallScheduled::ID: { + auto scheduled_group_call = move_tl_object_as(action); + break; + } default: UNREACHABLE(); } diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 9bac60842..64ba102d7 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -37374,7 +37374,7 @@ void MessagesManager::get_payment_form(FullMessageId full_message_id, return promise.set_error(r_message_id.move_as_error()); } - ::td::get_payment_form(r_message_id.ok(), std::move(promise)); + ::td::get_payment_form(full_message_id.get_dialog_id(), r_message_id.ok(), std::move(promise)); } void MessagesManager::validate_order_info(FullMessageId full_message_id, tl_object_ptr order_info, @@ -37385,7 +37385,8 @@ void MessagesManager::validate_order_info(FullMessageId full_message_id, tl_obje return promise.set_error(r_message_id.move_as_error()); } - ::td::validate_order_info(r_message_id.ok(), std::move(order_info), allow_save, std::move(promise)); + ::td::validate_order_info(full_message_id.get_dialog_id(), r_message_id.ok(), std::move(order_info), allow_save, + std::move(promise)); } void MessagesManager::send_payment_form(FullMessageId full_message_id, const string &order_info_id, @@ -37397,7 +37398,8 @@ void MessagesManager::send_payment_form(FullMessageId full_message_id, const str return promise.set_error(r_message_id.move_as_error()); } - ::td::send_payment_form(r_message_id.ok(), order_info_id, shipping_option_id, credentials, std::move(promise)); + ::td::send_payment_form(full_message_id.get_dialog_id(), r_message_id.ok(), order_info_id, shipping_option_id, + credentials, std::move(promise)); } void MessagesManager::get_payment_receipt(FullMessageId full_message_id, @@ -37416,7 +37418,7 @@ void MessagesManager::get_payment_receipt(FullMessageId full_message_id, return promise.set_error(Status::Error(5, "Wrong message identifier")); } - ::td::get_payment_receipt(m->message_id.get_server_message_id(), std::move(promise)); + ::td::get_payment_receipt(full_message_id.get_dialog_id(), m->message_id.get_server_message_id(), std::move(promise)); } void MessagesManager::remove_sponsored_dialog() { diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 22ebb11e3..08142dc44 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -6,14 +6,14 @@ // #include "td/telegram/Payments.h" -#include "td/telegram/td_api.h" -#include "td/telegram/telegram_api.h" - #include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" +#include "td/telegram/MessagesManager.h" #include "td/telegram/misc.h" #include "td/telegram/PasswordManager.h" #include "td/telegram/Td.h" +#include "td/telegram/td_api.h" +#include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" #include "td/utils/algorithm.h" @@ -255,13 +255,22 @@ static tl_object_ptr convert_saved_credentials( class GetPaymentFormQuery : public Td::ResultHandler { Promise> promise_; + DialogId dialog_id_; public: explicit GetPaymentFormQuery(Promise> &&promise) : promise_(std::move(promise)) { } - void send(ServerMessageId server_message_id) { - send_query(G()->net_query_creator().create(telegram_api::payments_getPaymentForm(server_message_id.get()))); + void send(DialogId dialog_id, ServerMessageId server_message_id) { + dialog_id_ = dialog_id; + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + if (input_peer == nullptr) { + return on_error(0, Status::Error(400, "Can't access the chat")); + } + + int32 flags = 0; + send_query(G()->net_query_creator().create( + telegram_api::payments_getPaymentForm(flags, std::move(input_peer), server_message_id.get(), nullptr))); } void on_result(uint64 id, BufferSlice packet) override { @@ -286,20 +295,28 @@ class GetPaymentFormQuery : public Td::ResultHandler { } void on_error(uint64 id, Status status) override { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetPaymentFormQuery"); promise_.set_error(std::move(status)); } }; class ValidateRequestedInfoQuery : public Td::ResultHandler { Promise> promise_; + DialogId dialog_id_; public: explicit ValidateRequestedInfoQuery(Promise> &&promise) : promise_(std::move(promise)) { } - void send(ServerMessageId server_message_id, tl_object_ptr requested_info, - bool allow_save) { + void send(DialogId dialog_id, ServerMessageId server_message_id, + tl_object_ptr requested_info, bool allow_save) { + dialog_id_ = dialog_id; + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + if (input_peer == nullptr) { + return on_error(0, Status::Error(400, "Can't access the chat")); + } + int32 flags = 0; if (allow_save) { flags |= telegram_api::payments_validateRequestedInfo::SAVE_MASK; @@ -309,7 +326,7 @@ class ValidateRequestedInfoQuery : public Td::ResultHandler { requested_info->flags_ = 0; } send_query(G()->net_query_creator().create(telegram_api::payments_validateRequestedInfo( - flags, false /*ignored*/, server_message_id.get(), std::move(requested_info)))); + flags, false /*ignored*/, std::move(input_peer), server_message_id.get(), std::move(requested_info)))); } void on_result(uint64 id, BufferSlice packet) override { @@ -327,21 +344,30 @@ class ValidateRequestedInfoQuery : public Td::ResultHandler { } void on_error(uint64 id, Status status) override { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "ValidateRequestedInfoQuery"); promise_.set_error(std::move(status)); } }; class SendPaymentFormQuery : public Td::ResultHandler { Promise> promise_; + DialogId dialog_id_; public: explicit SendPaymentFormQuery(Promise> &&promise) : promise_(std::move(promise)) { } - void send(ServerMessageId server_message_id, const string &order_info_id, const string &shipping_option_id, - tl_object_ptr input_credentials) { + void send(DialogId dialog_id, ServerMessageId server_message_id, const string &order_info_id, + const string &shipping_option_id, tl_object_ptr input_credentials) { CHECK(input_credentials != nullptr); + + dialog_id_ = dialog_id; + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + if (input_peer == nullptr) { + return on_error(0, Status::Error(400, "Can't access the chat")); + } + int32 flags = 0; if (!order_info_id.empty()) { flags |= telegram_api::payments_sendPaymentForm::REQUESTED_INFO_ID_MASK; @@ -349,8 +375,9 @@ class SendPaymentFormQuery : public Td::ResultHandler { if (!shipping_option_id.empty()) { flags |= telegram_api::payments_sendPaymentForm::SHIPPING_OPTION_ID_MASK; } - send_query(G()->net_query_creator().create(telegram_api::payments_sendPaymentForm( - flags, server_message_id.get(), order_info_id, shipping_option_id, std::move(input_credentials)))); + send_query(G()->net_query_creator().create( + telegram_api::payments_sendPaymentForm(flags, 0, std::move(input_peer), server_message_id.get(), order_info_id, + shipping_option_id, std::move(input_credentials), 0))); } void on_result(uint64 id, BufferSlice packet) override { @@ -382,20 +409,29 @@ class SendPaymentFormQuery : public Td::ResultHandler { } void on_error(uint64 id, Status status) override { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendPaymentFormQuery"); promise_.set_error(std::move(status)); } }; class GetPaymentReceiptQuery : public Td::ResultHandler { Promise> promise_; + DialogId dialog_id_; public: explicit GetPaymentReceiptQuery(Promise> &&promise) : promise_(std::move(promise)) { } - void send(ServerMessageId server_message_id) { - send_query(G()->net_query_creator().create(telegram_api::payments_getPaymentReceipt(server_message_id.get()))); + void send(DialogId dialog_id, ServerMessageId server_message_id) { + dialog_id_ = dialog_id; + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + if (input_peer == nullptr) { + return on_error(0, Status::Error(400, "Can't access the chat")); + } + + send_query(G()->net_query_creator().create( + telegram_api::payments_getPaymentReceipt(std::move(input_peer), server_message_id.get()))); } void on_result(uint64 id, BufferSlice packet) override { @@ -423,6 +459,7 @@ class GetPaymentReceiptQuery : public Td::ResultHandler { } void on_error(uint64 id, Status status) override { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetPaymentReceiptQuery"); promise_.set_error(std::move(status)); } }; @@ -785,12 +822,17 @@ void answer_pre_checkout_query(int64 pre_checkout_query_id, const string &error_ ->send(pre_checkout_query_id, error_message); } -void get_payment_form(ServerMessageId server_message_id, Promise> &&promise) { - G()->td().get_actor_unsafe()->create_handler(std::move(promise))->send(server_message_id); +void get_payment_form(DialogId dialog_id, ServerMessageId server_message_id, + Promise> &&promise) { + G()->td() + .get_actor_unsafe() + ->create_handler(std::move(promise)) + ->send(dialog_id, server_message_id); } -void validate_order_info(ServerMessageId server_message_id, tl_object_ptr order_info, - bool allow_save, Promise> &&promise) { +void validate_order_info(DialogId dialog_id, ServerMessageId server_message_id, + tl_object_ptr order_info, bool allow_save, + Promise> &&promise) { if (order_info != nullptr) { if (!clean_input_string(order_info->name_)) { return promise.set_error(Status::Error(400, "Name must be encoded in UTF-8")); @@ -826,11 +868,11 @@ void validate_order_info(ServerMessageId server_message_id, tl_object_ptrtd() .get_actor_unsafe() ->create_handler(std::move(promise)) - ->send(server_message_id, convert_order_info(std::move(order_info)), allow_save); + ->send(dialog_id, server_message_id, convert_order_info(std::move(order_info)), allow_save); } -void send_payment_form(ServerMessageId server_message_id, const string &order_info_id, const string &shipping_option_id, - const tl_object_ptr &credentials, +void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, const string &order_info_id, + const string &shipping_option_id, const tl_object_ptr &credentials, Promise> &&promise) { CHECK(credentials != nullptr); @@ -882,11 +924,15 @@ void send_payment_form(ServerMessageId server_message_id, const string &order_in G()->td() .get_actor_unsafe() ->create_handler(std::move(promise)) - ->send(server_message_id, order_info_id, shipping_option_id, std::move(input_credentials)); + ->send(dialog_id, server_message_id, order_info_id, shipping_option_id, std::move(input_credentials)); } -void get_payment_receipt(ServerMessageId server_message_id, Promise> &&promise) { - G()->td().get_actor_unsafe()->create_handler(std::move(promise))->send(server_message_id); +void get_payment_receipt(DialogId dialog_id, ServerMessageId server_message_id, + Promise> &&promise) { + G()->td() + .get_actor_unsafe() + ->create_handler(std::move(promise)) + ->send(dialog_id, server_message_id); } void get_saved_order_info(Promise> &&promise) { diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index 5287e0e7b..ab30e4d16 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -8,6 +8,7 @@ #include "td/actor/PromiseFuture.h" +#include "td/telegram/DialogId.h" #include "td/telegram/Photo.h" #include "td/telegram/ServerMessageId.h" @@ -137,16 +138,19 @@ void answer_shipping_query(int64 shipping_query_id, vector &&promise); -void get_payment_form(ServerMessageId server_message_id, Promise> &&promise); +void get_payment_form(DialogId dialog_id, ServerMessageId server_message_id, + Promise> &&promise); -void validate_order_info(ServerMessageId server_message_id, tl_object_ptr order_info, - bool allow_save, Promise> &&promise); +void validate_order_info(DialogId dialog_id, ServerMessageId server_message_id, + tl_object_ptr order_info, bool allow_save, + Promise> &&promise); -void send_payment_form(ServerMessageId server_message_id, const string &order_info_id, const string &shipping_option_id, - const tl_object_ptr &credentials, +void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, const string &order_info_id, + const string &shipping_option_id, const tl_object_ptr &credentials, Promise> &&promise); -void get_payment_receipt(ServerMessageId server_message_id, Promise> &&promise); +void get_payment_receipt(DialogId dialog_id, ServerMessageId server_message_id, + Promise> &&promise); void get_saved_order_info(Promise> &&promise); diff --git a/td/telegram/Photo.cpp b/td/telegram/Photo.cpp index 2fa58f8bf..6e8114441 100644 --- a/td/telegram/Photo.cpp +++ b/td/telegram/Photo.cpp @@ -992,7 +992,7 @@ tl_object_ptr convert_photo_to_profile_photo( flags |= telegram_api::userProfilePhoto::HAS_VIDEO_MASK; } return make_tl_object(flags, false /*ignored*/, photo->id_, std::move(photo_small), - std::move(photo_big), photo->dc_id_); + std::move(photo_big), BufferSlice(), photo->dc_id_); } } // namespace td diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index 3ca0835ed..e28158047 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -623,6 +623,7 @@ bool UpdatesManager::is_acceptable_message(const telegram_api::Message *message_ case telegram_api::messageActionSecureValuesSentMe::ID: case telegram_api::messageActionContactSignUp::ID: case telegram_api::messageActionGroupCall::ID: + case telegram_api::messageActionGroupCallScheduled::ID: case telegram_api::messageActionSetMessagesTTL::ID: break; case telegram_api::messageActionChatCreate::ID: { diff --git a/td/telegram/Version.h b/td/telegram/Version.h index d9f28e617..a523cd6cc 100644 --- a/td/telegram/Version.h +++ b/td/telegram/Version.h @@ -8,7 +8,7 @@ namespace td { -constexpr int32 MTPROTO_LAYER = 126; +constexpr int32 MTPROTO_LAYER = 127; enum class Version : int32 { Initial, // 0 From 66de95d93c48daee2d9656daba195ce250fcc564 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 26 Mar 2021 18:52:45 +0300 Subject: [PATCH 119/281] Fix compilation errors and formatting. --- td/mtproto/RawConnection.cpp | 8 ++++---- td/mtproto/Transport.h | 2 +- td/telegram/Td.cpp | 3 ++- td/telegram/net/ConnectionCreator.h | 9 +++++---- tdnet/CMakeLists.txt | 21 ++++++++++----------- tdnet/td/net/DarwinHttp.h | 9 +++++++++ tdnet/td/net/DarwinHttp.mm | 12 ++++++++++-- test/http.cpp | 8 ++++++-- test/mtproto.cpp | 15 +++++++-------- 9 files changed, 54 insertions(+), 33 deletions(-) diff --git a/td/mtproto/RawConnection.cpp b/td/mtproto/RawConnection.cpp index 6cefa1faf..0c5976564 100644 --- a/td/mtproto/RawConnection.cpp +++ b/td/mtproto/RawConnection.cpp @@ -9,16 +9,16 @@ #include "td/mtproto/AuthKey.h" #include "td/mtproto/Transport.h" +#if TD_EXPERIMENTAL_WATCH_OS +#include "td/net/DarwinHttp.h" +#endif + #include "td/utils/format.h" #include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/Status.h" #include "td/utils/StorerBase.h" -#if TD_EXPERIMENTAL_WATCH_OS -#include "td/net/DarwinHttp.h" -#endif - #include namespace td { diff --git a/td/mtproto/Transport.h b/td/mtproto/Transport.h index 57eea1a62..957d90055 100644 --- a/td/mtproto/Transport.h +++ b/td/mtproto/Transport.h @@ -92,11 +92,11 @@ class Transport { MutableSlice dest = MutableSlice()); static std::pair calc_message_key2(const AuthKey &auth_key, int X, Slice to_encrypt); + private: template static std::pair calc_message_ack_and_key(const HeaderT &head, size_t data_size); - template static size_t calc_crypto_size(size_t data_size); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 98bb4c44b..b82cc15c8 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -613,7 +613,8 @@ class TestProxyRequest : public RequestOnceActor { }; auto handshake = make_unique(dc_id_, 3600); auto data = r_data.move_as_ok(); - auto raw_connection = mtproto::RawConnection::create(data.ip_address, std::move(data.socket_fd), get_transport(), nullptr); + auto raw_connection = + mtproto::RawConnection::create(data.ip_address, std::move(data.socket_fd), get_transport(), nullptr); child_ = create_actor( "HandshakeActor", std::move(handshake), std::move(raw_connection), make_unique(), 10.0, PromiseCreator::lambda([actor_id = actor_id(this)](Result> raw_connection) { diff --git a/td/telegram/net/ConnectionCreator.h b/td/telegram/net/ConnectionCreator.h index 8acbfc7d6..633f31a68 100644 --- a/td/telegram/net/ConnectionCreator.h +++ b/td/telegram/net/ConnectionCreator.h @@ -92,8 +92,9 @@ class ConnectionCreator : public NetQueryCallback { static DcOptions get_default_dc_options(bool is_test); - static ActorOwn<> prepare_connection(IPAddress ip_address, SocketFd socket_fd, const Proxy &proxy, const IPAddress &mtproto_ip_address, - mtproto::TransportType transport_type, Slice actor_name_prefix, Slice debug_str, + static ActorOwn<> prepare_connection(IPAddress ip_address, SocketFd socket_fd, const Proxy &proxy, + const IPAddress &mtproto_ip_address, mtproto::TransportType transport_type, + Slice actor_name_prefix, Slice debug_str, unique_ptr stats_callback, ActorShared<> parent, bool use_connection_token, Promise promise); @@ -248,8 +249,8 @@ class ConnectionCreator : public NetQueryCallback { void ping_proxy_resolved(int32 proxy_id, IPAddress ip_address, Promise promise); - void ping_proxy_socket_fd(IPAddress ip_address, SocketFd socket_fd, mtproto::TransportType transport_type, string debug_str, - Promise promise); + void ping_proxy_socket_fd(IPAddress ip_address, SocketFd socket_fd, mtproto::TransportType transport_type, + string debug_str, Promise promise); void on_ping_main_dc_result(uint64 token, Result result); }; diff --git a/tdnet/CMakeLists.txt b/tdnet/CMakeLists.txt index bc2b0f6ef..b613cfe34 100644 --- a/tdnet/CMakeLists.txt +++ b/tdnet/CMakeLists.txt @@ -44,18 +44,15 @@ set(TDNET_SOURCE td/net/TcpListener.h td/net/TransparentProxy.h td/net/Wget.h - - td/net/DarwinHttp.mm - td/net/DarwinHttp.h ) if (TD_EXPERIMENTAL_WATCH_OS) -set (TDNET_SOURCE - ${TDNET_SOURCE} - td/net/DarwinHttp.mm - td/net/DarwinHttp.h -) -set_source_files_properties(td/net/DarwinHttp.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + set (TDNET_SOURCE + ${TDNET_SOURCE} + td/net/DarwinHttp.mm + td/net/DarwinHttp.h + ) + set_source_files_properties(td/net/DarwinHttp.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) endif() #RULES @@ -78,8 +75,10 @@ if (WIN32) endif() endif() -find_library(FOUNDATION_LIBRARY Foundation REQUIRED) -target_link_libraries(tdnet PRIVATE ${FOUNDATION_LIBRARY}) +if (TD_EXPERIMENTAL_WATCH_OS) + find_library(FOUNDATION_LIBRARY Foundation REQUIRED) + target_link_libraries(tdnet PRIVATE ${FOUNDATION_LIBRARY}) +endif() install(TARGETS tdnet EXPORT TdTargets LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" diff --git a/tdnet/td/net/DarwinHttp.h b/tdnet/td/net/DarwinHttp.h index 7dae980eb..cea215e89 100644 --- a/tdnet/td/net/DarwinHttp.h +++ b/tdnet/td/net/DarwinHttp.h @@ -1,13 +1,22 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// #pragma once #include "td/actor/PromiseFuture.h" #include "td/utils/buffer.h" +#include "td/utils/Slice.h" namespace td { + class DarwinHttp { public: static void get(CSlice url, Promise promise); static void post(CSlice url, Slice data, Promise promise); }; + } // namespace td diff --git a/tdnet/td/net/DarwinHttp.mm b/tdnet/td/net/DarwinHttp.mm index df545661a..11a491db3 100644 --- a/tdnet/td/net/DarwinHttp.mm +++ b/tdnet/td/net/DarwinHttp.mm @@ -1,8 +1,15 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// #include "td/net/DarwinHttp.h" #import namespace td { + namespace { NSString *to_ns_string(CSlice slice) { return [NSString stringWithUTF8String:slice.c_str()]; @@ -45,7 +52,7 @@ void http_send(NSURLRequest *request, Promise promise) { }]; [dataTask resume]; } -} +} // namespace void DarwinHttp::get(CSlice url, Promise promise) { return http_send(http_get(url), std::move(promise)); @@ -54,4 +61,5 @@ void DarwinHttp::get(CSlice url, Promise promise) { void DarwinHttp::post(CSlice url, Slice data, Promise promise) { return http_send(http_post(url, data), std::move(promise)); } -} + +} // namespace td diff --git a/test/http.cpp b/test/http.cpp index 6f20dd6ec..34fbd79c6 100644 --- a/test/http.cpp +++ b/test/http.cpp @@ -6,13 +6,15 @@ // #include "data.h" +#if TD_EXPERIMENTAL_WATCH_OS +#include "td/net/DarwinHttp.h" +#endif + #include "td/net/HttpChunkedByteFlow.h" #include "td/net/HttpHeaderCreator.h" #include "td/net/HttpQuery.h" #include "td/net/HttpReader.h" -#include "td/net/DarwinHttp.h" - #include "td/utils/AesCtrByteFlow.h" #include "td/utils/algorithm.h" #include "td/utils/base64.h" @@ -468,6 +470,7 @@ TEST(Http, gzip_bomb_with_limit) { ASSERT_TRUE(ok); } +#if TD_EXPERIMENTAL_WATCH_OS struct Baton { std::mutex mutex; std::condition_variable cond; @@ -501,3 +504,4 @@ TEST(Http, Darwin) { //LOG(ERROR) << "!!!"; baton.wait(); } +#endif diff --git a/test/mtproto.cpp b/test/mtproto.cpp index fa737567c..05b0aa252 100644 --- a/test/mtproto.cpp +++ b/test/mtproto.cpp @@ -216,9 +216,9 @@ class TestPingActor : public Actor { } ping_connection_ = mtproto::PingConnection::create_req_pq( - mtproto::RawConnection::create( - ip_address_, r_socket.move_as_ok(), mtproto::TransportType{mtproto::TransportType::Tcp, 0, mtproto::ProxySecret()}, - nullptr), + mtproto::RawConnection::create(ip_address_, r_socket.move_as_ok(), + mtproto::TransportType{mtproto::TransportType::Tcp, 0, mtproto::ProxySecret()}, + nullptr), 3); Scheduler::subscribe(ping_connection_->get_poll_info().extract_pollable_fd(this)); @@ -338,9 +338,8 @@ class HandshakeTestActor : public Actor { } raw_connection_ = mtproto::RawConnection::create( - ip_address, - r_socket.move_as_ok(), mtproto::TransportType{mtproto::TransportType::Tcp, 0, mtproto::ProxySecret()}, - nullptr); + ip_address, r_socket.move_as_ok(), + mtproto::TransportType{mtproto::TransportType::Tcp, 0, mtproto::ProxySecret()}, nullptr); } if (!wait_for_handshake_ && !handshake_) { handshake_ = make_unique(dc_id_, 3600); @@ -545,8 +544,8 @@ class FastPingTestActor : public Actor { } auto raw_connection = mtproto::RawConnection::create( - ip_address, - r_socket.move_as_ok(), mtproto::TransportType{mtproto::TransportType::Tcp, 0, mtproto::ProxySecret()}, nullptr); + ip_address, r_socket.move_as_ok(), + mtproto::TransportType{mtproto::TransportType::Tcp, 0, mtproto::ProxySecret()}, nullptr); auto handshake = make_unique(get_default_dc_id(), 60 * 100 /*temp*/); create_actor( "HandshakeActor", std::move(handshake), std::move(raw_connection), make_unique(), 10.0, From b84318fed439713fb17be84a79b6bd652b14089d Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 27 Mar 2021 05:19:22 +0300 Subject: [PATCH 120/281] Minor improvements. --- .gitattributes | 4 ++-- td/generate/tl-parser/CMakeLists.txt | 2 +- td/mtproto/RawConnection.cpp | 13 ++++++++++--- td/mtproto/RawConnection.h | 17 +++++++++-------- td/telegram/GroupCallManager.h | 1 + td/telegram/GroupCallParticipant.cpp | 2 ++ td/telegram/MessagesManager.cpp | 4 ++-- td/telegram/Td.cpp | 12 ++++++------ td/telegram/net/ConnectionCreator.cpp | 15 ++++++++------- tdnet/CMakeLists.txt | 2 +- tdnet/td/net/DarwinHttp.mm | 14 ++++++++------ test/http.cpp | 4 ++-- 12 files changed, 52 insertions(+), 38 deletions(-) diff --git a/.gitattributes b/.gitattributes index 2d04f9b7e..06e5328a4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,6 +5,7 @@ *.h text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.c text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.tl text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent +*.mm text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.txt text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.sh text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent eol=lf *.php text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent @@ -18,6 +19,7 @@ *.java text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.py text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.js text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent +*.patch text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.swift text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.pbxproj text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent *.cs text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent @@ -32,7 +34,5 @@ sqlite/sqlite/* linguist-vendored -*.tlo binary - *.pfx binary *.png binary diff --git a/td/generate/tl-parser/CMakeLists.txt b/td/generate/tl-parser/CMakeLists.txt index 251eb2b39..442ce674a 100644 --- a/td/generate/tl-parser/CMakeLists.txt +++ b/td/generate/tl-parser/CMakeLists.txt @@ -15,5 +15,5 @@ endif() add_executable(${PROJECT_NAME} ${SOURCES}) if (NOT WIN32) - target_link_libraries(${PROJECT_NAME} m) + target_link_libraries(${PROJECT_NAME} PRIVATE m) endif() diff --git a/td/mtproto/RawConnection.cpp b/td/mtproto/RawConnection.cpp index 0c5976564..3aa77ef81 100644 --- a/td/mtproto/RawConnection.cpp +++ b/td/mtproto/RawConnection.cpp @@ -7,18 +7,26 @@ #include "td/mtproto/RawConnection.h" #include "td/mtproto/AuthKey.h" +#include "td/mtproto/IStreamTransport.h" +#include "td/mtproto/ProxySecret.h" #include "td/mtproto/Transport.h" #if TD_EXPERIMENTAL_WATCH_OS #include "td/net/DarwinHttp.h" #endif +#include "td/utils/BufferedFd.h" #include "td/utils/format.h" #include "td/utils/logging.h" #include "td/utils/misc.h" +#include "td/utils/MpscPollableQueue.h" +#include "td/utils/port/EventFd.h" +#include "td/utils/Slice.h" #include "td/utils/Status.h" #include "td/utils/StorerBase.h" +#include +#include #include namespace td { @@ -441,9 +449,8 @@ class RawConnectionHttp : public RawConnection { }; #endif -td::unique_ptr RawConnection::create(IPAddress ip_address, SocketFd socket_fd, - TransportType transport_type, - unique_ptr stats_callback) { +unique_ptr RawConnection::create(IPAddress ip_address, SocketFd socket_fd, TransportType transport_type, + unique_ptr stats_callback) { #if TD_EXPERIMENTAL_WATCH_OS return td::make_unique(ip_address, std::move(stats_callback)); #else diff --git a/td/mtproto/RawConnection.h b/td/mtproto/RawConnection.h index 90a602fd6..fa0713857 100644 --- a/td/mtproto/RawConnection.h +++ b/td/mtproto/RawConnection.h @@ -6,22 +6,19 @@ // #pragma once -#include "td/mtproto/IStreamTransport.h" +#include "td/telegram/StateManager.h" + #include "td/mtproto/PacketInfo.h" #include "td/mtproto/TransportType.h" #include "td/utils/buffer.h" -#include "td/utils/BufferedFd.h" #include "td/utils/common.h" #include "td/utils/port/detail/PollableFd.h" +#include "td/utils/port/IPAddress.h" #include "td/utils/port/SocketFd.h" #include "td/utils/Status.h" #include "td/utils/StorerBase.h" -#include "td/telegram/StateManager.h" - -#include - namespace td { namespace mtproto { @@ -39,9 +36,13 @@ class RawConnection { virtual void on_error() = 0; // called on RawConnection error. Such error should be very rare on good connections. virtual void on_mtproto_error() = 0; }; + RawConnection() = default; + RawConnection(const RawConnection &) = delete; + RawConnection &operator=(const RawConnection &) = delete; virtual ~RawConnection() = default; - static td::unique_ptr create(IPAddress ip_address, SocketFd socket_fd, TransportType transport_type, - unique_ptr stats_callback); + + static unique_ptr create(IPAddress ip_address, SocketFd socket_fd, TransportType transport_type, + unique_ptr stats_callback); virtual void set_connection_token(StateManager::ConnectionToken connection_token) = 0; diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 12cf6bb7e..9afad8059 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -10,6 +10,7 @@ #include "td/telegram/DialogParticipant.h" #include "td/telegram/GroupCallId.h" #include "td/telegram/GroupCallParticipant.h" +#include "td/telegram/GroupCallParticipantOrder.h" #include "td/telegram/InputGroupCallId.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index aedcfe37b..c380433bb 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -12,6 +12,8 @@ #include "td/utils/logging.h" +#include + namespace td { GroupCallParticipant::GroupCallParticipant(const tl_object_ptr &participant, diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 69a05d968..0c5a48533 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -30481,7 +30481,7 @@ void MessagesManager::send_dialog_action(DialogId dialog_id, MessageId top_threa tl_object_ptr input_peer; if (action == DialogAction::get_speaking_action()) { - input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + input_peer = get_input_peer(dialog_id, AccessRights::Read); if (input_peer == nullptr) { return promise.set_error(Status::Error(400, "Have no access to the chat")); } @@ -30498,7 +30498,7 @@ void MessagesManager::send_dialog_action(DialogId dialog_id, MessageId top_threa return promise.set_value(Unit()); } - input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write); + input_peer = get_input_peer(dialog_id, AccessRights::Write); } if (dialog_id.get_type() == DialogType::SecretChat) { diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index b82cc15c8..f35a8ebc2 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -566,12 +566,12 @@ class TestProxyRequest : public RequestOnceActor { set_timeout_in(timeout_); promise_ = std::move(promise); - IPAddress ip; - auto status = ip.init_host_port(proxy_.server(), proxy_.port()); + IPAddress ip_address; + auto status = ip_address.init_host_port(proxy_.server(), proxy_.port()); if (status.is_error()) { return promise_.set_error(Status::Error(400, status.public_message())); } - auto r_socket_fd = SocketFd::open(ip); + auto r_socket_fd = SocketFd::open(ip_address); if (r_socket_fd.is_error()) { return promise_.set_error(Status::Error(400, r_socket_fd.error().public_message())); } @@ -590,9 +590,9 @@ class TestProxyRequest : public RequestOnceActor { send_closure(actor_id, &TestProxyRequest::on_connection_data, std::move(r_data)); }); - child_ = - ConnectionCreator::prepare_connection(ip, r_socket_fd.move_as_ok(), proxy_, mtproto_ip_address, get_transport(), - "Test", "TestPingDC2", nullptr, {}, false, std::move(connection_promise)); + child_ = ConnectionCreator::prepare_connection(ip_address, r_socket_fd.move_as_ok(), proxy_, mtproto_ip_address, + get_transport(), "Test", "TestPingDC2", nullptr, {}, false, + std::move(connection_promise)); } void on_connection_data(Result r_data) { diff --git a/td/telegram/net/ConnectionCreator.cpp b/td/telegram/net/ConnectionCreator.cpp index 63dd6a617..6bf5d47fa 100644 --- a/td/telegram/net/ConnectionCreator.cpp +++ b/td/telegram/net/ConnectionCreator.cpp @@ -323,19 +323,20 @@ void ConnectionCreator::ping_proxy(int32 proxy_id, Promise promise) { continue; } - auto ip = info.option->get_ip_address(); - auto r_socket_fd = SocketFd::open(ip); + auto ip_address = info.option->get_ip_address(); + auto r_socket_fd = SocketFd::open(ip_address); if (r_socket_fd.is_error()) { LOG(DEBUG) << "Failed to open socket: " << r_socket_fd.error(); on_ping_main_dc_result(token, r_socket_fd.move_as_error()); continue; } - ping_proxy_socket_fd( - ip, r_socket_fd.move_as_ok(), r_transport_type.move_as_ok(), PSTRING() << info.option->get_ip_address(), - PromiseCreator::lambda([actor_id = actor_id(this), token](Result result) { - send_closure(actor_id, &ConnectionCreator::on_ping_main_dc_result, token, std::move(result)); - })); + ping_proxy_socket_fd(std::move(ip_address), r_socket_fd.move_as_ok(), r_transport_type.move_as_ok(), + PSTRING() << info.option->get_ip_address(), + PromiseCreator::lambda([actor_id = actor_id(this), token](Result result) { + send_closure(actor_id, &ConnectionCreator::on_ping_main_dc_result, token, + std::move(result)); + })); } return; } diff --git a/tdnet/CMakeLists.txt b/tdnet/CMakeLists.txt index b613cfe34..b385bc236 100644 --- a/tdnet/CMakeLists.txt +++ b/tdnet/CMakeLists.txt @@ -47,7 +47,7 @@ set(TDNET_SOURCE ) if (TD_EXPERIMENTAL_WATCH_OS) - set (TDNET_SOURCE + set(TDNET_SOURCE ${TDNET_SOURCE} td/net/DarwinHttp.mm td/net/DarwinHttp.h diff --git a/tdnet/td/net/DarwinHttp.mm b/tdnet/td/net/DarwinHttp.mm index 11a491db3..d7cd819ba 100644 --- a/tdnet/td/net/DarwinHttp.mm +++ b/tdnet/td/net/DarwinHttp.mm @@ -6,6 +6,8 @@ // #include "td/net/DarwinHttp.h" +#include "td/utils/logging.h" + #import namespace td { @@ -16,7 +18,7 @@ NSString *to_ns_string(CSlice slice) { } NSData *to_ns_data(Slice data) { - return [NSData dataWithBytes:static_cast(data.data()) length:data.size()]; + return [NSData dataWithBytes:static_cast(data.data()) length:data.size()]; } auto http_get(CSlice url) { @@ -37,17 +39,17 @@ auto http_post(CSlice url, Slice data) { return request; } -void http_send(NSURLRequest *request, Promise promise) { +void http_send(NSURLRequest *request, Promise promise) { __block auto callback = std::move(promise); - NSURLSessionDataTask* dataTask = + NSURLSessionDataTask *dataTask = [NSURLSession.sharedSession dataTaskWithRequest:request completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) { - if(error == nil) { - callback(BufferSlice(Slice((const char *)([data bytes]), [data length]))); + if (error == nil) { + callback(BufferSlice(Slice((const char *)([data bytes]), [data length]))); } else { - callback(Status::Error(static_cast([error code]))); + callback(Status::Error(static_cast([error code]), "HTTP request failed")); } }]; [dataTask resume]; diff --git a/test/http.cpp b/test/http.cpp index 34fbd79c6..84b2f8817 100644 --- a/test/http.cpp +++ b/test/http.cpp @@ -42,8 +42,8 @@ #include #include -#include #include +#include REGISTER_TESTS(http) @@ -498,7 +498,7 @@ TEST(Http, Darwin) { Baton baton; //LOG(ERROR) << "???"; td::DarwinHttp::get("http://example.com", [&](td::BufferSlice data) { - LOG(ERROR) << data.as_slice(); + //LOG(ERROR) << data.as_slice(); baton.post(); }); //LOG(ERROR) << "!!!"; From 2ba7fd0f188cd2a7459dae1dca426a544eec9fdd Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 01:51:51 +0300 Subject: [PATCH 121/281] Enable HTTP gzip text. --- test/http.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/http.cpp b/test/http.cpp index 84b2f8817..3dbc9f940 100644 --- a/test/http.cpp +++ b/test/http.cpp @@ -246,7 +246,6 @@ TEST(Http, gzip_bomb) { } TEST(Http, gzip) { - return; auto gzip_str = gzdecode(base64url_decode(Slice(gzip, gzip_size)).ok()).as_slice().str(); td::ChainBufferWriter input_writer; From 879fd3b7c05df3a130202e8e414efe5eab9306db Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 01:55:39 +0300 Subject: [PATCH 122/281] Use add_message_sender_dependencies for default group call alias. --- td/telegram/MessagesManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 0c5a48533..597d019e4 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -34960,7 +34960,7 @@ unique_ptr MessagesManager::parse_dialog(DialogId dialo Dependencies dependencies; add_dialog_dependencies(dependencies, dialog_id); if (d->default_join_group_call_as_dialog_id != dialog_id) { - add_dialog_and_dependencies(dependencies, d->default_join_group_call_as_dialog_id); + add_message_sender_dependencies(dependencies, d->default_join_group_call_as_dialog_id); } if (d->messages != nullptr) { add_message_dependencies(dependencies, dialog_id, d->messages.get()); From f7e9da283dd0a2c6fa188907aa6737bb4399c3c1 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 01:59:17 +0300 Subject: [PATCH 123/281] Expect that there can be no access to group call participant channels. --- td/telegram/GroupCallManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 9e21bee55..d9cfce887 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1466,7 +1466,7 @@ void GroupCallManager::on_update_group_call_participants( } auto dialog_id = participant.dialog_id; if (dialog_id.get_type() != DialogType::User && participant.joined_date != 0) { - td_->messages_manager_->force_create_dialog(dialog_id, "on_update_group_call_participants 2"); + td_->messages_manager_->force_create_dialog(dialog_id, "on_update_group_call_participants 2", true); } if (GroupCallParticipant::is_versioned_update(group_call_participant)) { @@ -1655,7 +1655,7 @@ void GroupCallManager::process_group_call_participants( continue; } if (participant.dialog_id.get_type() != DialogType::User) { - td_->messages_manager_->force_create_dialog(participant.dialog_id, "process_group_call_participants"); + td_->messages_manager_->force_create_dialog(participant.dialog_id, "process_group_call_participants", true); } on_participant_speaking_in_group_call(input_group_call_id, participant); @@ -1689,7 +1689,7 @@ void GroupCallManager::process_group_call_participants( continue; } if (participant.dialog_id.get_type() != DialogType::User) { - td_->messages_manager_->force_create_dialog(participant.dialog_id, "process_group_call_participants"); + td_->messages_manager_->force_create_dialog(participant.dialog_id, "process_group_call_participants", true); } if (is_load) { @@ -3552,7 +3552,7 @@ void GroupCallManager::on_user_speaking_in_group_call(GroupCallId group_call_id, for (size_t i = 0; i <= recent_speakers->users.size(); i++) { if (i == recent_speakers->users.size() || recent_speakers->users[i].second <= date) { if (dialog_id.get_type() != DialogType::User) { - td_->messages_manager_->force_create_dialog(dialog_id, "on_user_speaking_in_group_call"); + td_->messages_manager_->force_create_dialog(dialog_id, "on_user_speaking_in_group_call", true); } recent_speakers->users.insert(recent_speakers->users.begin() + i, {dialog_id, date}); break; From 024601eb864e5c44b0ac0a7235d0602db6bdb2a6 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 02:06:24 +0300 Subject: [PATCH 124/281] Don't call remove_dialog_access_by_invite_link on username change. --- td/telegram/ContactsManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 1fd71da64..78ac131a2 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -11929,9 +11929,6 @@ void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool need_dr } update_channel_full(channel_full, channel_id); } - if (need_drop_invite_link) { - remove_dialog_access_by_invite_link(DialogId(channel_id)); - } } void ContactsManager::on_update_chat_full_photo(ChatFull *chat_full, ChatId chat_id, Photo photo) { @@ -12927,6 +12924,9 @@ void ContactsManager::on_channel_status_changed(Channel *c, ChannelId channel_id reload_dialog_administrators(DialogId(channel_id), 0, Auto()); remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); } + if (old_status.is_member() != new_status.is_member() || new_status.is_banned()) { + remove_dialog_access_by_invite_link(DialogId(channel_id)); + } if (need_reload_group_call) { send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_group_call_rights, DialogId(channel_id)); From 984e79b7f774e00a417df74f981e0fd139909958 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 02:35:11 +0300 Subject: [PATCH 125/281] Drop channel invite link, only when corresponding administrator right is removed. --- td/telegram/ContactsManager.cpp | 48 +++++++++++++++++---------------- td/telegram/ContactsManager.h | 2 +- td/telegram/DialogParticipant.h | 5 ++++ td/telegram/UpdatesManager.cpp | 2 +- 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 78ac131a2..ae1bfd3cb 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -2292,7 +2292,7 @@ class InviteToChannelQuery : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for InviteToChannelQuery: " << to_string(ptr); - td->contacts_manager_->invalidate_channel_full(channel_id_, false, false); + td->contacts_manager_->invalidate_channel_full(channel_id_, false); td->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); } @@ -2327,7 +2327,7 @@ class EditChannelAdminQuery : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for EditChannelAdminQuery: " << to_string(ptr); - td->contacts_manager_->invalidate_channel_full(channel_id_, false, false); + td->contacts_manager_->invalidate_channel_full(channel_id_, false); td->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); } @@ -2362,7 +2362,7 @@ class EditChannelBannedQuery : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for EditChannelBannedQuery: " << to_string(ptr); - td->contacts_manager_->invalidate_channel_full(channel_id_, false, false); + td->contacts_manager_->invalidate_channel_full(channel_id_, false); td->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); } @@ -2468,7 +2468,7 @@ class EditChannelCreatorQuery : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for EditChannelCreatorQuery: " << to_string(ptr); - td->contacts_manager_->invalidate_channel_full(channel_id_, false, false); + td->contacts_manager_->invalidate_channel_full(channel_id_, false); td->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); } @@ -3518,7 +3518,7 @@ void ContactsManager::on_channel_unban_timeout(ChannelId channel_id) { LOG(INFO) << "Update " << channel_id << " status"; c->is_status_changed = true; - invalidate_channel_full(channel_id, false, !c->is_slow_mode_enabled); + invalidate_channel_full(channel_id, !c->is_slow_mode_enabled); update_channel(c, channel_id); // always call, because in case of failure we need to reactivate timeout } @@ -7135,8 +7135,7 @@ Status ContactsManager::can_manage_dialog_invite_links(DialogId dialog_id, bool if (!c->is_active) { return Status::Error(3, "Chat is deactivated"); } - auto status = get_chat_status(c); - bool have_rights = creator_only ? status.is_creator() : status.is_administrator() && status.can_invite_users(); + bool have_rights = creator_only ? c->status.is_creator() : c->status.can_manage_invite_links(); if (!have_rights) { return Status::Error(3, "Not enough rights to manage chat invite link"); } @@ -7147,8 +7146,7 @@ Status ContactsManager::can_manage_dialog_invite_links(DialogId dialog_id, bool if (c == nullptr) { return Status::Error(3, "Chat info not found"); } - auto status = get_channel_status(c); - bool have_rights = creator_only ? status.is_creator() : status.is_administrator() && status.can_invite_users(); + bool have_rights = creator_only ? c->status.is_creator() : c->status.can_manage_invite_links(); if (!have_rights) { return Status::Error(3, "Not enough rights to manage chat invite link"); } @@ -11510,7 +11508,7 @@ bool ContactsManager::on_get_channel_error(ChannelId channel_id, const Status &s remove_dialog_access_by_invite_link(DialogId(channel_id)); } - invalidate_channel_full(channel_id, false, !c->is_slow_mode_enabled); + invalidate_channel_full(channel_id, !c->is_slow_mode_enabled); LOG_IF(ERROR, have_input_peer_channel(c, channel_id, AccessRights::Read)) << "Have read access to channel after receiving CHANNEL_PRIVATE. Channel state: " << oneline(to_string(get_supergroup_object(channel_id, c))) @@ -11760,7 +11758,7 @@ void ContactsManager::speculative_add_channel_participants(ChannelId channel_id, bool by_me) { if (by_me) { // Currently ignore all changes made by the current user, because they may be already counted - invalidate_channel_full(channel_id, false, false); // just in case + invalidate_channel_full(channel_id, false); // just in case return; } @@ -11911,16 +11909,12 @@ void ContactsManager::drop_channel_photos(ChannelId channel_id, bool is_empty, b } } -void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool need_drop_invite_link, - bool need_drop_slow_mode_delay) { +void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool need_drop_slow_mode_delay) { LOG(INFO) << "Invalidate supergroup full for " << channel_id; // drop channel full cache auto channel_full = get_channel_full_force(channel_id, "invalidate_channel_full"); if (channel_full != nullptr) { channel_full->expires_at = 0.0; - if (need_drop_invite_link) { - on_update_channel_full_invite_link(channel_full, nullptr); - } if (need_drop_slow_mode_delay && channel_full->slow_mode_delay != 0) { channel_full->slow_mode_delay = 0; channel_full->slow_mode_next_send_date = 0; @@ -12909,10 +12903,17 @@ void ContactsManager::on_channel_status_changed(Channel *c, ChannelId channel_id const DialogParticipantStatus &new_status) { CHECK(c->is_update_supergroup_sent); - bool need_drop_invite_link = old_status.is_administrator() != new_status.is_administrator() || - old_status.is_member() != new_status.is_member(); bool need_reload_group_call = old_status.can_manage_calls() != new_status.can_manage_calls(); - invalidate_channel_full(channel_id, need_drop_invite_link, !c->is_slow_mode_enabled); + if (old_status.can_manage_invite_links() && !new_status.can_manage_invite_links()) { + auto channel_full = get_channel_full_force(channel_id, "on_channel_status_changed"); + if (channel_full != nullptr) { + on_update_channel_full_invite_link(channel_full, nullptr); + invalidate_channel_full(channel_id, !c->is_slow_mode_enabled); + update_channel_full(channel_full, channel_id); + } + } else { + invalidate_channel_full(channel_id, !c->is_slow_mode_enabled); + } if (old_status.is_creator() != new_status.is_creator()) { for (size_t i = 0; i < 2; i++) { @@ -12924,6 +12925,7 @@ void ContactsManager::on_channel_status_changed(Channel *c, ChannelId channel_id reload_dialog_administrators(DialogId(channel_id), 0, Auto()); remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); } + if (old_status.is_member() != new_status.is_member() || new_status.is_banned()) { remove_dialog_access_by_invite_link(DialogId(channel_id)); } @@ -12976,7 +12978,7 @@ void ContactsManager::on_channel_username_changed(Channel *c, ChannelId channel_ const string &new_username) { if (old_username.empty() || new_username.empty()) { // moving channel from private to public can change availability of chat members - invalidate_channel_full(channel_id, true, !c->is_slow_mode_enabled); + invalidate_channel_full(channel_id, !c->is_slow_mode_enabled); } } @@ -15220,7 +15222,7 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char c->is_gigagroup = is_gigagroup; c->is_changed = true; - invalidate_channel_full(channel_id, false, !c->is_slow_mode_enabled); + invalidate_channel_full(channel_id, !c->is_slow_mode_enabled); } if (c->is_verified != is_verified || c->sign_messages != sign_messages) { c->is_verified = is_verified; @@ -15311,7 +15313,7 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char } if (need_invalidate_channel_full) { - invalidate_channel_full(channel_id, false, !c->is_slow_mode_enabled); + invalidate_channel_full(channel_id, !c->is_slow_mode_enabled); } bool has_active_group_call = (channel.flags_ & CHANNEL_FLAG_HAS_ACTIVE_GROUP_CALL) != 0; @@ -15420,7 +15422,7 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co } } if (need_invalidate_channel_full) { - invalidate_channel_full(channel_id, false, !c->is_slow_mode_enabled); + invalidate_channel_full(channel_id, !c->is_slow_mode_enabled); } } diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 86694d116..b620da9bc 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -233,7 +233,7 @@ class ContactsManager : public Actor { void speculative_delete_channel_participant(ChannelId channel_id, UserId deleted_user_id, bool by_me); - void invalidate_channel_full(ChannelId channel_id, bool need_drop_invite_link, bool need_drop_slow_mode_delay); + void invalidate_channel_full(ChannelId channel_id, bool need_drop_slow_mode_delay); bool on_get_channel_error(ChannelId channel_id, const Status &status, const string &source); diff --git a/td/telegram/DialogParticipant.h b/td/telegram/DialogParticipant.h index fb022a308..62ceea2b3 100644 --- a/td/telegram/DialogParticipant.h +++ b/td/telegram/DialogParticipant.h @@ -235,6 +235,11 @@ class DialogParticipantStatus { return (flags_ & CAN_INVITE_USERS_ADMIN) != 0 || (flags_ & CAN_INVITE_USERS_BANNED) != 0; } + bool can_manage_invite_links() const { + // invite links can be managed, only if administrator was explicitly granted the right + return (flags_ & CAN_INVITE_USERS_ADMIN) != 0; + } + bool can_restrict_members() const { return (flags_ & CAN_RESTRICT_MEMBERS) != 0; } diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index ba383eea9..52eacfeec 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -2213,7 +2213,7 @@ void UpdatesManager::on_update(tl_object_ptr } void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { - td_->contacts_manager_->invalidate_channel_full(ChannelId(update->channel_id_), false, false); + td_->contacts_manager_->invalidate_channel_full(ChannelId(update->channel_id_), false); promise.set_value(Unit()); } From d74749c8134f87e180a4665eb82573d3a6863b5f Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 03:25:08 +0300 Subject: [PATCH 126/281] Drop basic group invite link if removed from administrators. --- td/telegram/ContactsManager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index ae1bfd3cb..d3a890a96 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -12567,6 +12567,7 @@ void ContactsManager::on_update_chat_status(Chat *c, ChatId chat_id, DialogParti if (c->status != status) { LOG(INFO) << "Update " << chat_id << " status from " << c->status << " to " << status; bool need_reload_group_call = c->status.can_manage_calls() != status.can_manage_calls(); + bool need_drop_invite_link = c->status.can_manage_invite_links() && !status.can_manage_invite_links(); c->status = status; @@ -12577,6 +12578,12 @@ void ContactsManager::on_update_chat_status(Chat *c, ChatId chat_id, DialogParti c->pinned_message_version = -1; drop_chat_full(chat_id); + } else if (need_drop_invite_link) { + ChatFull *chat_full = get_chat_full_force(chat_id, "on_update_chat_status"); + if (chat_full != nullptr) { + on_update_chat_full_invite_link(chat_full, nullptr); + update_chat_full(chat_full, chat_id); + } } if (need_reload_group_call) { send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_group_call_rights, From 7aa71edad2ead09a889351c88697cad61837f6f4 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 03:36:14 +0300 Subject: [PATCH 127/281] Drop outdated *Full.invite_link stored in the database. --- td/telegram/ContactsManager.cpp | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index d3a890a96..dcf469108 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -9426,11 +9426,16 @@ void ContactsManager::on_load_chat_full_from_database(ChatId chat_id, string val Chat *c = get_chat(chat_id); CHECK(c != nullptr); - // ignore ChatFull without invite link - if (c->is_active && c->status.is_administrator() && c->status.can_invite_users() && - !chat_full->invite_link.is_valid()) { - chats_full_.erase(chat_id); - return; + bool need_invite_link = c->is_active && c->status.can_manage_invite_links(); + bool have_invite_link = chat_full->invite_link.is_valid(); + if (need_invite_link != have_invite_link) { + if (need_invite_link) { + // ignore ChatFull without invite link + chats_full_.erase(chat_id); + return; + } else { + chat_full->invite_link = DialogInviteLink(); + } } if (td_->file_manager_->get_file_view(c->photo.small_file_id).get_unique_file_id() != @@ -9525,10 +9530,16 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s Channel *c = get_channel(channel_id); CHECK(c != nullptr); - // ignore ChannelFull without invite link - if (c->status.is_administrator() && c->status.can_invite_users() && !channel_full->invite_link.is_valid()) { - channels_full_.erase(channel_id); - return; + bool need_invite_link = c->status.can_manage_invite_links(); + bool have_invite_link = channel_full->invite_link.is_valid(); + if (need_invite_link != have_invite_link) { + if (need_invite_link) { + // ignore ChannelFull without invite link + channels_full_.erase(channel_id); + return; + } else { + channel_full->invite_link = DialogInviteLink(); + } } if (td_->file_manager_->get_file_view(c->photo.small_file_id).get_unique_file_id() != @@ -13818,8 +13829,7 @@ bool ContactsManager::is_chat_full_outdated(const ChatFull *chat_full, const Cha } } - if (c->is_active && c->status.is_administrator() && c->status.can_invite_users() && - !chat_full->invite_link.is_valid()) { + if (c->is_active && c->status.can_manage_invite_links() && !chat_full->invite_link.is_valid()) { LOG(INFO) << "Have outdated invite link in " << chat_id; return true; } From 307821eb31b3dc02ab1d3d730d80b7244979b5f3 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 03:46:24 +0300 Subject: [PATCH 128/281] Never treat closed secret chats as just created. --- td/telegram/MessagesManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 597d019e4..8494bf893 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -33744,7 +33744,8 @@ void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source d = add_dialog(dialog_id); update_dialog_pos(d, "force_create_dialog"); - if (dialog_id.get_type() == DialogType::SecretChat && !d->notification_settings.is_synchronized) { + if (dialog_id.get_type() == DialogType::SecretChat && !d->notification_settings.is_synchronized && + td_->contacts_manager_->get_secret_chat_state(dialog_id.get_secret_chat_id()) != SecretChatState::Closed) { // secret chat is being created // let's copy notification settings from main chat if available VLOG(notifications) << "Create new secret " << dialog_id << " from " << source; From 9936cdc320c07b2e24fb9b595870e049b3ea4322 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 04:03:00 +0300 Subject: [PATCH 129/281] Fix handling of speaking in group call chat actions. --- td/telegram/MessagesManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 8494bf893..f9fdbc800 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -7247,7 +7247,7 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th const Dialog *d = get_dialog_force(dialog_id); if (d != nullptr && d->active_group_call_id.is_valid()) { auto group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, dialog_id); - td_->group_call_manager_->on_user_speaking_in_group_call(group_call_id, dialog_id, date); + td_->group_call_manager_->on_user_speaking_in_group_call(group_call_id, typing_dialog_id, date); } return; } From cc0d45a01c144f94b1793bcbb2c0b74f5e7d6a92 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 04:41:32 +0300 Subject: [PATCH 130/281] Add groupCallParticipant.is_current_user field. --- td/generate/scheme/td_api.tl | 3 ++- td/telegram/GroupCallParticipant.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index c647ed31a..70fe209a9 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2152,6 +2152,7 @@ groupCallJoinResponseStream = GroupCallJoinResponse; //@participant Identifier of the group call participant //@source User's synchronization source //@bio The participant user's bio or the participant chat's description +//@is_current_user True, if the participant is the current user //@is_speaking True, if the participant is speaking as set by setGroupCallParticipantIsSpeaking //@is_hand_raised True, if the participant hand is raised //@can_be_muted_for_all_users True, if the current user can mute the participant for all other group call participants @@ -2163,7 +2164,7 @@ groupCallJoinResponseStream = GroupCallJoinResponse; //@can_unmute_self True, if the participant is muted for all users, but can unmute themself //@volume_level Participant's volume level; 1-20000 in hundreds of percents //@order User's order in the group call participant list. Orders must be compared lexicographically. The bigger is order, the higher is user in the list. If order is empty, the user must be removed from the participant list -groupCallParticipant participant:MessageSender source:int32 bio:string is_speaking:Bool is_hand_raised:Bool can_be_muted_for_all_users:Bool can_be_unmuted_for_all_users:Bool can_be_muted_for_current_user:Bool can_be_unmuted_for_current_user:Bool is_muted_for_all_users:Bool is_muted_for_current_user:Bool can_unmute_self:Bool volume_level:int32 order:string = GroupCallParticipant; +groupCallParticipant participant:MessageSender source:int32 bio:string is_current_user:Bool is_speaking:Bool is_hand_raised:Bool can_be_muted_for_all_users:Bool can_be_unmuted_for_all_users:Bool can_be_muted_for_current_user:Bool can_be_unmuted_for_current_user:Bool is_muted_for_all_users:Bool is_muted_for_current_user:Bool can_unmute_self:Bool volume_level:int32 order:string = GroupCallParticipant; //@class CallProblem @description Describes the exact type of a problem with a call diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index c380433bb..8a339deac 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -247,7 +247,7 @@ td_api::object_ptr GroupCallParticipant::get_group } return td_api::make_object( - td->messages_manager_->get_message_sender_object(dialog_id), audio_source, about, is_speaking, + td->messages_manager_->get_message_sender_object(dialog_id), audio_source, about, is_self, is_speaking, get_is_hand_raised(), can_be_muted_for_all_users, can_be_unmuted_for_all_users, can_be_muted_only_for_self, can_be_unmuted_only_for_self, get_is_muted_for_all_users(), get_is_muted_locally(), get_is_muted_by_themselves(), get_volume_level(), order.get_group_call_participant_order_object()); @@ -255,7 +255,8 @@ td_api::object_ptr GroupCallParticipant::get_group bool operator==(const GroupCallParticipant &lhs, const GroupCallParticipant &rhs) { return lhs.dialog_id == rhs.dialog_id && lhs.audio_source == rhs.audio_source && lhs.about == rhs.about && - lhs.is_speaking == rhs.is_speaking && lhs.get_is_hand_raised() == rhs.get_is_hand_raised() && + lhs.is_self == rhs.is_self && lhs.is_speaking == rhs.is_speaking && + lhs.get_is_hand_raised() == rhs.get_is_hand_raised() && lhs.can_be_muted_for_all_users == rhs.can_be_muted_for_all_users && lhs.can_be_unmuted_for_all_users == rhs.can_be_unmuted_for_all_users && lhs.can_be_muted_only_for_self == rhs.can_be_muted_only_for_self && From 0d1c310e324871c279c249785f4336ac280ce217 Mon Sep 17 00:00:00 2001 From: Sprite Date: Sun, 28 Mar 2021 09:46:30 +0800 Subject: [PATCH 131/281] Fix memory leak of "handlers_" in cpp example (#1464) --- example/cpp/td_example.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/example/cpp/td_example.cpp b/example/cpp/td_example.cpp index 9e998f835..d94582110 100644 --- a/example/cpp/td_example.cpp +++ b/example/cpp/td_example.cpp @@ -172,6 +172,7 @@ class TdExample { auto it = handlers_.find(response.request_id); if (it != handlers_.end()) { it->second(std::move(response.object)); + handlers_.erase(it); } } From fbc7e5a7f845d6c8df12b11f5b9a5c9ffc6eea0e Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 05:34:58 +0300 Subject: [PATCH 132/281] Don't update group call participant count by definitely already applied updates. --- td/telegram/GroupCallManager.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index d9cfce887..1751a8f32 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -652,6 +652,7 @@ struct GroupCallManager::GroupCall { DialogId as_dialog_id; int32 version = -1; + int32 leave_version = -1; int32 title_version = -1; int32 mute_version = -1; int32 stream_dc_id_version = -1; @@ -1390,10 +1391,12 @@ void GroupCallManager::on_update_group_call_participants( continue; } if (participant.joined_date == 0) { - diff--; + if (version > group_call->leave_version) { + diff--; + } remove_recent_group_call_speaker(input_group_call_id, participant.dialog_id); } else { - if (participant.is_just_joined) { + if (participant.is_just_joined && version >= group_call->leave_version) { diff++; } on_participant_speaking_in_group_call(input_group_call_id, participant); @@ -3253,6 +3256,7 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ group_call->loaded_all_participants = false; send_update_group_call(group_call, "try_clear_group_call_participants"); } + group_call->leave_version = group_call->version; group_call->version = -1; for (auto &participant : participants->participants) { From 92f664614b192d3e7aef816f52c485e8b65a2a5f Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sun, 28 Mar 2021 12:50:00 +0200 Subject: [PATCH 133/281] Fix #18 --- td/telegram/PollManager.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/td/telegram/PollManager.cpp b/td/telegram/PollManager.cpp index 246139985..5d7a2e183 100644 --- a/td/telegram/PollManager.cpp +++ b/td/telegram/PollManager.cpp @@ -1177,8 +1177,12 @@ void PollManager::on_update_poll_timeout(PollId poll_id) { if (G()->close_flag()) { return; } + auto poll = get_poll(poll_id); - if (!(poll != nullptr)) return; + if (poll == nullptr) { + return; + } + if (poll->is_closed && poll->is_updated_after_close) { return; } @@ -1192,7 +1196,13 @@ void PollManager::on_update_poll_timeout(PollId poll_id) { return; } - auto full_message_id = *it->second.begin(); + auto full_message_id_set = std::move(it->second); + if (full_message_id_set.empty()) { + return; + } + + auto full_message_id = *full_message_id_set.begin(); + LOG(INFO) << "Fetching results of " << poll_id << " from " << full_message_id; auto query_promise = PromiseCreator::lambda([poll_id, generation = current_generation_, actor_id = actor_id(this)]( Result> &&result) { From 4df03c84911fadcb75ad690b17c3272631f4d635 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 28 Mar 2021 22:33:22 +0300 Subject: [PATCH 134/281] Clamp float numbers before conversion to integers. --- td/mtproto/SessionConnection.cpp | 3 ++- td/mtproto/SessionConnection.h | 4 ++-- td/telegram/Client.cpp | 2 +- td/telegram/NotificationManager.cpp | 3 ++- tdactor/td/actor/impl/Scheduler.cpp | 3 ++- tdutils/td/utils/port/detail/skip_eintr.h | 2 +- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/td/mtproto/SessionConnection.cpp b/td/mtproto/SessionConnection.cpp index eca0e9845..f81c47a00 100644 --- a/td/mtproto/SessionConnection.cpp +++ b/td/mtproto/SessionConnection.cpp @@ -19,6 +19,7 @@ #include "td/utils/format.h" #include "td/utils/Gzip.h" #include "td/utils/logging.h" +#include "td/utils/misc.h" #include "td/utils/Random.h" #include "td/utils/ScopeGuard.h" #include "td/utils/Time.h" @@ -863,7 +864,7 @@ void SessionConnection::flush_packet() { max_after = HTTP_MAX_AFTER; auto time_to_disconnect = min(ping_disconnect_delay() + last_pong_at_, read_disconnect_delay() + last_read_at_) - Time::now_cached(); - max_wait = min(http_max_wait(), static_cast(1000 * max(0.1, time_to_disconnect - rtt()))); + max_wait = static_cast(1000 * clamp(time_to_disconnect - rtt(), 0.1, http_max_wait())); } else if (mode_ == Mode::Http) { max_delay = HTTP_MAX_DELAY; max_after = HTTP_MAX_AFTER; diff --git a/td/mtproto/SessionConnection.h b/td/mtproto/SessionConnection.h index ca9e1fb16..d13f866ed 100644 --- a/td/mtproto/SessionConnection.h +++ b/td/mtproto/SessionConnection.h @@ -151,8 +151,8 @@ class SessionConnection return online_flag_ ? rtt() : 60; } - int http_max_wait() const { - return 25 * 1000; // 25s. Longer could be closed by proxy + double http_max_wait() const { + return 25.0; // 25s. Longer could be closed by proxy } static constexpr int HTTP_MAX_AFTER = 10; // 0.01s static constexpr int HTTP_MAX_DELAY = 30; // 0.03s diff --git a/td/telegram/Client.cpp b/td/telegram/Client.cpp index fc514fe86..74be58155 100644 --- a/td/telegram/Client.cpp +++ b/td/telegram/Client.cpp @@ -277,7 +277,7 @@ class TdReceiver { if (is_locked) { LOG(FATAL) << "Receive is called after Client destroy, or simultaneously from different threads"; } - auto response = receive_unlocked(timeout); + auto response = receive_unlocked(clamp(timeout, 0.0, 1000000.0)); is_locked = receive_lock_.exchange(false); CHECK(is_locked); VLOG(td_requests) << "End to wait for updates, returning object " << response.request_id << ' ' diff --git a/td/telegram/NotificationManager.cpp b/td/telegram/NotificationManager.cpp index f2393b91f..6c79a6a95 100644 --- a/td/telegram/NotificationManager.cpp +++ b/td/telegram/NotificationManager.cpp @@ -845,7 +845,8 @@ int32 NotificationManager::get_notification_delay_ms(DialogId dialog_id, const P return 0; }(); - auto passed_time_ms = max(0, static_cast((G()->server_time_cached() - notification.date - 1) * 1000)); + auto passed_time_ms = + static_cast(clamp(G()->server_time_cached() - notification.date - 1, 0.0, 1000000.0) * 1000); return max(max(min_delay_ms, delay_ms) - passed_time_ms, MIN_NOTIFICATION_DELAY_MS); } diff --git a/tdactor/td/actor/impl/Scheduler.cpp b/tdactor/td/actor/impl/Scheduler.cpp index 7ed44c1f6..c5c5c88a5 100644 --- a/tdactor/td/actor/impl/Scheduler.cpp +++ b/tdactor/td/actor/impl/Scheduler.cpp @@ -17,6 +17,7 @@ #include "td/utils/format.h" #include "td/utils/List.h" #include "td/utils/logging.h" +#include "td/utils/misc.h" #include "td/utils/ObjectPool.h" #include "td/utils/port/thread_local.h" #include "td/utils/ScopeGuard.h" @@ -428,7 +429,7 @@ void Scheduler::set_actor_timeout_at(ActorInfo *actor_info, double timeout_at) { void Scheduler::run_poll(Timestamp timeout) { // we can't wait for less than 1ms - int timeout_ms = static_cast(td::max(timeout.in(), 0.0) * 1000 + 1); + int timeout_ms = static_cast(clamp(timeout.in(), 0.0, 1000000.0) * 1000 + 1); #if TD_PORT_WINDOWS CHECK(inbound_queue_); inbound_queue_->reader_get_event_fd().wait(timeout_ms); diff --git a/tdutils/td/utils/port/detail/skip_eintr.h b/tdutils/td/utils/port/detail/skip_eintr.h index 5afa24159..e501269c7 100644 --- a/tdutils/td/utils/port/detail/skip_eintr.h +++ b/tdutils/td/utils/port/detail/skip_eintr.h @@ -53,7 +53,7 @@ auto skip_eintr_timeout(F &&f, int32 timeout_ms) { break; } left_timeout_ms = - td::max(static_cast((start.at() - Timestamp::now().at()) * 1000 + timeout_ms + 1 - 1e-9), 0); + static_cast(td::max((start.at() - Timestamp::now().at()) * 1000 + timeout_ms + 1 - 1e-9, 0.0)); } return res; } From 4f644ce38961c93d668820842bfa0c7a4233d329 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 00:50:15 +0300 Subject: [PATCH 135/281] Add and use statis UserId::get_user_ids/get_input_user_ids methods. --- td/telegram/AuthManager.cpp | 9 +++--- td/telegram/AuthManager.h | 12 +++---- td/telegram/DeviceTokenManager.cpp | 13 ++++---- td/telegram/DeviceTokenManager.h | 6 ++-- td/telegram/Td.cpp | 50 ++++++++++++------------------ td/telegram/UserId.h | 18 +++++++++++ 6 files changed, 56 insertions(+), 52 deletions(-) diff --git a/td/telegram/AuthManager.cpp b/td/telegram/AuthManager.cpp index 1da0117ed..5836d0efe 100644 --- a/td/telegram/AuthManager.cpp +++ b/td/telegram/AuthManager.cpp @@ -165,7 +165,7 @@ void AuthManager::check_bot_token(uint64 query_id, string bot_token) { telegram_api::auth_importBotAuthorization(0, api_id_, api_hash_, bot_token_))); } -void AuthManager::request_qr_code_authentication(uint64 query_id, vector other_user_ids) { +void AuthManager::request_qr_code_authentication(uint64 query_id, vector other_user_ids) { if (state_ != State::WaitPhoneNumber) { if ((state_ == State::WaitCode || state_ == State::WaitPassword || state_ == State::WaitRegistration) && net_query_id_ == 0) { @@ -181,8 +181,7 @@ void AuthManager::request_qr_code_authentication(uint64 query_id, vector "Cannot request QR code authentication after bot token was entered. You need to log out first")); } for (auto &other_user_id : other_user_ids) { - UserId user_id(other_user_id); - if (!user_id.is_valid()) { + if (!other_user_id.is_valid()) { return on_query_error(query_id, Status::Error(400, "Invalid user_id among other user_ids")); } } @@ -200,8 +199,8 @@ void AuthManager::request_qr_code_authentication(uint64 query_id, vector void AuthManager::send_export_login_token_query() { poll_export_login_code_timeout_.cancel_timeout(); start_net_query(NetQueryType::RequestQrCode, - G()->net_query_creator().create_unauth( - telegram_api::auth_exportLoginToken(api_id_, api_hash_, vector(other_user_ids_)))); + G()->net_query_creator().create_unauth(telegram_api::auth_exportLoginToken( + api_id_, api_hash_, UserId::get_input_user_ids(other_user_ids_)))); } void AuthManager::set_login_token_expires_at(double login_token_expires_at) { diff --git a/td/telegram/AuthManager.h b/td/telegram/AuthManager.h index 6ae668b44..dd071021f 100644 --- a/td/telegram/AuthManager.h +++ b/td/telegram/AuthManager.h @@ -9,10 +9,10 @@ #include "td/telegram/net/NetActor.h" #include "td/telegram/net/NetQuery.h" #include "td/telegram/SendCodeHelper.h" -#include "td/telegram/TermsOfService.h" - #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/TermsOfService.h" +#include "td/telegram/UserId.h" #include "td/actor/actor.h" #include "td/actor/Timeout.h" @@ -38,7 +38,7 @@ class AuthManager : public NetActor { void resend_authentication_code(uint64 query_id); void check_code(uint64 query_id, string code); void register_user(uint64 query_id, string first_name, string last_name); - void request_qr_code_authentication(uint64 query_id, vector other_user_ids); + void request_qr_code_authentication(uint64 query_id, vector other_user_ids); void check_bot_token(uint64 query_id, string bot_token); void check_password(uint64 query_id, string password); void request_password_recovery(uint64 query_id); @@ -113,7 +113,7 @@ class AuthManager : public NetActor { SendCodeHelper send_code_helper_; // WaitQrCodeConfirmation - vector other_user_ids_; + vector other_user_ids_; string login_token_; double login_token_expires_at_ = 0; @@ -130,7 +130,7 @@ class AuthManager : public NetActor { return state; } - static DbState wait_qr_code_confirmation(int32 api_id, string api_hash, vector other_user_ids, + static DbState wait_qr_code_confirmation(int32 api_id, string api_hash, vector other_user_ids, string login_token, double login_token_expires_at) { DbState state(State::WaitQrCodeConfirmation, api_id, api_hash); state.other_user_ids_ = std::move(other_user_ids); @@ -179,7 +179,7 @@ class AuthManager : public NetActor { string code_; // State::WaitQrCodeConfirmation - vector other_user_ids_; + vector other_user_ids_; string login_token_; double login_token_expires_at_ = 0.0; int32 imported_dc_id_ = -1; diff --git a/td/telegram/DeviceTokenManager.cpp b/td/telegram/DeviceTokenManager.cpp index 27a9020ca..758cda9c0 100644 --- a/td/telegram/DeviceTokenManager.cpp +++ b/td/telegram/DeviceTokenManager.cpp @@ -120,7 +120,7 @@ StringBuilder &operator<<(StringBuilder &string_builder, const DeviceTokenManage } void DeviceTokenManager::register_device(tl_object_ptr device_token_ptr, - vector other_user_ids, + vector other_user_ids, Promise> promise) { CHECK(device_token_ptr != nullptr); TokenType token_type; @@ -227,8 +227,7 @@ void DeviceTokenManager::register_device(tl_object_ptr devi return promise.set_error(Status::Error(400, "Device token must be encoded in UTF-8")); } for (auto &other_user_id : other_user_ids) { - UserId user_id(other_user_id); - if (!user_id.is_valid()) { + if (!other_user_id.is_valid()) { return promise.set_error(Status::Error(400, "Invalid user_id among other user_ids")); } } @@ -373,12 +372,12 @@ void DeviceTokenManager::loop() { auto other_user_ids = info.other_user_ids; if (info.state == TokenInfo::State::Unregister) { net_query = G()->net_query_creator().create( - telegram_api::account_unregisterDevice(token_type, info.token, std::move(other_user_ids))); + telegram_api::account_unregisterDevice(token_type, info.token, UserId::get_input_user_ids(other_user_ids))); } else { int32 flags = telegram_api::account_registerDevice::NO_MUTED_MASK; - net_query = G()->net_query_creator().create( - telegram_api::account_registerDevice(flags, false /*ignored*/, token_type, info.token, info.is_app_sandbox, - BufferSlice(info.encryption_key), std::move(other_user_ids))); + net_query = G()->net_query_creator().create(telegram_api::account_registerDevice( + flags, false /*ignored*/, token_type, info.token, info.is_app_sandbox, BufferSlice(info.encryption_key), + UserId::get_input_user_ids(other_user_ids))); } info.net_query_id = net_query->id(); G()->net_query_dispatcher().dispatch_with_callback(std::move(net_query), actor_shared(this, token_type)); diff --git a/td/telegram/DeviceTokenManager.h b/td/telegram/DeviceTokenManager.h index 76b728f9e..d8aa77b13 100644 --- a/td/telegram/DeviceTokenManager.h +++ b/td/telegram/DeviceTokenManager.h @@ -10,8 +10,8 @@ #include "td/actor/PromiseFuture.h" #include "td/telegram/net/NetQuery.h" - #include "td/telegram/td_api.h" +#include "td/telegram/UserId.h" #include "td/utils/common.h" #include "td/utils/Slice.h" @@ -26,7 +26,7 @@ class DeviceTokenManager : public NetQueryCallback { public: explicit DeviceTokenManager(ActorShared<> parent) : parent_(std::move(parent)) { } - void register_device(tl_object_ptr device_token_ptr, vector other_user_ids, + void register_device(tl_object_ptr device_token_ptr, vector other_user_ids, Promise> promise); void reregister_device(); @@ -55,7 +55,7 @@ class DeviceTokenManager : public NetQueryCallback { State state = State::Sync; string token; uint64 net_query_id = 0; - vector other_user_ids; + vector other_user_ids; bool is_app_sandbox = false; bool encrypt = false; string encryption_key; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index f35a8ebc2..725097909 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -1840,11 +1840,11 @@ class CreateNewGroupChatRequest : public RequestActor<> { } public: - CreateNewGroupChatRequest(ActorShared td, uint64 request_id, vector user_ids, string title) - : RequestActor(std::move(td), request_id), title_(std::move(title)), random_id_(0) { - for (auto user_id : user_ids) { - user_ids_.emplace_back(user_id); - } + CreateNewGroupChatRequest(ActorShared td, uint64 request_id, vector user_ids, string title) + : RequestActor(std::move(td), request_id) + , user_ids_(std::move(user_ids)) + , title_(std::move(title)) + , random_id_(0) { } }; @@ -2058,16 +2058,14 @@ class GetChatEventLogRequest : public RequestOnceActor { public: GetChatEventLogRequest(ActorShared td, uint64 request_id, int64 dialog_id, string &&query, int64 from_event_id, - int32 limit, tl_object_ptr &&filters, vector user_ids) + int32 limit, tl_object_ptr &&filters, vector user_ids) : RequestOnceActor(std::move(td), request_id) , dialog_id_(dialog_id) , query_(std::move(query)) , from_event_id_(from_event_id) , limit_(limit) - , filters_(std::move(filters)) { - for (auto user_id : user_ids) { - user_ids_.emplace_back(user_id); - } + , filters_(std::move(filters)) + , user_ids_(std::move(user_ids)) { } }; @@ -2152,11 +2150,8 @@ class RemoveContactsRequest : public RequestActor<> { } public: - RemoveContactsRequest(ActorShared td, uint64 request_id, vector &&user_ids) - : RequestActor(std::move(td), request_id) { - for (auto user_id : user_ids) { - user_ids_.emplace_back(user_id); - } + RemoveContactsRequest(ActorShared td, uint64 request_id, vector &&user_ids) + : RequestActor(std::move(td), request_id), user_ids_(std::move(user_ids)) { set_tries(3); // load_contacts + delete_contacts } }; @@ -4761,7 +4756,7 @@ void Td::on_request(uint64 id, td_api::registerUser &request) { void Td::on_request(uint64 id, td_api::requestQrCodeAuthentication &request) { send_closure(auth_manager_actor_, &AuthManager::request_qr_code_authentication, id, - std::move(request.other_user_ids_)); + UserId::get_user_ids(request.other_user_ids_)); } void Td::on_request(uint64 id, td_api::checkAuthenticationPassword &request) { @@ -4950,7 +4945,7 @@ void Td::on_request(uint64 id, td_api::registerDevice &request) { } CREATE_REQUEST_PROMISE(); send_closure(device_token_manager_, &DeviceTokenManager::register_device, std::move(request.device_token_), - std::move(request.other_user_ids_), std::move(promise)); + UserId::get_user_ids(request.other_user_ids_), std::move(promise)); } void Td::on_request(uint64 id, td_api::getUserPrivacySettingRules &request) { @@ -5881,7 +5876,7 @@ void Td::on_request(uint64 id, td_api::createSecretChat &request) { void Td::on_request(uint64 id, td_api::createNewBasicGroupChat &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.title_); - CREATE_REQUEST(CreateNewGroupChatRequest, request.user_ids_, std::move(request.title_)); + CREATE_REQUEST(CreateNewGroupChatRequest, UserId::get_user_ids(request.user_ids_), std::move(request.title_)); } void Td::on_request(uint64 id, td_api::createNewSupergroupChat &request) { @@ -6023,12 +6018,8 @@ void Td::on_request(uint64 id, const td_api::revokeGroupCallInviteLink &request) void Td::on_request(uint64 id, const td_api::inviteGroupCallParticipants &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - vector user_ids; - for (auto &user_id : request.user_ids_) { - user_ids.emplace_back(user_id); - } - group_call_manager_->invite_group_call_participants(GroupCallId(request.group_call_id_), std::move(user_ids), - std::move(promise)); + group_call_manager_->invite_group_call_participants(GroupCallId(request.group_call_id_), + UserId::get_user_ids(request.user_ids_), std::move(promise)); } void Td::on_request(uint64 id, const td_api::getGroupCallInviteLink &request) { @@ -6337,11 +6328,8 @@ void Td::on_request(uint64 id, const td_api::addChatMember &request) { void Td::on_request(uint64 id, const td_api::addChatMembers &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - vector user_ids; - for (auto &user_id : request.user_ids_) { - user_ids.emplace_back(user_id); - } - contacts_manager_->add_dialog_participants(DialogId(request.chat_id_), user_ids, std::move(promise)); + contacts_manager_->add_dialog_participants(DialogId(request.chat_id_), UserId::get_user_ids(request.user_ids_), + std::move(promise)); } void Td::on_request(uint64 id, td_api::setChatMemberStatus &request) { @@ -6488,7 +6476,7 @@ void Td::on_request(uint64 id, td_api::getChatEventLog &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.query_); CREATE_REQUEST(GetChatEventLogRequest, request.chat_id_, std::move(request.query_), request.from_event_id_, - request.limit_, std::move(request.filters_), std::move(request.user_ids_)); + request.limit_, std::move(request.filters_), UserId::get_user_ids(request.user_ids_)); } void Td::on_request(uint64 id, const td_api::clearAllDraftMessages &request) { @@ -6728,7 +6716,7 @@ void Td::on_request(uint64 id, td_api::searchContacts &request) { void Td::on_request(uint64 id, td_api::removeContacts &request) { CHECK_IS_USER(); - CREATE_REQUEST(RemoveContactsRequest, std::move(request.user_ids_)); + CREATE_REQUEST(RemoveContactsRequest, UserId::get_user_ids(request.user_ids_)); } void Td::on_request(uint64 id, const td_api::getImportedContactCount &request) { diff --git a/td/telegram/UserId.h b/td/telegram/UserId.h index 3e87c06ec..85bb74c75 100644 --- a/td/telegram/UserId.h +++ b/td/telegram/UserId.h @@ -25,6 +25,24 @@ class UserId { template ::value>> UserId(T user_id) = delete; + static vector get_user_ids(const vector &input_user_ids) { + vector user_ids; + user_ids.reserve(input_user_ids.size()); + for (auto &input_user_id : input_user_ids) { + user_ids.emplace_back(input_user_id); + } + return user_ids; + } + + static vector get_input_user_ids(const vector &user_ids) { + vector input_user_ids; + input_user_ids.reserve(user_ids.size()); + for (auto &user_id : user_ids) { + input_user_ids.emplace_back(user_id.get()); + } + return input_user_ids; + } + bool is_valid() const { return id > 0; } From f5ab187bb275aa9eedc211405a4619434956cd4f Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 01:34:33 +0300 Subject: [PATCH 136/281] Use UserId in PrivacyManager. --- td/telegram/PrivacyManager.cpp | 34 ++++++++++++++++++---------------- td/telegram/PrivacyManager.h | 7 ++++--- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/td/telegram/PrivacyManager.cpp b/td/telegram/PrivacyManager.cpp index 12f46cd50..399c292ab 100644 --- a/td/telegram/PrivacyManager.cpp +++ b/td/telegram/PrivacyManager.cpp @@ -185,7 +185,7 @@ PrivacyManager::UserPrivacySettingRule::UserPrivacySettingRule(const td_api::Use break; case td_api::userPrivacySettingRuleAllowUsers::ID: type_ = Type::AllowUsers; - user_ids_ = static_cast(rule).user_ids_; + user_ids_ = UserId::get_user_ids(static_cast(rule).user_ids_); break; case td_api::userPrivacySettingRuleAllowChatMembers::ID: type_ = Type::AllowChatParticipants; @@ -199,7 +199,8 @@ PrivacyManager::UserPrivacySettingRule::UserPrivacySettingRule(const td_api::Use break; case td_api::userPrivacySettingRuleRestrictUsers::ID: type_ = Type::RestrictUsers; - user_ids_ = static_cast(rule).user_ids_; + user_ids_ = + UserId::get_user_ids(static_cast(rule).user_ids_); break; case td_api::userPrivacySettingRuleRestrictChatMembers::ID: type_ = Type::RestrictChatParticipants; @@ -220,7 +221,7 @@ PrivacyManager::UserPrivacySettingRule::UserPrivacySettingRule(const telegram_ap break; case telegram_api::privacyValueAllowUsers::ID: type_ = Type::AllowUsers; - user_ids_ = static_cast(rule).users_; + user_ids_ = UserId::get_user_ids(static_cast(rule).users_); break; case telegram_api::privacyValueAllowChatParticipants::ID: type_ = Type::AllowChatParticipants; @@ -234,7 +235,7 @@ PrivacyManager::UserPrivacySettingRule::UserPrivacySettingRule(const telegram_ap break; case telegram_api::privacyValueDisallowUsers::ID: type_ = Type::RestrictUsers; - user_ids_ = static_cast(rule).users_; + user_ids_ = UserId::get_user_ids(static_cast(rule).users_); break; case telegram_api::privacyValueDisallowChatParticipants::ID: type_ = Type::RestrictChatParticipants; @@ -253,7 +254,7 @@ PrivacyManager::UserPrivacySettingRule::get_user_privacy_setting_rule_object() c case Type::AllowAll: return make_tl_object(); case Type::AllowUsers: - return make_tl_object(vector{user_ids_}); + return make_tl_object(UserId::get_input_user_ids(user_ids_)); case Type::AllowChatParticipants: return make_tl_object(chat_ids_as_dialog_ids()); case Type::RestrictContacts: @@ -261,7 +262,7 @@ PrivacyManager::UserPrivacySettingRule::get_user_privacy_setting_rule_object() c case Type::RestrictAll: return make_tl_object(); case Type::RestrictUsers: - return make_tl_object(vector{user_ids_}); + return make_tl_object(UserId::get_input_user_ids(user_ids_)); case Type::RestrictChatParticipants: return make_tl_object(chat_ids_as_dialog_ids()); default: @@ -298,7 +299,7 @@ Result PrivacyManager::UserPrivacySettin UserPrivacySettingRule result(*rule); auto td = G()->td().get_actor_unsafe(); for (auto user_id : result.user_ids_) { - if (!td->contacts_manager_->have_user(UserId(user_id))) { + if (!td->contacts_manager_->have_user(user_id)) { return Status::Error(500, "Got inaccessible user from the server"); } } @@ -320,7 +321,7 @@ Result PrivacyManager::UserPrivacySettin vector> PrivacyManager::UserPrivacySettingRule::get_input_users() const { vector> result; for (auto user_id : user_ids_) { - auto input_user = G()->td().get_actor_unsafe()->contacts_manager_->get_input_user(UserId(user_id)); + auto input_user = G()->td().get_actor_unsafe()->contacts_manager_->get_input_user(user_id); if (input_user != nullptr) { result.push_back(std::move(input_user)); } else { @@ -347,7 +348,7 @@ vector PrivacyManager::UserPrivacySettingRule::chat_ids_as_dialog_ids() c return result; } -vector PrivacyManager::UserPrivacySettingRule::get_restricted_user_ids() const { +vector PrivacyManager::UserPrivacySettingRule::get_restricted_user_ids() const { if (type_ == Type::RestrictUsers) { return user_ids_; } @@ -405,12 +406,13 @@ vector> PrivacyManager::UserPrivac return result; } -vector PrivacyManager::UserPrivacySettingRules::get_restricted_user_ids() const { - vector result; +vector PrivacyManager::UserPrivacySettingRules::get_restricted_user_ids() const { + vector result; for (auto &rule : rules_) { combine(result, rule.get_restricted_user_ids()); } - td::unique(result); + std::sort(result.begin(), result.end(), [](UserId lhs, UserId rhs) { return lhs.get() < rhs.get(); }); + result.erase(std::unique(result.begin(), result.end()), result.end()); return result; } @@ -530,12 +532,12 @@ void PrivacyManager::do_update_privacy(UserPrivacySetting user_privacy_setting, if (old_restricted != new_restricted) { // if a user was unrestricted, it is not received from the server anymore // we need to reget their online status manually - std::vector unrestricted; + std::vector unrestricted; std::set_difference(old_restricted.begin(), old_restricted.end(), new_restricted.begin(), - new_restricted.end(), std::back_inserter(unrestricted)); + new_restricted.end(), std::back_inserter(unrestricted), + [](UserId lhs, UserId rhs) { return lhs.get() < rhs.get(); }); for (auto &user_id : unrestricted) { - send_closure_later(G()->contacts_manager(), &ContactsManager::reload_user, UserId(user_id), - Promise()); + send_closure_later(G()->contacts_manager(), &ContactsManager::reload_user, user_id, Promise()); } } break; diff --git a/td/telegram/PrivacyManager.h b/td/telegram/PrivacyManager.h index 0fdc8f7b4..c6c0fbaf2 100644 --- a/td/telegram/PrivacyManager.h +++ b/td/telegram/PrivacyManager.h @@ -9,6 +9,7 @@ #include "td/telegram/net/NetQuery.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserId.h" #include "td/actor/actor.h" #include "td/actor/PromiseFuture.h" @@ -83,7 +84,7 @@ class PrivacyManager : public NetQueryCallback { return type_ == other.type_ && user_ids_ == other.user_ids_ && chat_ids_ == other.chat_ids_; } - vector get_restricted_user_ids() const; + vector get_restricted_user_ids() const; private: enum class Type : int32 { @@ -97,7 +98,7 @@ class PrivacyManager : public NetQueryCallback { RestrictChatParticipants } type_ = Type::RestrictAll; - vector user_ids_; + vector user_ids_; vector chat_ids_; vector> get_input_users() const; @@ -130,7 +131,7 @@ class PrivacyManager : public NetQueryCallback { return rules_ == other.rules_; } - vector get_restricted_user_ids() const; + vector get_restricted_user_ids() const; private: vector rules_; From b5655ddab617ad04e46e38c62da6b96cc00f94df Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 08:20:54 +0300 Subject: [PATCH 137/281] Pass UserId to Contact::Contact. --- td/telegram/Contact.cpp | 5 +++-- td/telegram/Contact.h | 2 +- td/telegram/ContactsManager.cpp | 5 +++-- td/telegram/InlineQueriesManager.cpp | 4 ++-- td/telegram/MessageContent.cpp | 11 ++++++----- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/td/telegram/Contact.cpp b/td/telegram/Contact.cpp index 2d34eab6d..f75af4567 100644 --- a/td/telegram/Contact.cpp +++ b/td/telegram/Contact.cpp @@ -17,7 +17,7 @@ namespace td { -Contact::Contact(string phone_number, string first_name, string last_name, string vcard, int32 user_id) +Contact::Contact(string phone_number, string first_name, string last_name, string vcard, UserId user_id) : phone_number_(std::move(phone_number)) , first_name_(std::move(first_name)) , last_name_(std::move(last_name)) @@ -96,7 +96,8 @@ Result process_input_message_contact(tl_object_ptrphone_number_, contact->first_name_, contact->last_name_, contact->vcard_, contact->user_id_); + return Contact(contact->phone_number_, contact->first_name_, contact->last_name_, contact->vcard_, + UserId(contact->user_id_)); } } // namespace td diff --git a/td/telegram/Contact.h b/td/telegram/Contact.h index bccf6591e..5617f1bb1 100644 --- a/td/telegram/Contact.h +++ b/td/telegram/Contact.h @@ -40,7 +40,7 @@ class Contact { public: Contact() = default; - Contact(string phone_number, string first_name, string last_name, string vcard, int32 user_id); + Contact(string phone_number, string first_name, string last_name, string vcard, UserId user_id); void set_user_id(UserId user_id); diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index dcf469108..ead891d52 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -5322,7 +5322,8 @@ std::pair, vector> ContactsManager::import_contacts( td_->create_handler(std::move(promise)) ->send(transform(contacts, [](const tl_object_ptr &contact) { - return Contact(contact->phone_number_, contact->first_name_, contact->last_name_, string(), 0); + return Contact(contact->phone_number_, contact->first_name_, contact->last_name_, string(), + UserId()); }), random_id); return {}; @@ -5512,7 +5513,7 @@ std::pair, vector> ContactsManager::change_imported_contac auto new_contacts = transform(std::move(contacts), [](tl_object_ptr &&contact) { return Contact(std::move(contact->phone_number_), std::move(contact->first_name_), std::move(contact->last_name_), - string(), 0); + string(), UserId()); }); vector new_contacts_unique_id(new_contacts.size()); diff --git a/td/telegram/InlineQueriesManager.cpp b/td/telegram/InlineQueriesManager.cpp index 759f84ce0..8a0cc3fe2 100644 --- a/td/telegram/InlineQueriesManager.cpp +++ b/td/telegram/InlineQueriesManager.cpp @@ -1423,10 +1423,10 @@ void InlineQueriesManager::on_get_inline_query_results(UserId bot_user_id, uint6 auto inline_message_contact = static_cast(result->send_message_.get()); Contact c(inline_message_contact->phone_number_, inline_message_contact->first_name_, - inline_message_contact->last_name_, inline_message_contact->vcard_, 0); + inline_message_contact->last_name_, inline_message_contact->vcard_, UserId()); contact->contact_ = c.get_contact_object(); } else { - Contact c(std::move(result->description_), std::move(result->title_), string(), string(), 0); + Contact c(std::move(result->description_), std::move(result->title_), string(), string(), UserId()); contact->contact_ = c.get_contact_object(); } contact->thumbnail_ = register_thumbnail(std::move(result->thumb_)); diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 5114b30bc..d134482bc 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -1514,7 +1514,7 @@ InlineMessageContent create_inline_message_content(Td *td, FileId file_id, auto inline_message_contact = move_tl_object_as(inline_message); result.message_content = make_unique( Contact(std::move(inline_message_contact->phone_number_), std::move(inline_message_contact->first_name_), - std::move(inline_message_contact->last_name_), std::move(inline_message_contact->vcard_), 0)); + std::move(inline_message_contact->last_name_), std::move(inline_message_contact->vcard_), UserId())); reply_markup = std::move(inline_message_contact->reply_markup_); break; } @@ -3915,7 +3915,7 @@ unique_ptr get_secret_message_content( } return make_unique( Contact(std::move(message_contact->phone_number_), std::move(message_contact->first_name_), - std::move(message_contact->last_name_), string(), message_contact->user_id_)); + std::move(message_contact->last_name_), string(), UserId(message_contact->user_id_))); } case secret_api::decryptedMessageMediaWebPage::ID: { auto media_web_page = move_tl_object_as(media); @@ -4082,9 +4082,10 @@ unique_ptr get_message_content(Td *td, FormattedText message, td->contacts_manager_->get_user_id_object(UserId(message_contact->user_id_), "MessageMediaContact"); // to ensure updateUser } - return make_unique(Contact( - std::move(message_contact->phone_number_), std::move(message_contact->first_name_), - std::move(message_contact->last_name_), std::move(message_contact->vcard_), message_contact->user_id_)); + return make_unique( + Contact(std::move(message_contact->phone_number_), std::move(message_contact->first_name_), + std::move(message_contact->last_name_), std::move(message_contact->vcard_), + UserId(message_contact->user_id_))); } case telegram_api::messageMediaDocument::ID: { auto message_document = move_tl_object_as(media); From 5de3751d8d970110c765d70d92d0b1a06deddb2b Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 11:28:43 +0300 Subject: [PATCH 138/281] Use int64 for sender_user_id in message database. --- td/telegram/MessagesDb.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/td/telegram/MessagesDb.cpp b/td/telegram/MessagesDb.cpp index 017f80719..ef09c26ad 100644 --- a/td/telegram/MessagesDb.cpp +++ b/td/telegram/MessagesDb.cpp @@ -114,7 +114,7 @@ Status init_messages_db(SqliteDb &db, int32 version) { LOG(INFO) << "Create new message database"; TRY_STATUS( db.exec("CREATE TABLE IF NOT EXISTS messages (dialog_id INT8, message_id INT8, unique_message_id INT4, " - "sender_user_id INT4, random_id INT8, data BLOB, ttl_expires_at INT4, index_mask INT4, search_id INT8, " + "sender_user_id INT8, random_id INT8, data BLOB, ttl_expires_at INT4, index_mask INT4, search_id INT8, " "text STRING, notification_id INT4, top_thread_message_id INT8, PRIMARY KEY (dialog_id, message_id))")); TRY_STATUS( @@ -297,7 +297,7 @@ class MessagesDbImpl : public MessagesDbSyncInterface { } if (sender_user_id.is_valid()) { - add_message_stmt_.bind_int32(4, sender_user_id.get()).ensure(); + add_message_stmt_.bind_int64(4, sender_user_id.get()).ensure(); } else { add_message_stmt_.bind_null(4).ensure(); } @@ -430,7 +430,7 @@ class MessagesDbImpl : public MessagesDbSyncInterface { delete_dialog_messages_from_user_stmt_.reset(); }; delete_dialog_messages_from_user_stmt_.bind_int64(1, dialog_id.get()).ensure(); - delete_dialog_messages_from_user_stmt_.bind_int32(2, sender_user_id.get()).ensure(); + delete_dialog_messages_from_user_stmt_.bind_int64(2, sender_user_id.get()).ensure(); delete_dialog_messages_from_user_stmt_.step().ensure(); return Status::OK(); } From c739df85071ed00de6cea311d7253dc41d9a2049 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 11:57:26 +0300 Subject: [PATCH 139/281] Pass UserId instead of int32 when creating secret chat. --- td/telegram/MessagesManager.cpp | 4 ++-- td/telegram/SecretChatActor.cpp | 6 +++--- td/telegram/SecretChatActor.h | 27 +++++++++++++------------- td/telegram/SecretChatsManager.cpp | 2 +- td/telegram/SecretChatsManager.h | 3 ++- td/telegram/logevent/SecretChatEvent.h | 13 ++++++++----- test/secret.cpp | 2 +- 7 files changed, 30 insertions(+), 27 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index f9fdbc800..a29a2196f 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -19334,8 +19334,8 @@ void MessagesManager::create_new_secret_chat(UserId user_id, Promise(user_base); - send_closure(G()->secret_chats_manager(), &SecretChatsManager::create_chat, user->user_id_, user->access_hash_, - std::move(promise)); + send_closure(G()->secret_chats_manager(), &SecretChatsManager::create_chat, UserId(user->user_id_), + user->access_hash_, std::move(promise)); } DialogId MessagesManager::migrate_dialog_to_megagroup(DialogId dialog_id, Promise &&promise) { diff --git a/td/telegram/SecretChatActor.cpp b/td/telegram/SecretChatActor.cpp index 8a7ee44a6..00c92e66d 100644 --- a/td/telegram/SecretChatActor.cpp +++ b/td/telegram/SecretChatActor.cpp @@ -83,7 +83,7 @@ void SecretChatActor::update_chat(telegram_api::object_ptr promise) { if (close_flag_) { promise.set_error(Status::Error(400, "Chat is closed")); @@ -826,7 +826,7 @@ void SecretChatActor::do_create_chat_impl(unique_ptr SecretChatActor::get_input_user() { - return telegram_api::make_object(auth_state_.user_id, auth_state_.user_access_hash); + return telegram_api::make_object(auth_state_.user_id.get(), auth_state_.user_access_hash); } telegram_api::object_ptr SecretChatActor::get_input_chat() { return telegram_api::make_object(auth_state_.id, auth_state_.access_hash); @@ -1869,7 +1869,7 @@ Status SecretChatActor::on_update_chat(telegram_api::encryptedChatRequested &upd } auth_state_.state = State::SendAccept; auth_state_.x = 1; - auth_state_.user_id = update.admin_id_; + auth_state_.user_id = UserId(update.admin_id_); auth_state_.date = context_->unix_time(); TRY_STATUS(save_common_info(update)); auth_state_.handshake.set_g_a(update.g_a_.as_slice()); diff --git a/td/telegram/SecretChatActor.h b/td/telegram/SecretChatActor.h index e3e29bdd5..c2a5e6747 100644 --- a/td/telegram/SecretChatActor.h +++ b/td/telegram/SecretChatActor.h @@ -6,15 +6,6 @@ // #pragma once -#include "td/telegram/secret_api.h" -#include "td/telegram/telegram_api.h" - -#include "td/actor/actor.h" -#include "td/actor/PromiseFuture.h" - -#include "td/mtproto/AuthKey.h" -#include "td/mtproto/DhHandshake.h" - #include "td/telegram/DhConfig.h" #include "td/telegram/FolderId.h" #include "td/telegram/logevent/SecretChatEvent.h" @@ -22,8 +13,16 @@ #include "td/telegram/net/NetQuery.h" #include "td/telegram/SecretChatDb.h" #include "td/telegram/SecretChatId.h" +#include "td/telegram/secret_api.h" +#include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" +#include "td/mtproto/AuthKey.h" +#include "td/mtproto/DhHandshake.h" + +#include "td/actor/actor.h" +#include "td/actor/PromiseFuture.h" + #include "td/utils/buffer.h" #include "td/utils/ChangesProcessor.h" #include "td/utils/common.h" @@ -115,7 +114,7 @@ class SecretChatActor : public NetQueryCallback { // First query to new chat must be one of these two void update_chat(telegram_api::object_ptr chat); - void create_chat(int32 user_id, int64 user_access_hash, int32 random_id, Promise promise); + void create_chat(UserId user_id, int64 user_access_hash, int32 random_id, Promise promise); void cancel_chat(bool delete_history, bool is_already_discarded, Promise<> promise); @@ -374,7 +373,7 @@ class SecretChatActor : public NetQueryCallback { int32 id = 0; int64 access_hash = 0; - int32 user_id = 0; + UserId user_id; int64 user_access_hash = 0; int32 random_id = 0; @@ -408,7 +407,7 @@ class SecretChatActor : public NetQueryCallback { storer.store_int(id); storer.store_long(access_hash); - storer.store_int(user_id); + storer.store_int(user_id.get()); storer.store_long(user_access_hash); storer.store_int(random_id); if (has_date) { @@ -439,7 +438,7 @@ class SecretChatActor : public NetQueryCallback { id = parser.fetch_int(); access_hash = parser.fetch_long(); - user_id = parser.fetch_int(); + user_id = UserId(parser.fetch_int()); user_access_hash = parser.fetch_long(); random_id = parser.fetch_int(); if (has_date) { @@ -701,7 +700,7 @@ class SecretChatActor : public NetQueryCallback { return SecretChatId(auth_state_.id); } UserId get_user_id() { - return UserId(auth_state_.user_id); + return auth_state_.user_id; } void send_update_ttl(int32 ttl); void send_update_secret_chat(); diff --git a/td/telegram/SecretChatsManager.cpp b/td/telegram/SecretChatsManager.cpp index db6d0a28e..00560d89d 100644 --- a/td/telegram/SecretChatsManager.cpp +++ b/td/telegram/SecretChatsManager.cpp @@ -96,7 +96,7 @@ void SecretChatsManager::start_up() { send_closure(G()->state_manager(), &StateManager::add_callback, make_unique(actor_id(this))); } -void SecretChatsManager::create_chat(int32 user_id, int64 user_access_hash, Promise promise) { +void SecretChatsManager::create_chat(UserId user_id, int64 user_access_hash, Promise promise) { int32 random_id; ActorId actor; do { diff --git a/td/telegram/SecretChatsManager.h b/td/telegram/SecretChatsManager.h index 04bf59870..81ece46d2 100644 --- a/td/telegram/SecretChatsManager.h +++ b/td/telegram/SecretChatsManager.h @@ -9,6 +9,7 @@ #include "td/telegram/logevent/SecretChatEvent.h" #include "td/telegram/SecretChatActor.h" #include "td/telegram/SecretChatId.h" +#include "td/telegram/UserId.h" #include "td/telegram/secret_api.h" #include "td/telegram/telegram_api.h" @@ -34,7 +35,7 @@ class SecretChatsManager : public Actor { void on_update_chat(tl_object_ptr update); void on_new_message(tl_object_ptr &&message_ptr, Promise &&promise); - void create_chat(int32 user_id, int64 user_access_hash, Promise promise); + void create_chat(UserId user_id, int64 user_access_hash, Promise promise); void cancel_chat(SecretChatId secret_chat_id, bool delete_history, Promise<> promise); void send_message(SecretChatId secret_chat_id, tl_object_ptr message, tl_object_ptr file, Promise<> promise); diff --git a/td/telegram/logevent/SecretChatEvent.h b/td/telegram/logevent/SecretChatEvent.h index 2c8f241f2..66178d469 100644 --- a/td/telegram/logevent/SecretChatEvent.h +++ b/td/telegram/logevent/SecretChatEvent.h @@ -18,6 +18,7 @@ #include "td/telegram/secret_api.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserId.h" namespace td { namespace log_event { @@ -445,14 +446,14 @@ class CreateSecretChat : public SecretChatLogEventBase { public: static constexpr Type type = SecretChatEvent::Type::CreateSecretChat; int32 random_id = 0; - int32 user_id = 0; + UserId user_id; int64 user_access_hash = 0; template void store(StorerT &storer) const { using td::store; store(random_id, storer); - store(user_id, storer); + store(user_id.get(), storer); store(user_access_hash, storer); } @@ -460,13 +461,15 @@ class CreateSecretChat : public SecretChatLogEventBase { void parse(ParserT &parser) { using td::parse; parse(random_id, parser); - parse(user_id, parser); + int32 legacy_user_id; + parse(legacy_user_id, parser); + user_id = UserId(legacy_user_id); parse(user_access_hash, parser); } StringBuilder &print(StringBuilder &sb) const override { - return sb << "[Logevent CreateSecretChat " << tag("id", log_event_id()) << tag("chat_id", random_id) - << tag("user_id", user_id) << "]"; + return sb << "[Logevent CreateSecretChat " << tag("id", log_event_id()) << tag("chat_id", random_id) << user_id + << "]"; } }; diff --git a/test/secret.cpp b/test/secret.cpp index b9d91108b..6f7779e84 100644 --- a/test/secret.cpp +++ b/test/secret.cpp @@ -765,7 +765,7 @@ class Master : public Actor { auto old_context = set_context(std::make_shared()); alice_ = create_actor("SecretChatProxy alice", "alice", actor_shared(this, 1)); bob_ = create_actor("SecretChatProxy bob", "bob", actor_shared(this, 2)); - send_closure(alice_->get_actor_unsafe()->actor_, &SecretChatActor::create_chat, 2, 0, 123, + send_closure(alice_->get_actor_unsafe()->actor_, &SecretChatActor::create_chat, UserId(2), 0, 123, PromiseCreator::lambda([actor_id = actor_id(this)](Result res) { send_closure(actor_id, &Master::got_secret_chat_id, std::move(res), 0); })); From 66a58daf700b739829d4a7a51e561d61ce678903 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Mon, 29 Mar 2021 14:04:37 +0200 Subject: [PATCH 140/281] Fix segmentation fault --- td/telegram/GroupCallManager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 64034b581..13c6c2b8e 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1439,7 +1439,13 @@ void GroupCallManager::on_update_group_call_participants( int32 diff = 0; bool need_update = false; auto group_call = get_group_call(input_group_call_id); + if (group_call == nullptr) { + return; + } for (auto &group_call_participant : participants) { + if (group_call_participant == nullptr) { + continue; + } GroupCallParticipant participant(group_call_participant, version); if (!participant.is_valid()) { LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); From 079c9919d2f892db81d328abec57f54464d4a78d Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 16:23:50 +0300 Subject: [PATCH 141/281] Parse push_receiver_id as int64. --- td/telegram/NotificationManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/telegram/NotificationManager.cpp b/td/telegram/NotificationManager.cpp index 6c79a6a95..d6d942d7a 100644 --- a/td/telegram/NotificationManager.cpp +++ b/td/telegram/NotificationManager.cpp @@ -3821,7 +3821,7 @@ Result NotificationManager::get_push_receiver_id(string payload) { return Status::Error(400, "Expected user_id as a String or a Number"); } Slice user_id_str = user_id.type() == JsonValue::Type::String ? user_id.get_string() : user_id.get_number(); - auto r_user_id = to_integer_safe(user_id_str); + auto r_user_id = to_integer_safe(user_id_str); if (r_user_id.is_error()) { return Status::Error(400, PSLICE() << "Failed to get user_id from " << user_id_str); } From a51b63afddf45648c681359770c84ee77f4bfe5e Mon Sep 17 00:00:00 2001 From: Arseny Smirnov Date: Sat, 27 Mar 2021 11:02:32 +0300 Subject: [PATCH 142/281] more checks for watch os version --- tdnet/td/net/Wget.cpp | 3 +++ tdutils/td/utils/port/SocketFd.cpp | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/tdnet/td/net/Wget.cpp b/tdnet/td/net/Wget.cpp index a6723ec43..7f961e3a6 100644 --- a/tdnet/td/net/Wget.cpp +++ b/tdnet/td/net/Wget.cpp @@ -74,6 +74,9 @@ Status Wget::try_init() { TRY_STATUS(addr.init_host_port(url.host_, url.port_, prefer_ipv6_)); TRY_RESULT(fd, SocketFd::open(addr)); + if (fd.empty()) { + return td::Status::Error("Sockets are not supported"); + } if (url.protocol_ == HttpUrl::Protocol::Http) { connection_ = create_actor("Connect", std::move(fd), SslStream{}, std::numeric_limits::max(), 0, 0, diff --git a/tdutils/td/utils/port/SocketFd.cpp b/tdutils/td/utils/port/SocketFd.cpp index a29070859..05e6aee4b 100644 --- a/tdutils/td/utils/port/SocketFd.cpp +++ b/tdutils/td/utils/port/SocketFd.cpp @@ -629,29 +629,36 @@ bool SocketFd::empty() const { } PollableFdInfo &SocketFd::get_poll_info() { + CHECK(!empty()); return impl_->get_poll_info(); } const PollableFdInfo &SocketFd::get_poll_info() const { + CHECK(!empty()); return impl_->get_poll_info(); } const NativeFd &SocketFd::get_native_fd() const { + CHECK(!empty()); return impl_->get_native_fd(); } Status SocketFd::get_pending_error() { + CHECK(!empty()); return impl_->get_pending_error(); } Result SocketFd::write(Slice slice) { + CHECK(!empty()); return impl_->write(slice); } Result SocketFd::writev(Span slices) { + CHECK(!empty()); return impl_->writev(slices); } Result SocketFd::read(MutableSlice slice) { + CHECK(!empty()); return impl_->read(slice); } From ad495c0d0c57554d6466cfcf028bb6ce106aaf3f Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 18:10:16 +0300 Subject: [PATCH 143/281] Skip error logging for deleted bots. --- td/telegram/ContactsManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index ead891d52..e761768fc 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -11565,7 +11565,7 @@ void ContactsManager::on_get_channel_participants( (filter.is_contacts() && !is_user_contact(participant.user_id)) || (filter.is_restricted() && !participant.status.is_restricted()) || (filter.is_banned() && !participant.status.is_banned())) { - bool skip_error = (filter.is_administrators() && is_user_deleted(participant.user_id)) || + bool skip_error = ((filter.is_administrators() || filter.is_bots()) && is_user_deleted(participant.user_id)) || (filter.is_contacts() && participant.user_id == get_my_id()); if (!skip_error) { LOG(ERROR) << "Receive " << participant << ", while searching for " << filter << " in " << channel_id From 732193b346d6a6276c557fd356688f261a3a9cfd Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 20:52:59 +0300 Subject: [PATCH 144/281] Fix default last_new_message_id in secret chats, broken in 9948e41aed13c5b0e403eeea49efb7546eba4c82. --- td/telegram/MessagesManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index a29a2196f..23a8077dd 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -33851,9 +33851,9 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&d, break; } case DialogType::SecretChat: - if (!d->last_new_message_id.is_valid()) { + if (d->last_new_message_id.get() <= MessageId::min().get()) { LOG(INFO) << "Set " << d->dialog_id << " last new message in add_new_dialog"; - d->last_new_message_id = MessageId::min(); + d->last_new_message_id = MessageId::min().get_next_message_id(MessageType::Local); } if (!d->notification_settings.is_secret_chat_show_preview_fixed) { From 224b560c830433aa315801272b47ea852f395a95 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 21:26:31 +0300 Subject: [PATCH 145/281] Improve error message on access to a closed secret chat. --- td/telegram/SecretChatActor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/telegram/SecretChatActor.cpp b/td/telegram/SecretChatActor.cpp index 00c92e66d..048bc1669 100644 --- a/td/telegram/SecretChatActor.cpp +++ b/td/telegram/SecretChatActor.cpp @@ -1963,7 +1963,7 @@ void SecretChatActor::start_up() { auth_state_ = r_auth_state.move_as_ok(); } if (!can_be_empty_ && auth_state_.state == State::Empty) { - LOG(WARNING) << "Close Secret chat because it is empty"; + LOG(INFO) << "Skip creation of empty secret chat " << auth_state_.id; return stop(); } if (auth_state_.state == State::Closed) { From 290293766f6d06be77c5eed0bc6b4f5e7fe2e5ef Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 21:43:50 +0300 Subject: [PATCH 146/281] Improve error message. --- td/telegram/NotificationManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/td/telegram/NotificationManager.cpp b/td/telegram/NotificationManager.cpp index d6d942d7a..82e5ca570 100644 --- a/td/telegram/NotificationManager.cpp +++ b/td/telegram/NotificationManager.cpp @@ -1858,7 +1858,9 @@ void NotificationManager::remove_notification(NotificationGroupId group_id, Noti bool is_total_count_changed = false; if ((!have_all_notifications && is_permanent) || (have_all_notifications && is_found)) { if (group_it->second.total_count == 0) { - LOG(ERROR) << "Total notification count became negative in " << group_id << " after removing " << notification_id; + LOG(ERROR) << "Total notification count became negative in " << group_it->second << " after removing " + << notification_id << " with is_permanent = " << is_permanent << ", is_found = " << is_found + << ", force_update = " << force_update << " from " << source; } else { group_it->second.total_count--; is_total_count_changed = true; From 955ce5f946ee19342bd670271bb1291526170678 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 22:25:06 +0300 Subject: [PATCH 147/281] Improve error message. --- td/telegram/MessagesManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 23a8077dd..17645ce1f 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -31854,7 +31854,7 @@ MessagesManager::Message *MessagesManager::on_get_message_from_database(DialogId Dependencies dependencies; add_message_dependencies(dependencies, d->dialog_id, m.get()); - resolve_dependencies_force(td_, dependencies, "get_message"); + resolve_dependencies_force(td_, dependencies, "on_get_message_from_database"); m->have_previous = false; m->have_next = false; @@ -34558,7 +34558,8 @@ bool MessagesManager::set_dialog_order(Dialog *d, int64 new_order, bool need_sen } auto folder_ptr = get_dialog_folder(d->folder_id); - CHECK(folder_ptr != nullptr); + LOG_CHECK(folder_ptr != nullptr) << dialog_id << ' ' << d->folder_id << ' ' << is_loaded_from_database << ' ' + << source; auto &folder = *folder_ptr; if (old_date == new_date) { if (new_order == DEFAULT_ORDER) { From 13a80bc4e8949ffb773dfe6054ead0a09d95fdec Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Mar 2021 22:35:27 +0300 Subject: [PATCH 148/281] Use send_closure_later to avoid cycles in add_message_to_dialog. --- td/telegram/ContactsManager.cpp | 22 +++++++++++++--------- td/telegram/ContactsManager.h | 2 +- td/telegram/MessagesManager.cpp | 12 ++++++------ 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index e761768fc..943f9f38d 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -9567,7 +9567,8 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s td_->group_call_manager_->on_update_dialog_about(DialogId(channel_id), channel_full->description, false); - td_->messages_manager_->on_dialog_bots_updated(DialogId(channel_id), channel_full->bot_user_ids, true); + send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id), + channel_full->bot_user_ids, true); update_channel_full(channel_full, channel_id, true); @@ -9960,7 +9961,8 @@ void ContactsManager::update_chat_full(ChatFull *chat_full, ChatId chat_id, bool } on_update_dialog_administrators(DialogId(chat_id), std::move(administrators), chat_full->version != -1, from_database); - td_->messages_manager_->on_dialog_bots_updated(DialogId(chat_id), std::move(bot_user_ids), from_database); + send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(chat_id), + std::move(bot_user_ids), from_database); { Chat *c = get_chat(chat_id); @@ -11735,7 +11737,7 @@ void ContactsManager::speculative_add_channel_participants(ChannelId channel_id, return; } - speculative_add_channel_participants(channel_id, delta_participant_count, by_me); + speculative_add_channel_participant_count(channel_id, delta_participant_count, by_me); } void ContactsManager::speculative_delete_channel_participant(ChannelId channel_id, UserId deleted_user_id, bool by_me) { @@ -11763,18 +11765,18 @@ void ContactsManager::speculative_delete_channel_participant(ChannelId channel_i } } - speculative_add_channel_participants(channel_id, -1, by_me); + speculative_add_channel_participant_count(channel_id, -1, by_me); } -void ContactsManager::speculative_add_channel_participants(ChannelId channel_id, int32 delta_participant_count, - bool by_me) { +void ContactsManager::speculative_add_channel_participant_count(ChannelId channel_id, int32 delta_participant_count, + bool by_me) { if (by_me) { // Currently ignore all changes made by the current user, because they may be already counted invalidate_channel_full(channel_id, false); // just in case return; } - auto channel_full = get_channel_full_force(channel_id, "speculative_add_channel_participants"); + auto channel_full = get_channel_full_force(channel_id, "speculative_add_channel_participant_count"); auto min_count = channel_full == nullptr ? 0 : channel_full->administrator_count; auto c = get_channel_force(channel_id); @@ -13083,7 +13085,8 @@ void ContactsManager::on_update_channel_bot_user_ids(ChannelId channel_id, vecto auto channel_full = get_channel_full_force(channel_id, "on_update_channel_bot_user_ids"); if (channel_full == nullptr) { - td_->messages_manager_->on_dialog_bots_updated(DialogId(channel_id), std::move(bot_user_ids), false); + send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id), + std::move(bot_user_ids), false); return; } on_update_channel_full_bot_user_ids(channel_full, channel_id, std::move(bot_user_ids)); @@ -13094,7 +13097,8 @@ void ContactsManager::on_update_channel_full_bot_user_ids(ChannelFull *channel_f vector &&bot_user_ids) { CHECK(channel_full != nullptr); if (channel_full->bot_user_ids != bot_user_ids) { - td_->messages_manager_->on_dialog_bots_updated(DialogId(channel_id), bot_user_ids, false); + send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id), + bot_user_ids, false); channel_full->bot_user_ids = std::move(bot_user_ids); channel_full->need_save_to_database = true; } diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index b620da9bc..5d7fbaf1f 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -1250,7 +1250,7 @@ class ContactsManager : public Actor { static bool speculative_add_count(int32 &count, int32 delta_count, int32 min_count = 0); - void speculative_add_channel_participants(ChannelId channel_id, int32 delta_participant_count, bool by_me); + void speculative_add_channel_participant_count(ChannelId channel_id, int32 delta_participant_count, bool by_me); void speculative_add_channel_user(ChannelId channel_id, UserId user_id, DialogParticipantStatus new_status, DialogParticipantStatus old_status); diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 17645ce1f..ecaeeb3c4 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -35979,16 +35979,16 @@ void MessagesManager::speculatively_update_channel_participants(DialogId dialog_ bool by_me = m->sender_user_id == my_user_id; switch (m->content->get_type()) { case MessageContentType::ChatAddUsers: - td_->contacts_manager_->speculative_add_channel_participants( - channel_id, get_message_content_added_user_ids(m->content.get()), m->sender_user_id, m->date, by_me); + send_closure_later(G()->contacts_manager(), &ContactsManager::speculative_add_channel_participants, channel_id, + get_message_content_added_user_ids(m->content.get()), m->sender_user_id, m->date, by_me); break; case MessageContentType::ChatJoinedByLink: - td_->contacts_manager_->speculative_add_channel_participants(channel_id, {m->sender_user_id}, m->sender_user_id, - m->date, by_me); + send_closure_later(G()->contacts_manager(), &ContactsManager::speculative_add_channel_participants, channel_id, + vector{m->sender_user_id}, m->sender_user_id, m->date, by_me); break; case MessageContentType::ChatDeleteUser: - td_->contacts_manager_->speculative_delete_channel_participant( - channel_id, get_message_content_deleted_user_id(m->content.get()), by_me); + send_closure_later(G()->contacts_manager(), &ContactsManager::speculative_delete_channel_participant, channel_id, + get_message_content_deleted_user_id(m->content.get()), by_me); break; default: break; From 17e8860855abab3d7774b5f72df9d73b58432327 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 30 Mar 2021 17:18:08 +0300 Subject: [PATCH 149/281] Add paymentForm.id. --- td/generate/scheme/td_api.tl | 9 +++++---- td/telegram/MessagesManager.cpp | 8 ++++---- td/telegram/MessagesManager.h | 4 ++-- td/telegram/Payments.cpp | 16 +++++++++------- td/telegram/Payments.h | 5 +++-- td/telegram/Td.cpp | 4 ++-- td/telegram/cli.cpp | 10 ++++++---- 7 files changed, 31 insertions(+), 25 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index e938257a1..1b1bfd68a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -1341,9 +1341,9 @@ inputCredentialsGooglePay data:string = InputCredentials; //@description Stripe payment provider @publishable_key Stripe API publishable key @need_country True, if the user country must be provided @need_postal_code True, if the user ZIP/postal code must be provided @need_cardholder_name True, if the cardholder name must be provided paymentsProviderStripe publishable_key:string need_country:Bool need_postal_code:Bool need_cardholder_name:Bool = PaymentsProviderStripe; -//@description Contains information about an invoice payment form @invoice Full information of the invoice @url Payment form URL @payments_provider Contains information about the payment provider, if available, to support it natively without the need for opening the URL; may be null +//@description Contains information about an invoice payment form @id The payment form identifier @invoice Full information of the invoice @url Payment form URL @payments_provider Contains information about the payment provider, if available, to support it natively without the need for opening the URL; may be null //@saved_order_info Saved server-side order information; may be null @saved_credentials Contains information about saved card credentials; may be null @can_save_credentials True, if the user can choose to save credentials @need_password True, if the user will be able to save credentials protected by a password they set up -paymentForm invoice:invoice url:string payments_provider:paymentsProviderStripe saved_order_info:orderInfo saved_credentials:savedCredentials can_save_credentials:Bool need_password:Bool = PaymentForm; +paymentForm id:int64 invoice:invoice url:string payments_provider:paymentsProviderStripe saved_order_info:orderInfo saved_credentials:savedCredentials can_save_credentials:Bool need_password:Bool = PaymentForm; //@description Contains a temporary identifier of validated order information, which is stored for one hour. Also contains the available shipping options @order_info_id Temporary identifier of the order information @shipping_options Available shipping options validatedOrderInfo order_info_id:string shipping_options:vector = ValidatedOrderInfo; @@ -4888,9 +4888,10 @@ getPaymentForm chat_id:int53 message_id:int53 = PaymentForm; //@description Validates the order information provided by a user and returns the available shipping options for a flexible invoice @chat_id Chat identifier of the Invoice message @message_id Message identifier @order_info The order information, provided by the user @allow_save True, if the order information can be saved validateOrderInfo chat_id:int53 message_id:int53 order_info:orderInfo allow_save:Bool = ValidatedOrderInfo; -//@description Sends a filled-out payment form to the bot for final verification @chat_id Chat identifier of the Invoice message @message_id Message identifier @order_info_id Identifier returned by ValidateOrderInfo, or an empty string @shipping_option_id Identifier of a chosen shipping option, if applicable +//@description Sends a filled-out payment form to the bot for final verification @chat_id Chat identifier of the Invoice message @message_id Message identifier +//@payment_form_id Payment form identifier returned by getPaymentForm @order_info_id Identifier returned by validateOrderInfo, or an empty string @shipping_option_id Identifier of a chosen shipping option, if applicable //@credentials The credentials chosen by user for payment -sendPaymentForm chat_id:int53 message_id:int53 order_info_id:string shipping_option_id:string credentials:InputCredentials = PaymentResult; +sendPaymentForm chat_id:int53 message_id:int53 payment_form_id:int64 order_info_id:string shipping_option_id:string credentials:InputCredentials = PaymentResult; //@description Returns information about a successful payment @chat_id Chat identifier of the PaymentSuccessful message @message_id Message identifier getPaymentReceipt chat_id:int53 message_id:int53 = PaymentReceipt; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 64ba102d7..6716a8ffe 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -37389,8 +37389,8 @@ void MessagesManager::validate_order_info(FullMessageId full_message_id, tl_obje std::move(promise)); } -void MessagesManager::send_payment_form(FullMessageId full_message_id, const string &order_info_id, - const string &shipping_option_id, +void MessagesManager::send_payment_form(FullMessageId full_message_id, int64 payment_form_id, + const string &order_info_id, const string &shipping_option_id, const tl_object_ptr &credentials, Promise> &&promise) { auto r_message_id = get_invoice_message_id(full_message_id); @@ -37398,8 +37398,8 @@ void MessagesManager::send_payment_form(FullMessageId full_message_id, const str return promise.set_error(r_message_id.move_as_error()); } - ::td::send_payment_form(full_message_id.get_dialog_id(), r_message_id.ok(), order_info_id, shipping_option_id, - credentials, std::move(promise)); + ::td::send_payment_form(full_message_id.get_dialog_id(), r_message_id.ok(), payment_form_id, order_info_id, + shipping_option_id, credentials, std::move(promise)); } void MessagesManager::get_payment_receipt(FullMessageId full_message_id, diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 693790421..24a2d635b 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -916,8 +916,8 @@ class MessagesManager : public Actor { void validate_order_info(FullMessageId full_message_id, tl_object_ptr order_info, bool allow_save, Promise> &&promise); - void send_payment_form(FullMessageId full_message_id, const string &order_info_id, const string &shipping_option_id, - const tl_object_ptr &credentials, + void send_payment_form(FullMessageId full_message_id, int64 payment_form_id, const string &order_info_id, + const string &shipping_option_id, const tl_object_ptr &credentials, Promise> &&promise); void get_payment_receipt(FullMessageId full_message_id, Promise> &&promise); diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 08142dc44..b56af5cbb 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -288,7 +288,7 @@ class GetPaymentFormQuery : public Td::ResultHandler { (payment_form->flags_ & telegram_api::payments_paymentForm::CAN_SAVE_CREDENTIALS_MASK) != 0; bool need_password = (payment_form->flags_ & telegram_api::payments_paymentForm::PASSWORD_MISSING_MASK) != 0; promise_.set_value(make_tl_object( - convert_invoice(std::move(payment_form->invoice_)), std::move(payment_form->url_), + payment_form->form_id_, convert_invoice(std::move(payment_form->invoice_)), std::move(payment_form->url_), convert_payment_provider(payment_form->native_provider_, std::move(payment_form->native_params_)), convert_order_info(std::move(payment_form->saved_info_)), convert_saved_credentials(std::move(payment_form->saved_credentials_)), can_save_credentials, need_password)); @@ -358,7 +358,7 @@ class SendPaymentFormQuery : public Td::ResultHandler { : promise_(std::move(promise)) { } - void send(DialogId dialog_id, ServerMessageId server_message_id, const string &order_info_id, + void send(DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, const string &order_info_id, const string &shipping_option_id, tl_object_ptr input_credentials) { CHECK(input_credentials != nullptr); @@ -376,8 +376,8 @@ class SendPaymentFormQuery : public Td::ResultHandler { flags |= telegram_api::payments_sendPaymentForm::SHIPPING_OPTION_ID_MASK; } send_query(G()->net_query_creator().create( - telegram_api::payments_sendPaymentForm(flags, 0, std::move(input_peer), server_message_id.get(), order_info_id, - shipping_option_id, std::move(input_credentials), 0))); + telegram_api::payments_sendPaymentForm(flags, payment_form_id, std::move(input_peer), server_message_id.get(), + order_info_id, shipping_option_id, std::move(input_credentials), 0))); } void on_result(uint64 id, BufferSlice packet) override { @@ -871,8 +871,9 @@ void validate_order_info(DialogId dialog_id, ServerMessageId server_message_id, ->send(dialog_id, server_message_id, convert_order_info(std::move(order_info)), allow_save); } -void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, const string &order_info_id, - const string &shipping_option_id, const tl_object_ptr &credentials, +void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, + const string &order_info_id, const string &shipping_option_id, + const tl_object_ptr &credentials, Promise> &&promise) { CHECK(credentials != nullptr); @@ -924,7 +925,8 @@ void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, co G()->td() .get_actor_unsafe() ->create_handler(std::move(promise)) - ->send(dialog_id, server_message_id, order_info_id, shipping_option_id, std::move(input_credentials)); + ->send(dialog_id, server_message_id, payment_form_id, order_info_id, shipping_option_id, + std::move(input_credentials)); } void get_payment_receipt(DialogId dialog_id, ServerMessageId server_message_id, diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index ab30e4d16..200a4491f 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -145,8 +145,9 @@ void validate_order_info(DialogId dialog_id, ServerMessageId server_message_id, tl_object_ptr order_info, bool allow_save, Promise> &&promise); -void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, const string &order_info_id, - const string &shipping_option_id, const tl_object_ptr &credentials, +void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, + const string &order_info_id, const string &shipping_option_id, + const tl_object_ptr &credentials, Promise> &&promise); void get_payment_receipt(DialogId dialog_id, ServerMessageId server_message_id, diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 565bd5449..27430095a 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -7733,8 +7733,8 @@ void Td::on_request(uint64 id, td_api::sendPaymentForm &request) { } CREATE_REQUEST_PROMISE(); messages_manager_->send_payment_form({DialogId(request.chat_id_), MessageId(request.message_id_)}, - request.order_info_id_, request.shipping_option_id_, request.credentials_, - std::move(promise)); + request.payment_form_id_, request.order_info_id_, request.shipping_option_id_, + request.credentials_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::getPaymentReceipt &request) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index dba8ea74d..96905d0e9 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1839,22 +1839,24 @@ class CliClient final : public Actor { } else if (op == "spfs") { string chat_id; string message_id; + int64 payment_form_id; string order_info_id; string shipping_option_id; string saved_credentials_id; - get_args(args, chat_id, message_id, order_info_id, shipping_option_id, saved_credentials_id); + get_args(args, chat_id, message_id, payment_form_id, order_info_id, shipping_option_id, saved_credentials_id); send_request(td_api::make_object( - as_chat_id(chat_id), as_message_id(message_id), order_info_id, shipping_option_id, + as_chat_id(chat_id), as_message_id(message_id), payment_form_id, order_info_id, shipping_option_id, td_api::make_object(saved_credentials_id))); } else if (op == "spfn") { string chat_id; string message_id; + int64 payment_form_id; string order_info_id; string shipping_option_id; string data; - get_args(args, chat_id, message_id, order_info_id, shipping_option_id, data); + get_args(args, chat_id, message_id, payment_form_id, order_info_id, shipping_option_id, data); send_request(td_api::make_object( - as_chat_id(chat_id), as_message_id(message_id), order_info_id, shipping_option_id, + as_chat_id(chat_id), as_message_id(message_id), payment_form_id, order_info_id, shipping_option_id, td_api::make_object(data, true))); } else if (op == "gpre") { string chat_id; From c3ff8539dbe7e906eb8bd2e05739f5f5b634fb1f Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 30 Mar 2021 18:05:20 +0300 Subject: [PATCH 150/281] Support tip amount in Invoice. --- td/generate/scheme/td_api.tl | 29 ++++++++++++++++------------- td/telegram/MessageContent.cpp | 19 +++++++++++++++++-- td/telegram/Payments.cpp | 14 +++++++++----- td/telegram/Payments.h | 2 ++ td/telegram/Payments.hpp | 12 ++++++++++++ 5 files changed, 56 insertions(+), 20 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 1b1bfd68a..7a3f6b021 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -552,7 +552,7 @@ supergroupMembersFilterBots = SupergroupMembersFilter; //@date Point in time (Unix timestamp) when the link was created //@edit_date Point in time (Unix timestamp) when the link was last edited; 0 if never or unknown //@expire_date Point in time (Unix timestamp) when the link will expire; 0 if never -//@member_limit Maximum number of members, which can join the chat using the link simultaneously; 0 if not limited +//@member_limit The maximum number of members, which can join the chat using the link simultaneously; 0 if not limited //@member_count Number of chat members, which joined the chat using the link //@is_primary True, if the link is primary. Primary invite link can't have expire date or usage limit. There is exactly one primary invite link for each administrator with can_invite_users right at a given time //@is_revoked True, if the link was revoked @@ -1306,14 +1306,17 @@ bankCardInfo title:string actions:vector = BankCardInfo; address country_code:string state:string city:string street_line1:string street_line2:string postal_code:string = Address; -//@description Portion of the price of a product (e.g., "delivery cost", "tax amount") @label Label for this portion of the product price @amount Currency amount in minimal quantity of the currency +//@description Portion of the price of a product (e.g., "delivery cost", "tax amount") @label Label for this portion of the product price @amount Currency amount in the smallest units of the currency labeledPricePart label:string amount:int53 = LabeledPricePart; -//@description Product invoice @currency ISO 4217 currency code @price_parts A list of objects used to calculate the total price of the product @is_test True, if the payment is a test payment +//@description Product invoice @currency ISO 4217 currency code @price_parts A list of objects used to calculate the total price of the product +//@max_tip_amount The maximum allowed amount of tip in the smallest units of the currency +//@suggested_tip_amounts Suggested amounts of tip in the smallest units of the currency +//@is_test True, if the payment is a test payment //@need_name True, if the user's name is needed for payment @need_phone_number True, if the user's phone number is needed for payment @need_email_address True, if the user's email address is needed for payment //@need_shipping_address True, if the user's shipping address is needed for payment @send_phone_number_to_provider True, if the user's phone number will be sent to the provider //@send_email_address_to_provider True, if the user's email address will be sent to the provider @is_flexible True, if the total price depends on the shipping method -invoice currency:string price_parts:vector is_test:Bool need_name:Bool need_phone_number:Bool need_email_address:Bool need_shipping_address:Bool send_phone_number_to_provider:Bool send_email_address_to_provider:Bool is_flexible:Bool = Invoice; +invoice currency:string price_parts:vector max_tip_amount:int53 suggested_tip_amounts:vector is_test:Bool need_name:Bool need_phone_number:Bool need_email_address:Bool need_shipping_address:Bool send_phone_number_to_provider:Bool send_email_address_to_provider:Bool is_flexible:Bool = Invoice; //@description Order information @name Name of the user @phone_number Phone number of the user @email_address Email address of the user @shipping_address Shipping address for this order; may be null orderInfo name:string phone_number:string email_address:string shipping_address:address = OrderInfo; @@ -1667,7 +1670,7 @@ messageGame game:game = MessageContent; //@description A message with a poll @poll The poll description messagePoll poll:poll = MessageContent; -//@description A message with an invoice from a bot @title Product title @param_description Product description @photo Product photo; may be null @currency Currency for the product price @total_amount Product total price in the minimal quantity of the currency +//@description A message with an invoice from a bot @title Product title @param_description Product description @photo Product photo; may be null @currency Currency for the product price @total_amount Product total price in the smallest units of the currency //@start_parameter Unique invoice bot start_parameter. To share an invoice use the URL https://t.me/{bot_username}?start={start_parameter} @is_test True, if the invoice is a test invoice //@need_shipping_address True, if the shipping address should be specified @receipt_message_id The identifier of the message with the receipt, after the product has been purchased messageInvoice title:string description:string photo:photo currency:string total_amount:int53 start_parameter:string is_test:Bool need_shipping_address:Bool receipt_message_id:int53 = MessageContent; @@ -1729,11 +1732,11 @@ messageCustomServiceAction text:string = MessageContent; //@description A new high score was achieved in a game @game_message_id Identifier of the message with the game, can be an identifier of a deleted message @game_id Identifier of the game; may be different from the games presented in the message with the game @score New score messageGameScore game_message_id:int53 game_id:int64 score:int32 = MessageContent; -//@description A payment has been completed @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for the price of the product @total_amount Total price for the product, in the minimal quantity of the currency +//@description A payment has been completed @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for the price of the product @total_amount Total price for the product, in the smallest units of the currency messagePaymentSuccessful invoice_message_id:int53 currency:string total_amount:int53 = MessageContent; //@description A payment has been completed; for bots only @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for price of the product -//@total_amount Total price for the product, in the minimal quantity of the currency @invoice_payload Invoice payload @shipping_option_id Identifier of the shipping option chosen by the user; may be empty if not applicable @order_info Information about the order; may be null +//@total_amount Total price for the product, in the smallest units of the currency @invoice_payload Invoice payload @shipping_option_id Identifier of the shipping option chosen by the user; may be empty if not applicable @order_info Information about the order; may be null //@telegram_payment_charge_id Telegram payment identifier @provider_payment_charge_id Provider payment identifier messagePaymentSuccessfulBot invoice_message_id:int53 currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo telegram_payment_charge_id:string provider_payment_charge_id:string = MessageContent; @@ -3606,7 +3609,7 @@ updateNewInlineCallbackQuery id:int64 sender_user_id:int32 inline_message_id:str //@description A new incoming shipping query; for bots only. Only for invoices with flexible price @id Unique query identifier @sender_user_id Identifier of the user who sent the query @invoice_payload Invoice payload @shipping_address User shipping address updateNewShippingQuery id:int64 sender_user_id:int32 invoice_payload:string shipping_address:address = Update; -//@description A new incoming pre-checkout query; for bots only. Contains full information about a checkout @id Unique query identifier @sender_user_id Identifier of the user who sent the query @currency Currency for the product price @total_amount Total price for the product, in the minimal quantity of the currency +//@description A new incoming pre-checkout query; for bots only. Contains full information about a checkout @id Unique query identifier @sender_user_id Identifier of the user who sent the query @currency Currency for the product price @total_amount Total price for the product, in the smallest units of the currency //@invoice_payload Invoice payload @shipping_option_id Identifier of a shipping option chosen by the user; may be empty if not applicable @order_info Information about the order; may be null updateNewPreCheckoutQuery id:int64 sender_user_id:int32 currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo = Update; @@ -4495,14 +4498,14 @@ replacePrimaryChatInviteLink chat_id:int53 = ChatInviteLink; //@description Creates a new invite link for a chat. Available for basic groups, supergroups, and channels. Requires administrator privileges and can_invite_users right in the chat //@chat_id Chat identifier //@expire_date Point in time (Unix timestamp) when the link will expire; pass 0 if never -//@member_limit Maximum number of chat members that can join the chat by the link simultaneously; 0-99999; pass 0 if not limited +//@member_limit The maximum number of chat members that can join the chat by the link simultaneously; 0-99999; pass 0 if not limited createChatInviteLink chat_id:int53 expire_date:int32 member_limit:int32 = ChatInviteLink; //@description Edits a non-primary invite link for a chat. Available for basic groups, supergroups, and channels. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links //@chat_id Chat identifier //@invite_link Invite link to be edited //@expire_date Point in time (Unix timestamp) when the link will expire; pass 0 if never -//@member_limit Maximum number of chat members that can join the chat by the link simultaneously; 0-99999; pass 0 if not limited +//@member_limit The maximum number of chat members that can join the chat by the link simultaneously; 0-99999; pass 0 if not limited editChatInviteLink chat_id:int53 invite_link:string expire_date:int32 member_limit:int32 = ChatInviteLink; //@description Returns information about an invite link. Requires administrator privileges and can_invite_users right in the chat to get own links and owner privileges to get other links @@ -4519,11 +4522,11 @@ getChatInviteLinkCounts chat_id:int53 = ChatInviteLinkCounts; //@is_revoked Pass true if revoked links needs to be returned instead of active or expired //@offset_date Creation date of an invite link starting after which to return invite links; use 0 to get results from the beginning //@offset_invite_link Invite link starting after which to return invite links; use empty string to get results from the beginning -//@limit Maximum number of invite links to return +//@limit The maximum number of invite links to return getChatInviteLinks chat_id:int53 creator_user_id:int32 is_revoked:Bool offset_date:int32 offset_invite_link:string limit:int32 = ChatInviteLinks; //@description Returns chat members joined a chat by an invite link. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links @chat_id Chat identifier @invite_link Invite link for which to return chat members -//@offset_member A chat member from which to return next chat members; use null to get results from the beginning @limit Maximum number of chat members to return +//@offset_member A chat member from which to return next chat members; use null to get results from the beginning @limit The maximum number of chat members to return getChatInviteLinkMembers chat_id:int53 invite_link:string offset_member:chatInviteLinkMember limit:int32 = ChatInviteLinkMembers; //@description Revokes invite link for a chat. Available for basic groups, supergroups, and channels. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links. @@ -4629,7 +4632,7 @@ toggleGroupCallParticipantIsHandRaised group_call_id:int32 participant:MessageSe //@description Loads more group call participants. The loaded participants will be received through updates. Use the field groupCall.loaded_all_participants to check whether all participants has already been loaded //@group_call_id Group call identifier. The group call must be previously received through getGroupCall and must be joined or being joined -//@limit Maximum number of participants to load +//@limit The maximum number of participants to load loadGroupCallParticipants group_call_id:int32 limit:int32 = Ok; //@description Leaves a group call @group_call_id Group call identifier diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 0321e53e3..f6c5c1cf4 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -1875,7 +1875,7 @@ static Result create_input_message_content( } message_invoice->invoice.price_parts.emplace_back(std::move(price->label_), price->amount_); if (price->amount_ < -MAX_AMOUNT || price->amount_ > MAX_AMOUNT) { - return Status::Error(400, "Too big amount of currency specified"); + return Status::Error(400, "Too big amount of the currency specified"); } total_amount += price->amount_; } @@ -1887,6 +1887,17 @@ static Result create_input_message_content( } message_invoice->total_amount = total_amount; + if (input_invoice->invoice_->max_tip_amount_ < 0 || input_invoice->invoice_->max_tip_amount_ > MAX_AMOUNT) { + return Status::Error(400, "Invalid max tip amount of the currency specified"); + } + for (auto tip_amount : input_invoice->invoice_->suggested_tip_amounts_) { + if (tip_amount < 0 || tip_amount > input_invoice->invoice_->max_tip_amount_) { + return Status::Error(400, "Invalid suggested tip amount of the currency specified"); + } + } + + message_invoice->invoice.max_tip_amount = input_invoice->invoice_->max_tip_amount_; + message_invoice->invoice.suggested_tip_amounts = std::move(input_invoice->invoice_->suggested_tip_amounts_); message_invoice->invoice.is_test = input_invoice->invoice_->is_test_; message_invoice->invoice.need_name = input_invoice->invoice_->need_name_; message_invoice->invoice.need_phone_number = input_invoice->invoice_->need_phone_number_; @@ -2295,13 +2306,17 @@ static tl_object_ptr get_input_invoice(const Invoice &inv if (invoice.is_flexible) { flags |= telegram_api::invoice::FLEXIBLE_MASK; } + if (invoice.max_tip_amount != 0) { + flags |= telegram_api::invoice::MAX_TIP_AMOUNT_MASK; + } auto prices = transform(invoice.price_parts, [](const LabeledPricePart &price) { return telegram_api::make_object(price.label, price.amount); }); return make_tl_object( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, - false /*ignored*/, false /*ignored*/, false /*ignored*/, invoice.currency, std::move(prices), 0, vector()); + false /*ignored*/, false /*ignored*/, false /*ignored*/, invoice.currency, std::move(prices), + invoice.max_tip_amount, vector(invoice.suggested_tip_amounts)); } static tl_object_ptr get_input_web_document(const FileManager *file_manager, diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index b56af5cbb..5f7d489df 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -129,9 +129,10 @@ static tl_object_ptr convert_invoice(tl_object_ptr(std::move(invoice->currency_), std::move(labeled_prices), is_test, need_name, - need_phone_number, need_email_address, need_shipping_address, - send_phone_number_to_provider, send_email_address_to_provider, is_flexible); + return make_tl_object( + std::move(invoice->currency_), std::move(labeled_prices), invoice->max_tip_amount_, + vector(invoice->suggested_tip_amounts_), is_test, need_name, need_phone_number, need_email_address, + need_shipping_address, send_phone_number_to_provider, send_email_address_to_provider, is_flexible); } static tl_object_ptr convert_payment_provider( @@ -574,7 +575,8 @@ bool operator==(const Invoice &lhs, const Invoice &rhs) { lhs.need_shipping_address == rhs.need_shipping_address && lhs.send_phone_number_to_provider == rhs.send_phone_number_to_provider && lhs.send_email_address_to_provider == rhs.send_email_address_to_provider && - lhs.is_flexible == rhs.is_flexible && lhs.currency == rhs.currency && lhs.price_parts == rhs.price_parts; + lhs.is_flexible == rhs.is_flexible && lhs.currency == rhs.currency && lhs.price_parts == rhs.price_parts && + lhs.max_tip_amount == rhs.max_tip_amount && lhs.suggested_tip_amounts == rhs.suggested_tip_amounts; } bool operator!=(const Invoice &lhs, const Invoice &rhs) { @@ -589,7 +591,9 @@ StringBuilder &operator<<(StringBuilder &string_builder, const Invoice &invoice) << (invoice.need_shipping_address ? ", needs shipping address" : "") << (invoice.send_phone_number_to_provider ? ", sends phone number to provider" : "") << (invoice.send_email_address_to_provider ? ", sends email address to provider" : "") << " in " - << invoice.currency << " with price parts " << format::as_array(invoice.price_parts) << "]"; + << invoice.currency << " with price parts " << format::as_array(invoice.price_parts) + << " and suggested tip amounts " << invoice.suggested_tip_amounts << " up to " + << invoice.max_tip_amount << "]"; } bool operator==(const Address &lhs, const Address &rhs) { diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index 200a4491f..96c6dd854 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -34,6 +34,8 @@ struct LabeledPricePart { struct Invoice { string currency; vector price_parts; + int64 max_tip_amount = 0; + vector suggested_tip_amounts; bool is_test = false; bool need_name = false; bool need_phone_number = false; diff --git a/td/telegram/Payments.hpp b/td/telegram/Payments.hpp index cc45116fb..330a880c2 100644 --- a/td/telegram/Payments.hpp +++ b/td/telegram/Payments.hpp @@ -28,6 +28,7 @@ void parse(LabeledPricePart &labeled_price_part, ParserT &parser) { template void store(const Invoice &invoice, StorerT &storer) { + bool has_tip = invoice.max_tip_amount != 0; BEGIN_STORE_FLAGS(); STORE_FLAG(invoice.is_test); STORE_FLAG(invoice.need_name); @@ -37,13 +38,19 @@ void store(const Invoice &invoice, StorerT &storer) { STORE_FLAG(invoice.is_flexible); STORE_FLAG(invoice.send_phone_number_to_provider); STORE_FLAG(invoice.send_email_address_to_provider); + STORE_FLAG(has_tip); END_STORE_FLAGS(); store(invoice.currency, storer); store(invoice.price_parts, storer); + if (has_tip) { + store(invoice.max_tip_amount, storer); + store(invoice.suggested_tip_amounts, storer); + } } template void parse(Invoice &invoice, ParserT &parser) { + bool has_tip; BEGIN_PARSE_FLAGS(); PARSE_FLAG(invoice.is_test); PARSE_FLAG(invoice.need_name); @@ -53,9 +60,14 @@ void parse(Invoice &invoice, ParserT &parser) { PARSE_FLAG(invoice.is_flexible); PARSE_FLAG(invoice.send_phone_number_to_provider); PARSE_FLAG(invoice.send_email_address_to_provider); + PARSE_FLAG(has_tip); END_PARSE_FLAGS(); parse(invoice.currency, parser); parse(invoice.price_parts, parser); + if (has_tip) { + parse(invoice.max_tip_amount, parser); + parse(invoice.suggested_tip_amounts, parser); + } } template From f1b949456b237e50c0a33a121fa649a546ec4792 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 30 Mar 2021 18:45:22 +0300 Subject: [PATCH 151/281] Support tip sending. --- td/generate/scheme/td_api.tl | 4 ++-- td/telegram/MessagesManager.cpp | 4 ++-- td/telegram/MessagesManager.h | 2 +- td/telegram/Payments.cpp | 16 ++++++++++------ td/telegram/Payments.h | 2 +- td/telegram/Td.cpp | 2 +- td/telegram/cli.cpp | 11 +++++++---- 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 7a3f6b021..cac2ce2aa 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4893,8 +4893,8 @@ validateOrderInfo chat_id:int53 message_id:int53 order_info:orderInfo allow_save //@description Sends a filled-out payment form to the bot for final verification @chat_id Chat identifier of the Invoice message @message_id Message identifier //@payment_form_id Payment form identifier returned by getPaymentForm @order_info_id Identifier returned by validateOrderInfo, or an empty string @shipping_option_id Identifier of a chosen shipping option, if applicable -//@credentials The credentials chosen by user for payment -sendPaymentForm chat_id:int53 message_id:int53 payment_form_id:int64 order_info_id:string shipping_option_id:string credentials:InputCredentials = PaymentResult; +//@credentials The credentials chosen by user for payment @tip_amount Chosen by the user amount of tip in the smallest units of the currency +sendPaymentForm chat_id:int53 message_id:int53 payment_form_id:int64 order_info_id:string shipping_option_id:string credentials:InputCredentials tip_amount:int53 = PaymentResult; //@description Returns information about a successful payment @chat_id Chat identifier of the PaymentSuccessful message @message_id Message identifier getPaymentReceipt chat_id:int53 message_id:int53 = PaymentReceipt; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 6716a8ffe..86a073f67 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -37391,7 +37391,7 @@ void MessagesManager::validate_order_info(FullMessageId full_message_id, tl_obje void MessagesManager::send_payment_form(FullMessageId full_message_id, int64 payment_form_id, const string &order_info_id, const string &shipping_option_id, - const tl_object_ptr &credentials, + const tl_object_ptr &credentials, int64 tip_amount, Promise> &&promise) { auto r_message_id = get_invoice_message_id(full_message_id); if (r_message_id.is_error()) { @@ -37399,7 +37399,7 @@ void MessagesManager::send_payment_form(FullMessageId full_message_id, int64 pay } ::td::send_payment_form(full_message_id.get_dialog_id(), r_message_id.ok(), payment_form_id, order_info_id, - shipping_option_id, credentials, std::move(promise)); + shipping_option_id, credentials, tip_amount, std::move(promise)); } void MessagesManager::get_payment_receipt(FullMessageId full_message_id, diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 24a2d635b..97d7035b3 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -918,7 +918,7 @@ class MessagesManager : public Actor { void send_payment_form(FullMessageId full_message_id, int64 payment_form_id, const string &order_info_id, const string &shipping_option_id, const tl_object_ptr &credentials, - Promise> &&promise); + int64 tip_amount, Promise> &&promise); void get_payment_receipt(FullMessageId full_message_id, Promise> &&promise); diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 5f7d489df..259e5a03d 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -360,7 +360,8 @@ class SendPaymentFormQuery : public Td::ResultHandler { } void send(DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, const string &order_info_id, - const string &shipping_option_id, tl_object_ptr input_credentials) { + const string &shipping_option_id, tl_object_ptr input_credentials, + int64 tip_amount) { CHECK(input_credentials != nullptr); dialog_id_ = dialog_id; @@ -376,9 +377,12 @@ class SendPaymentFormQuery : public Td::ResultHandler { if (!shipping_option_id.empty()) { flags |= telegram_api::payments_sendPaymentForm::SHIPPING_OPTION_ID_MASK; } - send_query(G()->net_query_creator().create( - telegram_api::payments_sendPaymentForm(flags, payment_form_id, std::move(input_peer), server_message_id.get(), - order_info_id, shipping_option_id, std::move(input_credentials), 0))); + if (tip_amount != 0) { + flags |= telegram_api::payments_sendPaymentForm::TIP_AMOUNT_MASK; + } + send_query(G()->net_query_creator().create(telegram_api::payments_sendPaymentForm( + flags, payment_form_id, std::move(input_peer), server_message_id.get(), order_info_id, shipping_option_id, + std::move(input_credentials), tip_amount))); } void on_result(uint64 id, BufferSlice packet) override { @@ -877,7 +881,7 @@ void validate_order_info(DialogId dialog_id, ServerMessageId server_message_id, void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, const string &order_info_id, const string &shipping_option_id, - const tl_object_ptr &credentials, + const tl_object_ptr &credentials, int64 tip_amount, Promise> &&promise) { CHECK(credentials != nullptr); @@ -930,7 +934,7 @@ void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, in .get_actor_unsafe() ->create_handler(std::move(promise)) ->send(dialog_id, server_message_id, payment_form_id, order_info_id, shipping_option_id, - std::move(input_credentials)); + std::move(input_credentials), tip_amount); } void get_payment_receipt(DialogId dialog_id, ServerMessageId server_message_id, diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index 96c6dd854..66b9e4abd 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -149,7 +149,7 @@ void validate_order_info(DialogId dialog_id, ServerMessageId server_message_id, void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, const string &order_info_id, const string &shipping_option_id, - const tl_object_ptr &credentials, + const tl_object_ptr &credentials, int64 tip_amount, Promise> &&promise); void get_payment_receipt(DialogId dialog_id, ServerMessageId server_message_id, diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 27430095a..1c3b7df4e 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -7734,7 +7734,7 @@ void Td::on_request(uint64 id, td_api::sendPaymentForm &request) { CREATE_REQUEST_PROMISE(); messages_manager_->send_payment_form({DialogId(request.chat_id_), MessageId(request.message_id_)}, request.payment_form_id_, request.order_info_id_, request.shipping_option_id_, - request.credentials_, std::move(promise)); + request.credentials_, request.tip_amount_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::getPaymentReceipt &request) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 96905d0e9..75f33b050 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1839,25 +1839,28 @@ class CliClient final : public Actor { } else if (op == "spfs") { string chat_id; string message_id; + int64 tip_amount; int64 payment_form_id; string order_info_id; string shipping_option_id; string saved_credentials_id; - get_args(args, chat_id, message_id, payment_form_id, order_info_id, shipping_option_id, saved_credentials_id); + get_args(args, chat_id, message_id, tip_amount, payment_form_id, order_info_id, shipping_option_id, + saved_credentials_id); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), payment_form_id, order_info_id, shipping_option_id, - td_api::make_object(saved_credentials_id))); + td_api::make_object(saved_credentials_id), tip_amount)); } else if (op == "spfn") { string chat_id; string message_id; + int64 tip_amount; int64 payment_form_id; string order_info_id; string shipping_option_id; string data; - get_args(args, chat_id, message_id, payment_form_id, order_info_id, shipping_option_id, data); + get_args(args, chat_id, message_id, tip_amount, payment_form_id, order_info_id, shipping_option_id, data); send_request(td_api::make_object( as_chat_id(chat_id), as_message_id(message_id), payment_form_id, order_info_id, shipping_option_id, - td_api::make_object(data, true))); + td_api::make_object(data, true), tip_amount)); } else if (op == "gpre") { string chat_id; string message_id; From b9bc86fb5aefa8942caf1b6f638636846426ce65 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 01:20:40 +0300 Subject: [PATCH 152/281] Add class InputInvoice. --- td/telegram/MessageContent.cpp | 287 ++------------------------------- td/telegram/Payments.cpp | 246 +++++++++++++++++++++++++++- td/telegram/Payments.h | 37 ++++- td/telegram/Payments.hpp | 33 ++++ 4 files changed, 324 insertions(+), 279 deletions(-) diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index f6c5c1cf4..e79afc6a9 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -469,34 +469,10 @@ class MessageCall : public MessageContent { class MessageInvoice : public MessageContent { public: - string title; - string description; - Photo photo; - string start_parameter; - - // InputMessageInvoice - Invoice invoice; - string payload; - string provider_token; - string provider_data; - - // MessageInvoice - int64 total_amount = 0; - MessageId receipt_message_id; + InputInvoice input_invoice; MessageInvoice() = default; - MessageInvoice(string &&title, string &&description, Photo &&photo, string &&start_parameter, int64 total_amount, - string &¤cy, bool is_test, bool need_shipping_address, MessageId receipt_message_id) - : title(std::move(title)) - , description(std::move(description)) - , photo(std::move(photo)) - , start_parameter(std::move(start_parameter)) - , invoice(std::move(currency), is_test, need_shipping_address) - , payload() - , provider_token() - , provider_data() - , total_amount(total_amount) - , receipt_message_id(receipt_message_id) { + explicit MessageInvoice(InputInvoice &&input_invoice) : input_invoice(std::move(input_invoice)) { } MessageContentType get_type() const override { @@ -782,16 +758,7 @@ static void store(const MessageContent *content, StorerT &storer) { } case MessageContentType::Invoice: { auto m = static_cast(content); - store(m->title, storer); - store(m->description, storer); - store(m->photo, storer); - store(m->start_parameter, storer); - store(m->invoice, storer); - store(m->payload, storer); - store(m->provider_token, storer); - store(m->provider_data, storer); - store(m->total_amount, storer); - store(m->receipt_message_id, storer); + store(m->input_invoice, storer); break; } case MessageContentType::LiveLocation: { @@ -1100,20 +1067,7 @@ static void parse(unique_ptr &content, ParserT &parser) { } case MessageContentType::Invoice: { auto m = make_unique(); - parse(m->title, parser); - parse(m->description, parser); - parse(m->photo, parser); - parse(m->start_parameter, parser); - parse(m->invoice, parser); - parse(m->payload, parser); - parse(m->provider_token, parser); - if (parser.version() >= static_cast(Version::AddMessageInvoiceProviderData)) { - parse(m->provider_data, parser); - } else { - m->provider_data.clear(); - } - parse(m->total_amount, parser); - parse(m->receipt_message_id, parser); + parse(m->input_invoice, parser); content = std::move(m); break; } @@ -1812,116 +1766,9 @@ static Result create_input_message_content( return Status::Error(400, "Invoices can be sent only by bots"); } - auto input_invoice = move_tl_object_as(input_message_content); - if (!clean_input_string(input_invoice->title_)) { - return Status::Error(400, "Invoice title must be encoded in UTF-8"); - } - if (!clean_input_string(input_invoice->description_)) { - return Status::Error(400, "Invoice description must be encoded in UTF-8"); - } - if (!clean_input_string(input_invoice->photo_url_)) { - return Status::Error(400, "Invoice photo URL must be encoded in UTF-8"); - } - if (!clean_input_string(input_invoice->start_parameter_)) { - return Status::Error(400, "Invoice bot start parameter must be encoded in UTF-8"); - } - if (!clean_input_string(input_invoice->provider_token_)) { - return Status::Error(400, "Invoice provider token must be encoded in UTF-8"); - } - if (!clean_input_string(input_invoice->provider_data_)) { - return Status::Error(400, "Invoice provider data must be encoded in UTF-8"); - } - if (!clean_input_string(input_invoice->invoice_->currency_)) { - return Status::Error(400, "Invoice currency must be encoded in UTF-8"); - } - - auto message_invoice = make_unique(); - message_invoice->title = std::move(input_invoice->title_); - message_invoice->description = std::move(input_invoice->description_); - - auto r_http_url = parse_url(input_invoice->photo_url_); - if (r_http_url.is_error()) { - if (!input_invoice->photo_url_.empty()) { - LOG(INFO) << "Can't register url " << input_invoice->photo_url_; - } - } else { - auto url = r_http_url.ok().get_url(); - auto r_invoice_file_id = td->file_manager_->from_persistent_id(url, FileType::Temp); - if (r_invoice_file_id.is_error()) { - LOG(INFO) << "Can't register url " << url; - } else { - auto invoice_file_id = r_invoice_file_id.move_as_ok(); - - PhotoSize s; - s.type = 'n'; - s.dimensions = - get_dimensions(input_invoice->photo_width_, input_invoice->photo_height_, "inputMessageInvoice"); - s.size = input_invoice->photo_size_; // TODO use invoice_file_id size - s.file_id = invoice_file_id; - - message_invoice->photo.id = 0; - message_invoice->photo.photos.push_back(s); - } - } - message_invoice->start_parameter = std::move(input_invoice->start_parameter_); - - message_invoice->invoice.currency = std::move(input_invoice->invoice_->currency_); - message_invoice->invoice.price_parts.reserve(input_invoice->invoice_->price_parts_.size()); - int64 total_amount = 0; - const int64 MAX_AMOUNT = 9999'9999'9999; - for (auto &price : input_invoice->invoice_->price_parts_) { - if (!clean_input_string(price->label_)) { - return Status::Error(400, "Invoice price label must be encoded in UTF-8"); - } - message_invoice->invoice.price_parts.emplace_back(std::move(price->label_), price->amount_); - if (price->amount_ < -MAX_AMOUNT || price->amount_ > MAX_AMOUNT) { - return Status::Error(400, "Too big amount of the currency specified"); - } - total_amount += price->amount_; - } - if (total_amount <= 0) { - return Status::Error(400, "Total price must be positive"); - } - if (total_amount > MAX_AMOUNT) { - return Status::Error(400, "Total price is too big"); - } - message_invoice->total_amount = total_amount; - - if (input_invoice->invoice_->max_tip_amount_ < 0 || input_invoice->invoice_->max_tip_amount_ > MAX_AMOUNT) { - return Status::Error(400, "Invalid max tip amount of the currency specified"); - } - for (auto tip_amount : input_invoice->invoice_->suggested_tip_amounts_) { - if (tip_amount < 0 || tip_amount > input_invoice->invoice_->max_tip_amount_) { - return Status::Error(400, "Invalid suggested tip amount of the currency specified"); - } - } - - message_invoice->invoice.max_tip_amount = input_invoice->invoice_->max_tip_amount_; - message_invoice->invoice.suggested_tip_amounts = std::move(input_invoice->invoice_->suggested_tip_amounts_); - message_invoice->invoice.is_test = input_invoice->invoice_->is_test_; - message_invoice->invoice.need_name = input_invoice->invoice_->need_name_; - message_invoice->invoice.need_phone_number = input_invoice->invoice_->need_phone_number_; - message_invoice->invoice.need_email_address = input_invoice->invoice_->need_email_address_; - message_invoice->invoice.need_shipping_address = input_invoice->invoice_->need_shipping_address_; - message_invoice->invoice.send_phone_number_to_provider = input_invoice->invoice_->send_phone_number_to_provider_; - message_invoice->invoice.send_email_address_to_provider = - input_invoice->invoice_->send_email_address_to_provider_; - message_invoice->invoice.is_flexible = input_invoice->invoice_->is_flexible_; - if (message_invoice->invoice.send_phone_number_to_provider) { - message_invoice->invoice.need_phone_number = true; - } - if (message_invoice->invoice.send_email_address_to_provider) { - message_invoice->invoice.need_email_address = true; - } - if (message_invoice->invoice.is_flexible) { - message_invoice->invoice.need_shipping_address = true; - } - - message_invoice->payload = std::move(input_invoice->payload_); - message_invoice->provider_token = std::move(input_invoice->provider_token_); - message_invoice->provider_data = std::move(input_invoice->provider_data_); - - content = std::move(message_invoice); + TRY_RESULT(input_invoice, process_input_message_invoice( + move_tl_object_as(input_message_content), td)); + content = make_unique(std::move(input_invoice)); break; } case td_api::inputMessagePoll::ID: { @@ -2280,88 +2127,6 @@ SecretInputMedia get_secret_input_media(const MessageContent *content, Td *td, return SecretInputMedia{}; } -static tl_object_ptr get_input_invoice(const Invoice &invoice) { - int32 flags = 0; - if (invoice.is_test) { - flags |= telegram_api::invoice::TEST_MASK; - } - if (invoice.need_name) { - flags |= telegram_api::invoice::NAME_REQUESTED_MASK; - } - if (invoice.need_phone_number) { - flags |= telegram_api::invoice::PHONE_REQUESTED_MASK; - } - if (invoice.need_email_address) { - flags |= telegram_api::invoice::EMAIL_REQUESTED_MASK; - } - if (invoice.need_shipping_address) { - flags |= telegram_api::invoice::SHIPPING_ADDRESS_REQUESTED_MASK; - } - if (invoice.send_phone_number_to_provider) { - flags |= telegram_api::invoice::PHONE_TO_PROVIDER_MASK; - } - if (invoice.send_email_address_to_provider) { - flags |= telegram_api::invoice::EMAIL_TO_PROVIDER_MASK; - } - if (invoice.is_flexible) { - flags |= telegram_api::invoice::FLEXIBLE_MASK; - } - if (invoice.max_tip_amount != 0) { - flags |= telegram_api::invoice::MAX_TIP_AMOUNT_MASK; - } - - auto prices = transform(invoice.price_parts, [](const LabeledPricePart &price) { - return telegram_api::make_object(price.label, price.amount); - }); - return make_tl_object( - flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, - false /*ignored*/, false /*ignored*/, false /*ignored*/, invoice.currency, std::move(prices), - invoice.max_tip_amount, vector(invoice.suggested_tip_amounts)); -} - -static tl_object_ptr get_input_web_document(const FileManager *file_manager, - const Photo &photo) { - if (photo.is_empty()) { - return nullptr; - } - - CHECK(photo.photos.size() == 1); - const PhotoSize &size = photo.photos[0]; - CHECK(size.file_id.is_valid()); - - vector> attributes; - if (size.dimensions.width != 0 && size.dimensions.height != 0) { - attributes.push_back( - make_tl_object(size.dimensions.width, size.dimensions.height)); - } - - auto file_view = file_manager->get_file_view(size.file_id); - CHECK(file_view.has_url()); - - auto file_name = get_url_file_name(file_view.url()); - return make_tl_object( - file_view.url(), size.size, MimeType::from_extension(PathView(file_name).extension(), "image/jpeg"), - std::move(attributes)); -} - -static tl_object_ptr get_input_media_invoice(const FileManager *file_manager, - const MessageInvoice *message_invoice) { - CHECK(message_invoice != nullptr); - int32 flags = telegram_api::inputMediaInvoice::START_PARAM_MASK; - auto input_web_document = get_input_web_document(file_manager, message_invoice->photo); - if (input_web_document != nullptr) { - flags |= telegram_api::inputMediaInvoice::PHOTO_MASK; - } - - return make_tl_object( - flags, message_invoice->title, message_invoice->description, std::move(input_web_document), - get_input_invoice(message_invoice->invoice), BufferSlice(message_invoice->payload), - message_invoice->provider_token, - telegram_api::make_object( - message_invoice->provider_data.empty() ? "null" : message_invoice->provider_data), - message_invoice->start_parameter); -} - static tl_object_ptr get_input_media_impl( const MessageContent *content, Td *td, tl_object_ptr input_file, tl_object_ptr input_thumbnail, int32 ttl, const string &emoji) { @@ -2395,7 +2160,7 @@ static tl_object_ptr get_input_media_impl( } case MessageContentType::Invoice: { auto m = static_cast(content); - return get_input_media_invoice(td->file_manager_.get(), m); + return get_input_media_invoice(m->input_invoice, td); } case MessageContentType::LiveLocation: { auto m = static_cast(content); @@ -3016,15 +2781,9 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo case MessageContentType::Invoice: { auto old_ = static_cast(old_content); auto new_ = static_cast(new_content); - if (old_->title != new_->title || old_->description != new_->description || old_->photo != new_->photo || - old_->start_parameter != new_->start_parameter || old_->invoice != new_->invoice || - old_->total_amount != new_->total_amount || old_->receipt_message_id != new_->receipt_message_id) { + if (old_->input_invoice != new_->input_invoice) { need_update = true; } - if (old_->payload != new_->payload || old_->provider_token != new_->provider_token || - old_->provider_data != new_->provider_data) { - is_content_changed = true; - } break; } case MessageContentType::LiveLocation: { @@ -4158,26 +3917,9 @@ unique_ptr get_message_content(Td *td, FormattedText message, return std::move(m); } - case telegram_api::messageMediaInvoice::ID: { - auto message_invoice = move_tl_object_as(media); - - MessageId receipt_message_id; - if ((message_invoice->flags_ & telegram_api::messageMediaInvoice::RECEIPT_MSG_ID_MASK) != 0) { - receipt_message_id = MessageId(ServerMessageId(message_invoice->receipt_msg_id_)); - if (!receipt_message_id.is_valid()) { - LOG(ERROR) << "Receive as receipt message " << receipt_message_id << " in " << owner_dialog_id; - receipt_message_id = MessageId(); - } - } - bool need_shipping_address = - (message_invoice->flags_ & telegram_api::messageMediaInvoice::SHIPPING_ADDRESS_REQUESTED_MASK) != 0; - bool is_test = (message_invoice->flags_ & telegram_api::messageMediaInvoice::TEST_MASK) != 0; + case telegram_api::messageMediaInvoice::ID: return td::make_unique( - std::move(message_invoice->title_), std::move(message_invoice->description_), - get_web_document_photo(td->file_manager_.get(), std::move(message_invoice->photo_), owner_dialog_id), - std::move(message_invoice->start_param_), message_invoice->total_amount_, - std::move(message_invoice->currency_), is_test, need_shipping_address, receipt_message_id); - } + get_input_invoice(move_tl_object_as(media), td, owner_dialog_id)); case telegram_api::messageMediaWebPage::ID: { auto media_web_page = move_tl_object_as(media); auto web_page_id = td->web_pages_manager_->on_get_web_page(std::move(media_web_page->webpage_), owner_dialog_id); @@ -4710,10 +4452,7 @@ tl_object_ptr get_message_content_object(const MessageCo } case MessageContentType::Invoice: { const MessageInvoice *m = static_cast(content); - return make_tl_object( - m->title, m->description, get_photo_object(td->file_manager_.get(), m->photo), m->invoice.currency, - m->total_amount, m->start_parameter, m->invoice.is_test, m->invoice.need_shipping_address, - m->receipt_message_id.get()); + return get_message_invoice_object(m->input_invoice, td); } case MessageContentType::LiveLocation: { const MessageLiveLocation *m = static_cast(content); @@ -5109,7 +4848,7 @@ vector get_message_content_file_ids(const MessageContent *content, const case MessageContentType::Game: return static_cast(content)->game.get_file_ids(td); case MessageContentType::Invoice: - return photo_get_file_ids(static_cast(content)->photo); + return get_input_invoice_file_ids(static_cast(content)->input_invoice); case MessageContentType::ChatChangePhoto: return photo_get_file_ids(static_cast(content)->photo); case MessageContentType::PassportDataReceived: { diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 259e5a03d..9abefaf8e 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -7,21 +7,24 @@ #include "td/telegram/Payments.h" #include "td/telegram/ContactsManager.h" +#include "td/telegram/files/FileManager.h" +#include "td/telegram/files/FileType.h" #include "td/telegram/Global.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/misc.h" #include "td/telegram/PasswordManager.h" #include "td/telegram/Td.h" -#include "td/telegram/td_api.h" -#include "td/telegram/telegram_api.h" #include "td/telegram/UpdatesManager.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" #include "td/utils/common.h" #include "td/utils/format.h" +#include "td/utils/HttpUrl.h" #include "td/utils/JsonBuilder.h" #include "td/utils/logging.h" +#include "td/utils/MimeType.h" +#include "td/utils/PathView.h" #include "td/utils/Status.h" namespace td { @@ -600,6 +603,245 @@ StringBuilder &operator<<(StringBuilder &string_builder, const Invoice &invoice) << invoice.max_tip_amount << "]"; } +bool operator==(const InputInvoice &lhs, const InputInvoice &rhs) { + return lhs.title == rhs.title && lhs.description == rhs.description && lhs.photo == rhs.photo && + lhs.start_parameter == rhs.start_parameter && lhs.invoice == rhs.invoice && + lhs.total_amount == rhs.total_amount && lhs.receipt_message_id == rhs.receipt_message_id && + lhs.payload == rhs.payload && lhs.provider_token == rhs.provider_token && + lhs.provider_data == rhs.provider_data; +} + +bool operator!=(const InputInvoice &lhs, const InputInvoice &rhs) { + return !(lhs == rhs); +} + +InputInvoice get_input_invoice(tl_object_ptr &&message_invoice, Td *td, + DialogId owner_dialog_id) { + InputInvoice result; + result.title = std::move(message_invoice->title_); + result.description = std::move(message_invoice->description_); + result.photo = get_web_document_photo(td->file_manager_.get(), std::move(message_invoice->photo_), owner_dialog_id); + result.start_parameter = std::move(message_invoice->start_param_); + result.invoice.currency = std::move(message_invoice->currency_); + result.invoice.is_test = (message_invoice->flags_ & telegram_api::messageMediaInvoice::TEST_MASK) != 0; + result.invoice.need_shipping_address = + (message_invoice->flags_ & telegram_api::messageMediaInvoice::SHIPPING_ADDRESS_REQUESTED_MASK) != 0; + // result.payload = string(); + // result.provider_token = string(); + // result.provider_data = string(); + result.total_amount = message_invoice->total_amount_; + if ((message_invoice->flags_ & telegram_api::messageMediaInvoice::RECEIPT_MSG_ID_MASK) != 0) { + result.receipt_message_id = MessageId(ServerMessageId(message_invoice->receipt_msg_id_)); + if (!result.receipt_message_id.is_valid()) { + LOG(ERROR) << "Receive as receipt message " << result.receipt_message_id << " in " << owner_dialog_id; + result.receipt_message_id = MessageId(); + } + } + return result; +} + +Result process_input_message_invoice(td_api::object_ptr &&input_invoice, + Td *td) { + if (!clean_input_string(input_invoice->title_)) { + return Status::Error(400, "Invoice title must be encoded in UTF-8"); + } + if (!clean_input_string(input_invoice->description_)) { + return Status::Error(400, "Invoice description must be encoded in UTF-8"); + } + if (!clean_input_string(input_invoice->photo_url_)) { + return Status::Error(400, "Invoice photo URL must be encoded in UTF-8"); + } + if (!clean_input_string(input_invoice->start_parameter_)) { + return Status::Error(400, "Invoice bot start parameter must be encoded in UTF-8"); + } + if (!clean_input_string(input_invoice->provider_token_)) { + return Status::Error(400, "Invoice provider token must be encoded in UTF-8"); + } + if (!clean_input_string(input_invoice->provider_data_)) { + return Status::Error(400, "Invoice provider data must be encoded in UTF-8"); + } + if (!clean_input_string(input_invoice->invoice_->currency_)) { + return Status::Error(400, "Invoice currency must be encoded in UTF-8"); + } + + InputInvoice result; + result.title = std::move(input_invoice->title_); + result.description = std::move(input_invoice->description_); + + auto r_http_url = parse_url(input_invoice->photo_url_); + if (r_http_url.is_error()) { + if (!input_invoice->photo_url_.empty()) { + LOG(INFO) << "Can't register url " << input_invoice->photo_url_; + } + } else { + auto url = r_http_url.ok().get_url(); + auto r_invoice_file_id = td->file_manager_->from_persistent_id(url, FileType::Temp); + if (r_invoice_file_id.is_error()) { + LOG(INFO) << "Can't register url " << url; + } else { + auto invoice_file_id = r_invoice_file_id.move_as_ok(); + + PhotoSize s; + s.type = 'n'; + s.dimensions = + get_dimensions(input_invoice->photo_width_, input_invoice->photo_height_, "process_input_message_invoice"); + s.size = input_invoice->photo_size_; // TODO use invoice_file_id size + s.file_id = invoice_file_id; + + result.photo.id = 0; + result.photo.photos.push_back(s); + } + } + result.start_parameter = std::move(input_invoice->start_parameter_); + + result.invoice.currency = std::move(input_invoice->invoice_->currency_); + result.invoice.price_parts.reserve(input_invoice->invoice_->price_parts_.size()); + int64 total_amount = 0; + const int64 MAX_AMOUNT = 9999'9999'9999; + for (auto &price : input_invoice->invoice_->price_parts_) { + if (!clean_input_string(price->label_)) { + return Status::Error(400, "Invoice price label must be encoded in UTF-8"); + } + result.invoice.price_parts.emplace_back(std::move(price->label_), price->amount_); + if (price->amount_ < -MAX_AMOUNT || price->amount_ > MAX_AMOUNT) { + return Status::Error(400, "Too big amount of the currency specified"); + } + total_amount += price->amount_; + } + if (total_amount <= 0) { + return Status::Error(400, "Total price must be positive"); + } + if (total_amount > MAX_AMOUNT) { + return Status::Error(400, "Total price is too big"); + } + result.total_amount = total_amount; + + if (input_invoice->invoice_->max_tip_amount_ < 0 || input_invoice->invoice_->max_tip_amount_ > MAX_AMOUNT) { + return Status::Error(400, "Invalid max tip amount of the currency specified"); + } + for (auto tip_amount : input_invoice->invoice_->suggested_tip_amounts_) { + if (tip_amount < 0 || tip_amount > input_invoice->invoice_->max_tip_amount_) { + return Status::Error(400, "Invalid suggested tip amount of the currency specified"); + } + } + + result.invoice.max_tip_amount = input_invoice->invoice_->max_tip_amount_; + result.invoice.suggested_tip_amounts = std::move(input_invoice->invoice_->suggested_tip_amounts_); + result.invoice.is_test = input_invoice->invoice_->is_test_; + result.invoice.need_name = input_invoice->invoice_->need_name_; + result.invoice.need_phone_number = input_invoice->invoice_->need_phone_number_; + result.invoice.need_email_address = input_invoice->invoice_->need_email_address_; + result.invoice.need_shipping_address = input_invoice->invoice_->need_shipping_address_; + result.invoice.send_phone_number_to_provider = input_invoice->invoice_->send_phone_number_to_provider_; + result.invoice.send_email_address_to_provider = input_invoice->invoice_->send_email_address_to_provider_; + result.invoice.is_flexible = input_invoice->invoice_->is_flexible_; + if (result.invoice.send_phone_number_to_provider) { + result.invoice.need_phone_number = true; + } + if (result.invoice.send_email_address_to_provider) { + result.invoice.need_email_address = true; + } + if (result.invoice.is_flexible) { + result.invoice.need_shipping_address = true; + } + + result.payload = std::move(input_invoice->payload_); + result.provider_token = std::move(input_invoice->provider_token_); + result.provider_data = std::move(input_invoice->provider_data_); + return result; +} + +tl_object_ptr get_message_invoice_object(const InputInvoice &input_invoice, Td *td) { + return make_tl_object( + input_invoice.title, input_invoice.description, get_photo_object(td->file_manager_.get(), input_invoice.photo), + input_invoice.invoice.currency, input_invoice.total_amount, input_invoice.start_parameter, + input_invoice.invoice.is_test, input_invoice.invoice.need_shipping_address, + input_invoice.receipt_message_id.get()); +} + +static tl_object_ptr get_input_invoice(const Invoice &invoice) { + int32 flags = 0; + if (invoice.is_test) { + flags |= telegram_api::invoice::TEST_MASK; + } + if (invoice.need_name) { + flags |= telegram_api::invoice::NAME_REQUESTED_MASK; + } + if (invoice.need_phone_number) { + flags |= telegram_api::invoice::PHONE_REQUESTED_MASK; + } + if (invoice.need_email_address) { + flags |= telegram_api::invoice::EMAIL_REQUESTED_MASK; + } + if (invoice.need_shipping_address) { + flags |= telegram_api::invoice::SHIPPING_ADDRESS_REQUESTED_MASK; + } + if (invoice.send_phone_number_to_provider) { + flags |= telegram_api::invoice::PHONE_TO_PROVIDER_MASK; + } + if (invoice.send_email_address_to_provider) { + flags |= telegram_api::invoice::EMAIL_TO_PROVIDER_MASK; + } + if (invoice.is_flexible) { + flags |= telegram_api::invoice::FLEXIBLE_MASK; + } + if (invoice.max_tip_amount != 0) { + flags |= telegram_api::invoice::MAX_TIP_AMOUNT_MASK; + } + + auto prices = transform(invoice.price_parts, [](const LabeledPricePart &price) { + return telegram_api::make_object(price.label, price.amount); + }); + return make_tl_object( + flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, + false /*ignored*/, false /*ignored*/, false /*ignored*/, invoice.currency, std::move(prices), + invoice.max_tip_amount, vector(invoice.suggested_tip_amounts)); +} + +static tl_object_ptr get_input_web_document(const FileManager *file_manager, + const Photo &photo) { + if (photo.is_empty()) { + return nullptr; + } + + CHECK(photo.photos.size() == 1); + const PhotoSize &size = photo.photos[0]; + CHECK(size.file_id.is_valid()); + + vector> attributes; + if (size.dimensions.width != 0 && size.dimensions.height != 0) { + attributes.push_back( + make_tl_object(size.dimensions.width, size.dimensions.height)); + } + + auto file_view = file_manager->get_file_view(size.file_id); + CHECK(file_view.has_url()); + + auto file_name = get_url_file_name(file_view.url()); + return make_tl_object( + file_view.url(), size.size, MimeType::from_extension(PathView(file_name).extension(), "image/jpeg"), + std::move(attributes)); +} + +tl_object_ptr get_input_media_invoice(const InputInvoice &input_invoice, Td *td) { + int32 flags = telegram_api::inputMediaInvoice::START_PARAM_MASK; + auto input_web_document = get_input_web_document(td->file_manager_.get(), input_invoice.photo); + if (input_web_document != nullptr) { + flags |= telegram_api::inputMediaInvoice::PHOTO_MASK; + } + + return make_tl_object( + flags, input_invoice.title, input_invoice.description, std::move(input_web_document), + get_input_invoice(input_invoice.invoice), BufferSlice(input_invoice.payload), input_invoice.provider_token, + telegram_api::make_object( + input_invoice.provider_data.empty() ? "null" : input_invoice.provider_data), + input_invoice.start_parameter); +} + +vector get_input_invoice_file_ids(const InputInvoice &input_invoice) { + return photo_get_file_ids(input_invoice.photo); +} + bool operator==(const Address &lhs, const Address &rhs) { return lhs.country_code == rhs.country_code && lhs.state == rhs.state && lhs.city == rhs.city && lhs.street_line1 == rhs.street_line1 && lhs.street_line2 == rhs.street_line2 && diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index 66b9e4abd..9675654f1 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -9,19 +9,21 @@ #include "td/actor/PromiseFuture.h" #include "td/telegram/DialogId.h" +#include "td/telegram/MessageId.h" #include "td/telegram/Photo.h" #include "td/telegram/ServerMessageId.h" +#include "td/telegram/td_api.h" +#include "td/telegram/telegram_api.h" #include "td/utils/common.h" #include "td/utils/Slice.h" #include "td/utils/Status.h" #include "td/utils/StringBuilder.h" -#include "td/telegram/td_api.h" -#include "td/telegram/telegram_api.h" - namespace td { +class Td; + struct LabeledPricePart { string label; int64 amount = 0; @@ -51,6 +53,20 @@ struct Invoice { } }; +struct InputInvoice { + string title; + string description; + Photo photo; + string start_parameter; + Invoice invoice; + string payload; + string provider_token; + string provider_data; + + int64 total_amount = 0; + MessageId receipt_message_id; +}; + struct Address { string country_code; string state; @@ -102,6 +118,21 @@ bool operator!=(const Invoice &lhs, const Invoice &rhs); StringBuilder &operator<<(StringBuilder &string_builder, const Invoice &invoice); +bool operator==(const InputInvoice &lhs, const InputInvoice &rhs); +bool operator!=(const InputInvoice &lhs, const InputInvoice &rhs); + +InputInvoice get_input_invoice(tl_object_ptr &&message_invoice, Td *td, + DialogId owner_dialog_id); + +Result process_input_message_invoice(td_api::object_ptr &&input_invoice, + Td *td); + +tl_object_ptr get_message_invoice_object(const InputInvoice &input_invoice, Td *td); + +tl_object_ptr get_input_media_invoice(const InputInvoice &input_invoice, Td *td); + +vector get_input_invoice_file_ids(const InputInvoice &input_invoice); + bool operator==(const Address &lhs, const Address &rhs); bool operator!=(const Address &lhs, const Address &rhs); diff --git a/td/telegram/Payments.hpp b/td/telegram/Payments.hpp index 330a880c2..b52f4db73 100644 --- a/td/telegram/Payments.hpp +++ b/td/telegram/Payments.hpp @@ -9,6 +9,7 @@ #include "td/telegram/Payments.h" #include "td/telegram/Photo.hpp" +#include "td/telegram/Version.h" #include "td/utils/tl_helpers.h" @@ -70,6 +71,38 @@ void parse(Invoice &invoice, ParserT &parser) { } } +template +void store(const InputInvoice &input_invoice, StorerT &storer) { + store(input_invoice.title, storer); + store(input_invoice.description, storer); + store(input_invoice.photo, storer); + store(input_invoice.start_parameter, storer); + store(input_invoice.invoice, storer); + store(input_invoice.payload, storer); + store(input_invoice.provider_token, storer); + store(input_invoice.provider_data, storer); + store(input_invoice.total_amount, storer); + store(input_invoice.receipt_message_id, storer); +} + +template +void parse(InputInvoice &input_invoice, ParserT &parser) { + parse(input_invoice.title, parser); + parse(input_invoice.description, parser); + parse(input_invoice.photo, parser); + parse(input_invoice.start_parameter, parser); + parse(input_invoice.invoice, parser); + parse(input_invoice.payload, parser); + parse(input_invoice.provider_token, parser); + if (parser.version() >= static_cast(Version::AddMessageInvoiceProviderData)) { + parse(input_invoice.provider_data, parser); + } else { + input_invoice.provider_data.clear(); + } + parse(input_invoice.total_amount, parser); + parse(input_invoice.receipt_message_id, parser); +} + template void store(const Address &address, StorerT &storer) { store(address.country_code, storer); From 2379735d9b4959b687ea39acbe3efc0b7c5178b5 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 01:55:12 +0300 Subject: [PATCH 153/281] Support sending Invoice as result of any inline query. --- td/generate/scheme/td_api.tl | 22 +++++++++++----------- td/telegram/InlineQueriesManager.cpp | 5 +++++ td/telegram/MessageContent.cpp | 3 +-- td/telegram/Payments.cpp | 23 +++++++++++++++++++++-- td/telegram/Payments.h | 7 +++++-- 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index cac2ce2aa..e91668256 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2247,30 +2247,30 @@ httpUrl url:string = HttpUrl; //@video_url The URL of the video file (file size must not exceed 1MB) @video_mime_type MIME type of the video file. Must be one of "image/gif" and "video/mp4" //@video_duration Duration of the video, in seconds @video_width Width of the video @video_height Height of the video //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageAnimation, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageAnimation, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact inputInlineQueryResultAnimation id:string title:string thumbnail_url:string thumbnail_mime_type:string video_url:string video_mime_type:string video_duration:int32 video_width:int32 video_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to an article or web page @id Unique identifier of the query result @url URL of the result, if it exists @hide_url True, if the URL must be not shown @title Title of the result //@param_description A short description of the result @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact inputInlineQueryResultArticle id:string url:string hide_url:Bool title:string description:string thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to an MP3 audio file @id Unique identifier of the query result @title Title of the audio file @performer Performer of the audio file //@audio_url The URL of the audio file @audio_duration Audio file duration, in seconds //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageAudio, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageAudio, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact inputInlineQueryResultAudio id:string title:string performer:string audio_url:string audio_duration:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a user contact @id Unique identifier of the query result @contact User contact @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact inputInlineQueryResultContact id:string contact:contact thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to a file @id Unique identifier of the query result @title Title of the resulting file @param_description Short description of the result, if known @document_url URL of the file @mime_type MIME type of the file content; only "application/pdf" and "application/zip" are currently allowed //@thumbnail_url The URL of the file thumbnail, if it exists @thumbnail_width Width of the thumbnail @thumbnail_height Height of the thumbnail //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageDocument, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageDocument, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact inputInlineQueryResultDocument id:string title:string description:string document_url:string mime_type:string thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a game @id Unique identifier of the query result @game_short_name Short name of the game @reply_markup Message reply markup. Must be of type replyMarkupInlineKeyboard or null @@ -2280,37 +2280,37 @@ inputInlineQueryResultGame id:string game_short_name:string reply_markup:ReplyMa //@live_period Amount of time relative to the message sent time until the location can be updated, in seconds //@title Title of the result @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact inputInlineQueryResultLocation id:string location:location live_period:int32 title:string thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents link to a JPEG image @id Unique identifier of the query result @title Title of the result, if known @param_description A short description of the result, if known @thumbnail_url URL of the photo thumbnail, if it exists //@photo_url The URL of the JPEG photo (photo size must not exceed 5MB) @photo_width Width of the photo @photo_height Height of the photo //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessagePhoto, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessagePhoto, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact inputInlineQueryResultPhoto id:string title:string description:string thumbnail_url:string photo_url:string photo_width:int32 photo_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to a WEBP or TGS sticker @id Unique identifier of the query result @thumbnail_url URL of the sticker thumbnail, if it exists //@sticker_url The URL of the WEBP or TGS sticker (sticker file size must not exceed 5MB) @sticker_width Width of the sticker @sticker_height Height of the sticker //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, inputMessageSticker, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, inputMessageSticker, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact inputInlineQueryResultSticker id:string thumbnail_url:string sticker_url:string sticker_width:int32 sticker_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents information about a venue @id Unique identifier of the query result @venue Venue result @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact inputInlineQueryResultVenue id:string venue:venue thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to a page containing an embedded video player or a video file @id Unique identifier of the query result @title Title of the result @param_description A short description of the result, if known //@thumbnail_url The URL of the video thumbnail (JPEG), if it exists @video_url URL of the embedded video player or video file @mime_type MIME type of the content of the video URL, only "text/html" or "video/mp4" are currently supported //@video_width Width of the video @video_height Height of the video @video_duration Video duration, in seconds //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageVideo, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageVideo, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact inputInlineQueryResultVideo id:string title:string description:string thumbnail_url:string video_url:string mime_type:string video_width:int32 video_height:int32 video_duration:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to an opus-encoded audio file within an OGG container, single channel audio @id Unique identifier of the query result @title Title of the voice note //@voice_note_url The URL of the voice note file @voice_note_duration Duration of the voice note, in seconds //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageVoiceNote, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageVoiceNote, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact inputInlineQueryResultVoiceNote id:string title:string voice_note_url:string voice_note_duration:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; diff --git a/td/telegram/InlineQueriesManager.cpp b/td/telegram/InlineQueriesManager.cpp index 8a0cc3fe2..6c1ba0fd2 100644 --- a/td/telegram/InlineQueriesManager.cpp +++ b/td/telegram/InlineQueriesManager.cpp @@ -29,6 +29,7 @@ #include "td/telegram/MessageEntity.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/misc.h" +#include "td/telegram/Payments.h" #include "td/telegram/Photo.h" #include "td/telegram/ReplyMarkup.h" #include "td/telegram/StickersManager.h" @@ -254,6 +255,10 @@ Result> InlineQueriesManager: TRY_RESULT(contact, process_input_message_contact(std::move(input_message_content))); return contact.get_input_bot_inline_message_media_contact(flags, std::move(input_reply_markup)); } + if (constructor_id == td_api::inputMessageInvoice::ID) { + TRY_RESULT(input_invoice, process_input_message_invoice(std::move(input_message_content), td_)); + return get_input_bot_inline_message_media_invoice(input_invoice, flags, std::move(input_reply_markup), td_); + } if (constructor_id == td_api::inputMessageLocation::ID) { TRY_RESULT(location, process_input_message_location(std::move(input_message_content))); if (location.heading != 0) { diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index e79afc6a9..f6f98c6ef 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -1766,8 +1766,7 @@ static Result create_input_message_content( return Status::Error(400, "Invoices can be sent only by bots"); } - TRY_RESULT(input_invoice, process_input_message_invoice( - move_tl_object_as(input_message_content), td)); + TRY_RESULT(input_invoice, process_input_message_invoice(std::move(input_message_content), td)); content = make_unique(std::move(input_invoice)); break; } diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 9abefaf8e..f2a7c204a 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -640,8 +640,12 @@ InputInvoice get_input_invoice(tl_object_ptr return result; } -Result process_input_message_invoice(td_api::object_ptr &&input_invoice, - Td *td) { +Result process_input_message_invoice( + td_api::object_ptr &&input_message_content, Td *td) { + CHECK(input_message_content != nullptr); + CHECK(input_message_content->get_id() == td_api::inputMessageInvoice::ID); + auto input_invoice = move_tl_object_as(input_message_content); + if (!clean_input_string(input_invoice->title_)) { return Status::Error(400, "Invoice title must be encoded in UTF-8"); } @@ -838,6 +842,21 @@ tl_object_ptr get_input_media_invoice(const Inp input_invoice.start_parameter); } +tl_object_ptr get_input_bot_inline_message_media_invoice( + const InputInvoice &input_invoice, int32 flags, tl_object_ptr &&reply_markup, Td *td) { + auto input_web_document = get_input_web_document(td->file_manager_.get(), input_invoice.photo); + if (input_web_document != nullptr) { + flags |= telegram_api::inputMediaInvoice::PHOTO_MASK; + } + return make_tl_object( + flags, false /*ignored*/, false /*ignored*/, input_invoice.title, input_invoice.description, + std::move(input_web_document), get_input_invoice(input_invoice.invoice), BufferSlice(input_invoice.payload), + input_invoice.provider_token, + telegram_api::make_object( + input_invoice.provider_data.empty() ? "null" : input_invoice.provider_data), + input_invoice.start_parameter, std::move(reply_markup)); +} + vector get_input_invoice_file_ids(const InputInvoice &input_invoice) { return photo_get_file_ids(input_invoice.photo); } diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index 9675654f1..7061aa7ce 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -124,13 +124,16 @@ bool operator!=(const InputInvoice &lhs, const InputInvoice &rhs); InputInvoice get_input_invoice(tl_object_ptr &&message_invoice, Td *td, DialogId owner_dialog_id); -Result process_input_message_invoice(td_api::object_ptr &&input_invoice, - Td *td); +Result process_input_message_invoice( + td_api::object_ptr &&input_message_content, Td *td); tl_object_ptr get_message_invoice_object(const InputInvoice &input_invoice, Td *td); tl_object_ptr get_input_media_invoice(const InputInvoice &input_invoice, Td *td); +tl_object_ptr get_input_bot_inline_message_media_invoice( + const InputInvoice &input_invoice, int32 flags, tl_object_ptr &&reply_markup, Td *td); + vector get_input_invoice_file_ids(const InputInvoice &input_invoice); bool operator==(const Address &lhs, const Address &rhs); From d7afe3d3e2d6dd165ba563dd3f653475adecbc50 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 02:02:53 +0300 Subject: [PATCH 154/281] Simplify variable names in create_inline_message_content. --- td/telegram/MessageContent.cpp | 75 ++++++++++++++++------------------ td/telegram/MessageContent.h | 2 +- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index f6f98c6ef..121ccb5fd 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -1417,9 +1417,9 @@ void parse_message_content(unique_ptr &content, LogEventParser & } InlineMessageContent create_inline_message_content(Td *td, FileId file_id, - tl_object_ptr &&inline_message, + tl_object_ptr &&bot_inline_message, int32 allowed_media_content_id, Photo *photo, Game *game) { - CHECK(inline_message != nullptr); + CHECK(bot_inline_message != nullptr); CHECK((allowed_media_content_id == td_api::inputMessagePhoto::ID) == (photo != nullptr)); CHECK((allowed_media_content_id == td_api::inputMessageGame::ID) == (game != nullptr)); CHECK((allowed_media_content_id != td_api::inputMessagePhoto::ID && @@ -1429,72 +1429,69 @@ InlineMessageContent create_inline_message_content(Td *td, FileId file_id, InlineMessageContent result; tl_object_ptr reply_markup; result.disable_web_page_preview = false; - switch (inline_message->get_id()) { + switch (bot_inline_message->get_id()) { case telegram_api::botInlineMessageText::ID: { - auto inline_message_text = move_tl_object_as(inline_message); - auto entities = get_message_entities(td->contacts_manager_.get(), std::move(inline_message_text->entities_), + auto inline_message = move_tl_object_as(bot_inline_message); + auto entities = get_message_entities(td->contacts_manager_.get(), std::move(inline_message->entities_), "botInlineMessageText"); - auto status = fix_formatted_text(inline_message_text->message_, entities, false, true, true, false); + auto status = fix_formatted_text(inline_message->message_, entities, false, true, true, false); if (status.is_error()) { - LOG(ERROR) << "Receive error " << status << " while parsing botInlineMessageText " - << inline_message_text->message_; + LOG(ERROR) << "Receive error " << status << " while parsing botInlineMessageText " << inline_message->message_; break; } result.disable_web_page_preview = - (inline_message_text->flags_ & telegram_api::botInlineMessageText::NO_WEBPAGE_MASK) != 0; + (inline_message->flags_ & telegram_api::botInlineMessageText::NO_WEBPAGE_MASK) != 0; WebPageId web_page_id; if (!result.disable_web_page_preview) { - web_page_id = - td->web_pages_manager_->get_web_page_by_url(get_first_url(inline_message_text->message_, entities)); + web_page_id = td->web_pages_manager_->get_web_page_by_url(get_first_url(inline_message->message_, entities)); } result.message_content = make_unique( - FormattedText{std::move(inline_message_text->message_), std::move(entities)}, web_page_id); - reply_markup = std::move(inline_message_text->reply_markup_); + FormattedText{std::move(inline_message->message_), std::move(entities)}, web_page_id); + reply_markup = std::move(inline_message->reply_markup_); break; } case telegram_api::botInlineMessageMediaGeo::ID: { - auto inline_message_geo = move_tl_object_as(inline_message); - if ((inline_message_geo->flags_ & telegram_api::botInlineMessageMediaGeo::PERIOD_MASK) != 0 && - inline_message_geo->period_ > 0) { - auto heading = (inline_message_geo->flags_ & telegram_api::botInlineMessageMediaGeo::HEADING_MASK) != 0 - ? inline_message_geo->heading_ + auto inline_message = move_tl_object_as(bot_inline_message); + if ((inline_message->flags_ & telegram_api::botInlineMessageMediaGeo::PERIOD_MASK) != 0 && + inline_message->period_ > 0) { + auto heading = (inline_message->flags_ & telegram_api::botInlineMessageMediaGeo::HEADING_MASK) != 0 + ? inline_message->heading_ : 0; auto approacing_notification_radius = - (inline_message_geo->flags_ & telegram_api::botInlineMessageMediaGeo::PROXIMITY_NOTIFICATION_RADIUS_MASK) != - 0 - ? inline_message_geo->proximity_notification_radius_ + (inline_message->flags_ & telegram_api::botInlineMessageMediaGeo::PROXIMITY_NOTIFICATION_RADIUS_MASK) != 0 + ? inline_message->proximity_notification_radius_ : 0; result.message_content = make_unique( - Location(inline_message_geo->geo_), inline_message_geo->period_, heading, approacing_notification_radius); + Location(inline_message->geo_), inline_message->period_, heading, approacing_notification_radius); } else { - result.message_content = make_unique(Location(inline_message_geo->geo_)); + result.message_content = make_unique(Location(inline_message->geo_)); } - reply_markup = std::move(inline_message_geo->reply_markup_); + reply_markup = std::move(inline_message->reply_markup_); break; } case telegram_api::botInlineMessageMediaVenue::ID: { - auto inline_message_venue = move_tl_object_as(inline_message); + auto inline_message = move_tl_object_as(bot_inline_message); result.message_content = make_unique( - Venue(inline_message_venue->geo_, std::move(inline_message_venue->title_), - std::move(inline_message_venue->address_), std::move(inline_message_venue->provider_), - std::move(inline_message_venue->venue_id_), std::move(inline_message_venue->venue_type_))); - reply_markup = std::move(inline_message_venue->reply_markup_); + Venue(inline_message->geo_, std::move(inline_message->title_), std::move(inline_message->address_), + std::move(inline_message->provider_), std::move(inline_message->venue_id_), + std::move(inline_message->venue_type_))); + reply_markup = std::move(inline_message->reply_markup_); break; } case telegram_api::botInlineMessageMediaContact::ID: { - auto inline_message_contact = move_tl_object_as(inline_message); + auto inline_message = move_tl_object_as(bot_inline_message); result.message_content = make_unique( - Contact(std::move(inline_message_contact->phone_number_), std::move(inline_message_contact->first_name_), - std::move(inline_message_contact->last_name_), std::move(inline_message_contact->vcard_), UserId())); - reply_markup = std::move(inline_message_contact->reply_markup_); + Contact(std::move(inline_message->phone_number_), std::move(inline_message->first_name_), + std::move(inline_message->last_name_), std::move(inline_message->vcard_), UserId())); + reply_markup = std::move(inline_message->reply_markup_); break; } case telegram_api::botInlineMessageMediaAuto::ID: { - auto input_message_media_auto = move_tl_object_as(inline_message); - auto caption = get_message_text(td->contacts_manager_.get(), input_message_media_auto->message_, - std::move(input_message_media_auto->entities_), true, 0, false, - "register_inline_message_content"); + auto inline_message = move_tl_object_as(bot_inline_message); + auto caption = + get_message_text(td->contacts_manager_.get(), inline_message->message_, std::move(inline_message->entities_), + true, 0, false, "create_inline_message_content"); if (allowed_media_content_id == td_api::inputMessageAnimation::ID) { result.message_content = make_unique(file_id, std::move(caption)); } else if (allowed_media_content_id == td_api::inputMessageAudio::ID) { @@ -1514,10 +1511,10 @@ InlineMessageContent create_inline_message_content(Td *td, FileId file_id, } else if (allowed_media_content_id == td_api::inputMessageVoiceNote::ID) { result.message_content = make_unique(file_id, std::move(caption), true); } else { - LOG(WARNING) << "Unallowed bot inline message " << to_string(input_message_media_auto); + LOG(WARNING) << "Unallowed bot inline message " << to_string(inline_message); } - reply_markup = std::move(input_message_media_auto->reply_markup_); + reply_markup = std::move(inline_message->reply_markup_); break; } default: diff --git a/td/telegram/MessageContent.h b/td/telegram/MessageContent.h index 179f2c9d6..b9dae31b8 100644 --- a/td/telegram/MessageContent.h +++ b/td/telegram/MessageContent.h @@ -87,7 +87,7 @@ void store_message_content(const MessageContent *content, LogEventStorerUnsafe & void parse_message_content(unique_ptr &content, LogEventParser &parser); InlineMessageContent create_inline_message_content(Td *td, FileId file_id, - tl_object_ptr &&inline_message, + tl_object_ptr &&bot_inline_message, int32 allowed_media_content_id, Photo *photo, Game *game); unique_ptr create_text_message_content(string text, vector entities, From 32a5fc6855da3ea2ccf24a70ef66addabf89fa5f Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 02:38:16 +0300 Subject: [PATCH 155/281] Support sending messageInvoice via inline mode. --- td/generate/scheme/td_api.tl | 13 +++++++++---- td/telegram/MessageContent.cpp | 7 +++++++ td/telegram/Payments.cpp | 26 ++++++++++++++++++++++---- td/telegram/Payments.h | 3 +++ 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index e91668256..c8469531b 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -1309,13 +1309,18 @@ address country_code:string state:string city:string street_line1:string street_ //@description Portion of the price of a product (e.g., "delivery cost", "tax amount") @label Label for this portion of the product price @amount Currency amount in the smallest units of the currency labeledPricePart label:string amount:int53 = LabeledPricePart; -//@description Product invoice @currency ISO 4217 currency code @price_parts A list of objects used to calculate the total price of the product +//@description Product invoice @currency ISO 4217 currency code +//@price_parts A list of objects used to calculate the total price of the product //@max_tip_amount The maximum allowed amount of tip in the smallest units of the currency //@suggested_tip_amounts Suggested amounts of tip in the smallest units of the currency //@is_test True, if the payment is a test payment -//@need_name True, if the user's name is needed for payment @need_phone_number True, if the user's phone number is needed for payment @need_email_address True, if the user's email address is needed for payment -//@need_shipping_address True, if the user's shipping address is needed for payment @send_phone_number_to_provider True, if the user's phone number will be sent to the provider -//@send_email_address_to_provider True, if the user's email address will be sent to the provider @is_flexible True, if the total price depends on the shipping method +//@need_name True, if the user's name is needed for payment +//@need_phone_number True, if the user's phone number is needed for payment +//@need_email_address True, if the user's email address is needed for payment +//@need_shipping_address True, if the user's shipping address is needed for payment +//@send_phone_number_to_provider True, if the user's phone number will be sent to the provider +//@send_email_address_to_provider True, if the user's email address will be sent to the provider +//@is_flexible True, if the total price depends on the shipping method invoice currency:string price_parts:vector max_tip_amount:int53 suggested_tip_amounts:vector is_test:Bool need_name:Bool need_phone_number:Bool need_email_address:Bool need_shipping_address:Bool send_phone_number_to_provider:Bool send_email_address_to_provider:Bool is_flexible:Bool = Invoice; //@description Order information @name Name of the user @phone_number Phone number of the user @email_address Email address of the user @shipping_address Shipping address for this order; may be null diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 121ccb5fd..7b42a85d0 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -1451,6 +1451,13 @@ InlineMessageContent create_inline_message_content(Td *td, FileId file_id, reply_markup = std::move(inline_message->reply_markup_); break; } + case telegram_api::botInlineMessageMediaInvoice::ID: { + auto inline_message = move_tl_object_as(bot_inline_message); + reply_markup = std::move(inline_message->reply_markup_); + result.message_content = + make_unique(get_input_invoice(std::move(inline_message), td, DialogId())); + break; + } case telegram_api::botInlineMessageMediaGeo::ID: { auto inline_message = move_tl_object_as(bot_inline_message); if ((inline_message->flags_ & telegram_api::botInlineMessageMediaGeo::PERIOD_MASK) != 0 && diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index f2a7c204a..566892e73 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -640,6 +640,25 @@ InputInvoice get_input_invoice(tl_object_ptr return result; } +InputInvoice get_input_invoice(tl_object_ptr &&message_invoice, Td *td, + DialogId owner_dialog_id) { + InputInvoice result; + result.title = std::move(message_invoice->title_); + result.description = std::move(message_invoice->description_); + result.photo = get_web_document_photo(td->file_manager_.get(), std::move(message_invoice->photo_), owner_dialog_id); + // result.start_parameter = string(); + result.invoice.currency = std::move(message_invoice->currency_); + result.invoice.is_test = (message_invoice->flags_ & telegram_api::messageMediaInvoice::TEST_MASK) != 0; + result.invoice.need_shipping_address = + (message_invoice->flags_ & telegram_api::messageMediaInvoice::SHIPPING_ADDRESS_REQUESTED_MASK) != 0; + // result.payload = string(); + // result.provider_token = string(); + // result.provider_data = string(); + result.total_amount = message_invoice->total_amount_; + // result.receipt_message_id = MessageId(); + return result; +} + Result process_input_message_invoice( td_api::object_ptr &&input_message_content, Td *td) { CHECK(input_message_content != nullptr); @@ -849,12 +868,11 @@ tl_object_ptr get_input_bot_inl flags |= telegram_api::inputMediaInvoice::PHOTO_MASK; } return make_tl_object( - flags, false /*ignored*/, false /*ignored*/, input_invoice.title, input_invoice.description, - std::move(input_web_document), get_input_invoice(input_invoice.invoice), BufferSlice(input_invoice.payload), - input_invoice.provider_token, + flags, input_invoice.title, input_invoice.description, std::move(input_web_document), + get_input_invoice(input_invoice.invoice), BufferSlice(input_invoice.payload), input_invoice.provider_token, telegram_api::make_object( input_invoice.provider_data.empty() ? "null" : input_invoice.provider_data), - input_invoice.start_parameter, std::move(reply_markup)); + std::move(reply_markup)); } vector get_input_invoice_file_ids(const InputInvoice &input_invoice) { diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index 7061aa7ce..813b81040 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -124,6 +124,9 @@ bool operator!=(const InputInvoice &lhs, const InputInvoice &rhs); InputInvoice get_input_invoice(tl_object_ptr &&message_invoice, Td *td, DialogId owner_dialog_id); +InputInvoice get_input_invoice(tl_object_ptr &&message_invoice, Td *td, + DialogId owner_dialog_id); + Result process_input_message_invoice( td_api::object_ptr &&input_message_content, Td *td); From aa65e2b58616c76d119ea20fd6f878c8caba1a8e Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 02:45:10 +0300 Subject: [PATCH 156/281] Allow to send invoice messages in all chat types. --- td/telegram/InlineQueriesManager.cpp | 1 + td/telegram/MessagesManager.cpp | 20 ++++++-------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/td/telegram/InlineQueriesManager.cpp b/td/telegram/InlineQueriesManager.cpp index 6c1ba0fd2..a35d146be 100644 --- a/td/telegram/InlineQueriesManager.cpp +++ b/td/telegram/InlineQueriesManager.cpp @@ -1754,6 +1754,7 @@ bool InlineQueriesManager::load_recently_used_bots(Promise &promise) { tl_object_ptr InlineQueriesManager::get_inline_query_results_object(uint64 query_hash) { // TODO filter out games if request is sent in a broadcast channel or in a secret chat + // TODO filter out invoice messages if request is sent in a secret chat return decrease_pending_request_count(query_hash); } diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 86a073f67..88625dceb 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -23134,7 +23134,7 @@ Status MessagesManager::can_send_message_content(DialogId dialog_id, const Messa break; case MessageContentType::Audio: if (!permissions.can_send_media()) { - return Status::Error(400, "Not enough rights to send audios to the chat"); + return Status::Error(400, "Not enough rights to send music to the chat"); } break; case MessageContentType::Contact: @@ -23167,19 +23167,11 @@ Status MessagesManager::can_send_message_content(DialogId dialog_id, const Messa } break; case MessageContentType::Invoice: - if (!is_forward) { - switch (dialog_type) { - case DialogType::User: - // ok - break; - case DialogType::Chat: - case DialogType::Channel: - case DialogType::SecretChat: - return Status::Error(400, "Invoices can be sent only to private chats"); - case DialogType::None: - default: - UNREACHABLE(); - } + if (!permissions.can_send_messages()) { + return Status::Error(400, "Not enough rights to send invoice messages to the chat"); + } + if (dialog_type == DialogType::SecretChat) { + return Status::Error(400, "Invoice messages can't be sent to secret chats"); } break; case MessageContentType::LiveLocation: From 6cf3755707389319cca0a3bd557499605ef43a30 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 02:54:29 +0300 Subject: [PATCH 157/281] Improve get_input_bot_inline_message_media_* functions. --- td/telegram/Contact.cpp | 6 +++++- td/telegram/Contact.h | 2 +- td/telegram/InlineQueriesManager.cpp | 26 ++++++++++++++++---------- td/telegram/Payments.cpp | 8 ++++++-- td/telegram/Payments.h | 2 +- td/telegram/Venue.cpp | 6 +++++- td/telegram/Venue.h | 3 +-- 7 files changed, 35 insertions(+), 18 deletions(-) diff --git a/td/telegram/Contact.cpp b/td/telegram/Contact.cpp index f75af4567..e9388a66d 100644 --- a/td/telegram/Contact.cpp +++ b/td/telegram/Contact.cpp @@ -58,7 +58,11 @@ tl_object_ptr Contact::get_input_phone_contact( } tl_object_ptr Contact::get_input_bot_inline_message_media_contact( - int32 flags, tl_object_ptr &&reply_markup) const { + tl_object_ptr &&reply_markup) const { + int32 flags = 0; + if (reply_markup != nullptr) { + flags |= telegram_api::inputBotInlineMessageMediaContact::REPLY_MARKUP_MASK; + } return make_tl_object(flags, phone_number_, first_name_, last_name_, vcard_, std::move(reply_markup)); } diff --git a/td/telegram/Contact.h b/td/telegram/Contact.h index 5617f1bb1..5ab981018 100644 --- a/td/telegram/Contact.h +++ b/td/telegram/Contact.h @@ -57,7 +57,7 @@ class Contact { tl_object_ptr get_input_phone_contact(int64 client_id) const; tl_object_ptr get_input_bot_inline_message_media_contact( - int32 flags, tl_object_ptr &&reply_markup) const; + tl_object_ptr &&reply_markup) const; template void store(StorerT &storer) const { diff --git a/td/telegram/InlineQueriesManager.cpp b/td/telegram/InlineQueriesManager.cpp index a35d146be..96411055b 100644 --- a/td/telegram/InlineQueriesManager.cpp +++ b/td/telegram/InlineQueriesManager.cpp @@ -229,16 +229,15 @@ Result> InlineQueriesManager: } TRY_RESULT(reply_markup, get_reply_markup(std::move(reply_markup_ptr), true, true, false, true)); auto input_reply_markup = get_input_reply_markup(reply_markup); - int32 flags = 0; - if (input_reply_markup != nullptr) { - flags |= telegram_api::inputBotInlineMessageText::REPLY_MARKUP_MASK; - } auto constructor_id = input_message_content->get_id(); if (constructor_id == td_api::inputMessageText::ID) { TRY_RESULT(input_message_text, process_input_message_text(td_->contacts_manager_.get(), DialogId(), std::move(input_message_content), true)); - + int32 flags = 0; + if (input_reply_markup != nullptr) { + flags |= telegram_api::inputBotInlineMessageText::REPLY_MARKUP_MASK; + } if (input_message_text.disable_web_page_preview) { flags |= telegram_api::inputBotInlineMessageText::NO_WEBPAGE_MASK; } @@ -253,14 +252,18 @@ Result> InlineQueriesManager: } if (constructor_id == td_api::inputMessageContact::ID) { TRY_RESULT(contact, process_input_message_contact(std::move(input_message_content))); - return contact.get_input_bot_inline_message_media_contact(flags, std::move(input_reply_markup)); + return contact.get_input_bot_inline_message_media_contact(std::move(input_reply_markup)); } if (constructor_id == td_api::inputMessageInvoice::ID) { TRY_RESULT(input_invoice, process_input_message_invoice(std::move(input_message_content), td_)); - return get_input_bot_inline_message_media_invoice(input_invoice, flags, std::move(input_reply_markup), td_); + return get_input_bot_inline_message_media_invoice(input_invoice, std::move(input_reply_markup), td_); } if (constructor_id == td_api::inputMessageLocation::ID) { TRY_RESULT(location, process_input_message_location(std::move(input_message_content))); + int32 flags = 0; + if (input_reply_markup != nullptr) { + flags |= telegram_api::inputBotInlineMessageMediaGeo::REPLY_MARKUP_MASK; + } if (location.heading != 0) { flags |= telegram_api::inputBotInlineMessageMediaGeo::HEADING_MASK; } @@ -274,16 +277,19 @@ Result> InlineQueriesManager: } if (constructor_id == td_api::inputMessageVenue::ID) { TRY_RESULT(venue, process_input_message_venue(std::move(input_message_content))); - return venue.get_input_bot_inline_message_media_venue(flags, std::move(input_reply_markup)); + return venue.get_input_bot_inline_message_media_venue(std::move(input_reply_markup)); } if (constructor_id == allowed_media_content_id) { TRY_RESULT(caption, process_input_caption(td_->contacts_manager_.get(), DialogId(), extract_input_caption(input_message_content), true)); + int32 flags = 0; + if (input_reply_markup != nullptr) { + flags |= telegram_api::inputBotInlineMessageMediaAuto::REPLY_MARKUP_MASK; + } auto entities = get_input_message_entities(td_->contacts_manager_.get(), caption.entities, "get_inline_message"); if (!entities.empty()) { - flags |= telegram_api::inputBotInlineMessageText::ENTITIES_MASK; + flags |= telegram_api::inputBotInlineMessageMediaAuto::ENTITIES_MASK; } - return make_tl_object(flags, caption.text, std::move(entities), std::move(input_reply_markup)); } diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 566892e73..c8e231613 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -862,10 +862,14 @@ tl_object_ptr get_input_media_invoice(const Inp } tl_object_ptr get_input_bot_inline_message_media_invoice( - const InputInvoice &input_invoice, int32 flags, tl_object_ptr &&reply_markup, Td *td) { + const InputInvoice &input_invoice, tl_object_ptr &&reply_markup, Td *td) { + int32 flags = 0; + if (reply_markup != nullptr) { + flags |= telegram_api::inputBotInlineMessageMediaInvoice::REPLY_MARKUP_MASK; + } auto input_web_document = get_input_web_document(td->file_manager_.get(), input_invoice.photo); if (input_web_document != nullptr) { - flags |= telegram_api::inputMediaInvoice::PHOTO_MASK; + flags |= telegram_api::inputBotInlineMessageMediaInvoice::PHOTO_MASK; } return make_tl_object( flags, input_invoice.title, input_invoice.description, std::move(input_web_document), diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index 813b81040..21230d383 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -135,7 +135,7 @@ tl_object_ptr get_message_invoice_object(const InputInvo tl_object_ptr get_input_media_invoice(const InputInvoice &input_invoice, Td *td); tl_object_ptr get_input_bot_inline_message_media_invoice( - const InputInvoice &input_invoice, int32 flags, tl_object_ptr &&reply_markup, Td *td); + const InputInvoice &input_invoice, tl_object_ptr &&reply_markup, Td *td); vector get_input_invoice_file_ids(const InputInvoice &input_invoice); diff --git a/td/telegram/Venue.cpp b/td/telegram/Venue.cpp index 1eee9828f..4d4d785b7 100644 --- a/td/telegram/Venue.cpp +++ b/td/telegram/Venue.cpp @@ -67,7 +67,11 @@ SecretInputMedia Venue::get_secret_input_media_venue() const { } tl_object_ptr Venue::get_input_bot_inline_message_media_venue( - int32 flags, tl_object_ptr &&reply_markup) const { + tl_object_ptr &&reply_markup) const { + int32 flags = 0; + if (reply_markup != nullptr) { + flags |= telegram_api::inputBotInlineMessageMediaVenue::REPLY_MARKUP_MASK; + } return make_tl_object( flags, location_.get_input_geo_point(), title_, address_, provider_, id_, type_, std::move(reply_markup)); } diff --git a/td/telegram/Venue.h b/td/telegram/Venue.h index 240c15821..7174deb14 100644 --- a/td/telegram/Venue.h +++ b/td/telegram/Venue.h @@ -54,9 +54,8 @@ class Venue { SecretInputMedia get_secret_input_media_venue() const; - // TODO very strange function tl_object_ptr get_input_bot_inline_message_media_venue( - int32 flags, tl_object_ptr &&reply_markup) const; + tl_object_ptr &&reply_markup) const; template void store(StorerT &storer) const { From 3ac49bc8b111967d6fda38333679595439d45bed Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 03:18:00 +0300 Subject: [PATCH 158/281] Pass Td to all payments method. --- td/telegram/MessagesManager.cpp | 9 ++--- td/telegram/Payments.cpp | 61 +++++++++++++-------------------- td/telegram/Payments.h | 23 +++++++------ td/telegram/Td.cpp | 12 +++---- 4 files changed, 48 insertions(+), 57 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 88625dceb..9fef40c81 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -37366,7 +37366,7 @@ void MessagesManager::get_payment_form(FullMessageId full_message_id, return promise.set_error(r_message_id.move_as_error()); } - ::td::get_payment_form(full_message_id.get_dialog_id(), r_message_id.ok(), std::move(promise)); + ::td::get_payment_form(td_, full_message_id.get_dialog_id(), r_message_id.ok(), std::move(promise)); } void MessagesManager::validate_order_info(FullMessageId full_message_id, tl_object_ptr order_info, @@ -37377,7 +37377,7 @@ void MessagesManager::validate_order_info(FullMessageId full_message_id, tl_obje return promise.set_error(r_message_id.move_as_error()); } - ::td::validate_order_info(full_message_id.get_dialog_id(), r_message_id.ok(), std::move(order_info), allow_save, + ::td::validate_order_info(td_, full_message_id.get_dialog_id(), r_message_id.ok(), std::move(order_info), allow_save, std::move(promise)); } @@ -37390,7 +37390,7 @@ void MessagesManager::send_payment_form(FullMessageId full_message_id, int64 pay return promise.set_error(r_message_id.move_as_error()); } - ::td::send_payment_form(full_message_id.get_dialog_id(), r_message_id.ok(), payment_form_id, order_info_id, + ::td::send_payment_form(td_, full_message_id.get_dialog_id(), r_message_id.ok(), payment_form_id, order_info_id, shipping_option_id, credentials, tip_amount, std::move(promise)); } @@ -37410,7 +37410,8 @@ void MessagesManager::get_payment_receipt(FullMessageId full_message_id, return promise.set_error(Status::Error(5, "Wrong message identifier")); } - ::td::get_payment_receipt(full_message_id.get_dialog_id(), m->message_id.get_server_message_id(), std::move(promise)); + ::td::get_payment_receipt(td_, full_message_id.get_dialog_id(), m->message_id.get_server_message_id(), + std::move(promise)); } void MessagesManager::remove_sponsored_dialog() { diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index c8e231613..83924a84a 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -1070,7 +1070,8 @@ StringBuilder &operator<<(StringBuilder &string_builder, const ShippingOption &s << " with price parts " << format::as_array(shipping_option.price_parts) << "]"; } -void answer_shipping_query(int64 shipping_query_id, vector> &&shipping_options, +void answer_shipping_query(Td *td, int64 shipping_query_id, + vector> &&shipping_options, const string &error_message, Promise &&promise) { vector> options; for (auto &option : shipping_options) { @@ -1100,28 +1101,21 @@ void answer_shipping_query(int64 shipping_query_id, vectortd() - .get_actor_unsafe() - ->create_handler(std::move(promise)) + td->create_handler(std::move(promise)) ->send(shipping_query_id, error_message, std::move(options)); } -void answer_pre_checkout_query(int64 pre_checkout_query_id, const string &error_message, Promise &&promise) { - G()->td() - .get_actor_unsafe() - ->create_handler(std::move(promise)) - ->send(pre_checkout_query_id, error_message); +void answer_pre_checkout_query(Td *td, int64 pre_checkout_query_id, const string &error_message, + Promise &&promise) { + td->create_handler(std::move(promise))->send(pre_checkout_query_id, error_message); } -void get_payment_form(DialogId dialog_id, ServerMessageId server_message_id, +void get_payment_form(Td *td, DialogId dialog_id, ServerMessageId server_message_id, Promise> &&promise) { - G()->td() - .get_actor_unsafe() - ->create_handler(std::move(promise)) - ->send(dialog_id, server_message_id); + td->create_handler(std::move(promise))->send(dialog_id, server_message_id); } -void validate_order_info(DialogId dialog_id, ServerMessageId server_message_id, +void validate_order_info(Td *td, DialogId dialog_id, ServerMessageId server_message_id, tl_object_ptr order_info, bool allow_save, Promise> &&promise) { if (order_info != nullptr) { @@ -1156,13 +1150,11 @@ void validate_order_info(DialogId dialog_id, ServerMessageId server_message_id, } } - G()->td() - .get_actor_unsafe() - ->create_handler(std::move(promise)) + td->create_handler(std::move(promise)) ->send(dialog_id, server_message_id, convert_order_info(std::move(order_info)), allow_save); } -void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, +void send_payment_form(Td *td, DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, const string &order_info_id, const string &shipping_option_id, const tl_object_ptr &credentials, int64 tip_amount, Promise> &&promise) { @@ -1176,8 +1168,7 @@ void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, in if (!clean_input_string(credentials_id)) { return promise.set_error(Status::Error(400, "Credentials identifier must be encoded in UTF-8")); } - auto temp_password_state = - G()->td().get_actor_unsafe()->password_manager_->get_actor_unsafe()->get_temp_password_state_sync(); + auto temp_password_state = td->password_manager_->get_actor_unsafe()->get_temp_password_state_sync(); if (!temp_password_state.has_temp_password) { return promise.set_error(Status::Error(400, "Temporary password required to use saved credentials")); } @@ -1213,35 +1204,31 @@ void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, in UNREACHABLE(); } - G()->td() - .get_actor_unsafe() - ->create_handler(std::move(promise)) + td->create_handler(std::move(promise)) ->send(dialog_id, server_message_id, payment_form_id, order_info_id, shipping_option_id, std::move(input_credentials), tip_amount); } -void get_payment_receipt(DialogId dialog_id, ServerMessageId server_message_id, +void get_payment_receipt(Td *td, DialogId dialog_id, ServerMessageId server_message_id, Promise> &&promise) { - G()->td() - .get_actor_unsafe() - ->create_handler(std::move(promise)) - ->send(dialog_id, server_message_id); + td->create_handler(std::move(promise))->send(dialog_id, server_message_id); } -void get_saved_order_info(Promise> &&promise) { - G()->td().get_actor_unsafe()->create_handler(std::move(promise))->send(); +void get_saved_order_info(Td *td, Promise> &&promise) { + td->create_handler(std::move(promise))->send(); } -void delete_saved_order_info(Promise &&promise) { - G()->td().get_actor_unsafe()->create_handler(std::move(promise))->send(false, true); +void delete_saved_order_info(Td *td, Promise &&promise) { + td->create_handler(std::move(promise))->send(false, true); } -void delete_saved_credentials(Promise &&promise) { - G()->td().get_actor_unsafe()->create_handler(std::move(promise))->send(true, false); +void delete_saved_credentials(Td *td, Promise &&promise) { + td->create_handler(std::move(promise))->send(true, false); } -void get_bank_card_info(const string &bank_card_number, Promise> &&promise) { - G()->td().get_actor_unsafe()->create_handler(std::move(promise))->send(bank_card_number); +void get_bank_card_info(Td *td, const string &bank_card_number, + Promise> &&promise) { + td->create_handler(std::move(promise))->send(bank_card_number); } } // namespace td diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index 21230d383..5fcb86d84 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -172,32 +172,35 @@ bool operator!=(const ShippingOption &lhs, const ShippingOption &rhs); StringBuilder &operator<<(StringBuilder &string_builder, const ShippingOption &shipping_option); -void answer_shipping_query(int64 shipping_query_id, vector> &&shipping_options, +void answer_shipping_query(Td *td, int64 shipping_query_id, + vector> &&shipping_options, const string &error_message, Promise &&promise); -void answer_pre_checkout_query(int64 pre_checkout_query_id, const string &error_message, Promise &&promise); +void answer_pre_checkout_query(Td *td, int64 pre_checkout_query_id, const string &error_message, + Promise &&promise); -void get_payment_form(DialogId dialog_id, ServerMessageId server_message_id, +void get_payment_form(Td *td, DialogId dialog_id, ServerMessageId server_message_id, Promise> &&promise); -void validate_order_info(DialogId dialog_id, ServerMessageId server_message_id, +void validate_order_info(Td *td, DialogId dialog_id, ServerMessageId server_message_id, tl_object_ptr order_info, bool allow_save, Promise> &&promise); -void send_payment_form(DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, +void send_payment_form(Td *td, DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, const string &order_info_id, const string &shipping_option_id, const tl_object_ptr &credentials, int64 tip_amount, Promise> &&promise); -void get_payment_receipt(DialogId dialog_id, ServerMessageId server_message_id, +void get_payment_receipt(Td *td, DialogId dialog_id, ServerMessageId server_message_id, Promise> &&promise); -void get_saved_order_info(Promise> &&promise); +void get_saved_order_info(Td *td, Promise> &&promise); -void delete_saved_order_info(Promise &&promise); +void delete_saved_order_info(Td *td, Promise &&promise); -void delete_saved_credentials(Promise &&promise); +void delete_saved_credentials(Td *td, Promise &&promise); -void get_bank_card_info(const string &bank_card_number, Promise> &&promise); +void get_bank_card_info(Td *td, const string &bank_card_number, + Promise> &&promise); } // namespace td diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 1c3b7df4e..904e03456 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -7693,7 +7693,7 @@ void Td::on_request(uint64 id, td_api::answerShippingQuery &request) { CHECK_IS_BOT(); CLEAN_INPUT_STRING(request.error_message_); CREATE_OK_REQUEST_PROMISE(); - answer_shipping_query(request.shipping_query_id_, std::move(request.shipping_options_), request.error_message_, + answer_shipping_query(this, request.shipping_query_id_, std::move(request.shipping_options_), request.error_message_, std::move(promise)); } @@ -7701,14 +7701,14 @@ void Td::on_request(uint64 id, td_api::answerPreCheckoutQuery &request) { CHECK_IS_BOT(); CLEAN_INPUT_STRING(request.error_message_); CREATE_OK_REQUEST_PROMISE(); - answer_pre_checkout_query(request.pre_checkout_query_id_, request.error_message_, std::move(promise)); + answer_pre_checkout_query(this, request.pre_checkout_query_id_, request.error_message_, std::move(promise)); } void Td::on_request(uint64 id, td_api::getBankCardInfo &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.bank_card_number_); CREATE_REQUEST_PROMISE(); - get_bank_card_info(request.bank_card_number_, std::move(promise)); + get_bank_card_info(this, request.bank_card_number_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::getPaymentForm &request) { @@ -7747,19 +7747,19 @@ void Td::on_request(uint64 id, const td_api::getPaymentReceipt &request) { void Td::on_request(uint64 id, const td_api::getSavedOrderInfo &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - get_saved_order_info(std::move(promise)); + get_saved_order_info(this, std::move(promise)); } void Td::on_request(uint64 id, const td_api::deleteSavedOrderInfo &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - delete_saved_order_info(std::move(promise)); + delete_saved_order_info(this, std::move(promise)); } void Td::on_request(uint64 id, const td_api::deleteSavedCredentials &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - delete_saved_credentials(std::move(promise)); + delete_saved_credentials(this, std::move(promise)); } void Td::on_request(uint64 id, td_api::getPassportElement &request) { From 97005290858b3e1ed601ba27f15a5c97d634ebbf Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 04:15:02 +0300 Subject: [PATCH 159/281] Remove payments proxy methods from MessagesManager. --- td/telegram/MessagesManager.cpp | 52 +++++---------------------------- td/telegram/MessagesManager.h | 13 ++------- td/telegram/Payments.cpp | 38 ++++++++++++++---------- td/telegram/Payments.h | 19 +++++------- td/telegram/Td.cpp | 18 +++++------- 5 files changed, 47 insertions(+), 93 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 9fef40c81..8dc2bde36 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -42,7 +42,6 @@ #include "td/telegram/NotificationManager.h" #include "td/telegram/NotificationSettings.hpp" #include "td/telegram/NotificationType.h" -#include "td/telegram/Payments.h" #include "td/telegram/ReplyMarkup.h" #include "td/telegram/ReplyMarkup.hpp" #include "td/telegram/SecretChatActor.h" @@ -37359,59 +37358,22 @@ Result MessagesManager::get_invoice_message_id(FullMessageId fu return m->message_id.get_server_message_id(); } -void MessagesManager::get_payment_form(FullMessageId full_message_id, - Promise> &&promise) { - auto r_message_id = get_invoice_message_id(full_message_id); - if (r_message_id.is_error()) { - return promise.set_error(r_message_id.move_as_error()); - } - - ::td::get_payment_form(td_, full_message_id.get_dialog_id(), r_message_id.ok(), std::move(promise)); -} - -void MessagesManager::validate_order_info(FullMessageId full_message_id, tl_object_ptr order_info, - bool allow_save, - Promise> &&promise) { - auto r_message_id = get_invoice_message_id(full_message_id); - if (r_message_id.is_error()) { - return promise.set_error(r_message_id.move_as_error()); - } - - ::td::validate_order_info(td_, full_message_id.get_dialog_id(), r_message_id.ok(), std::move(order_info), allow_save, - std::move(promise)); -} - -void MessagesManager::send_payment_form(FullMessageId full_message_id, int64 payment_form_id, - const string &order_info_id, const string &shipping_option_id, - const tl_object_ptr &credentials, int64 tip_amount, - Promise> &&promise) { - auto r_message_id = get_invoice_message_id(full_message_id); - if (r_message_id.is_error()) { - return promise.set_error(r_message_id.move_as_error()); - } - - ::td::send_payment_form(td_, full_message_id.get_dialog_id(), r_message_id.ok(), payment_form_id, order_info_id, - shipping_option_id, credentials, tip_amount, std::move(promise)); -} - -void MessagesManager::get_payment_receipt(FullMessageId full_message_id, - Promise> &&promise) { - auto m = get_message_force(full_message_id, "get_payment_receipt"); +Result MessagesManager::get_payment_successful_message_id(FullMessageId full_message_id) { + auto m = get_message_force(full_message_id, "get_payment_successful_message_id"); if (m == nullptr) { - return promise.set_error(Status::Error(5, "Message not found")); + return Status::Error(5, "Message not found"); } if (m->content->get_type() != MessageContentType::PaymentSuccessful) { - return promise.set_error(Status::Error(5, "Message has wrong type")); + return Status::Error(5, "Message has wrong type"); } if (m->message_id.is_scheduled()) { - return promise.set_error(Status::Error(5, "Can't get payment receipt from scheduled messages")); + return Status::Error(5, "Wrong sheduled message identifier"); } if (!m->message_id.is_server()) { - return promise.set_error(Status::Error(5, "Wrong message identifier")); + return Status::Error(5, "Wrong message identifier"); } - ::td::get_payment_receipt(td_, full_message_id.get_dialog_id(), m->message_id.get_server_message_id(), - std::move(promise)); + return m->message_id.get_server_message_id(); } void MessagesManager::remove_sponsored_dialog() { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 97d7035b3..8cfb6a616 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -911,16 +911,9 @@ class MessagesManager : public Actor { void stop_poll(FullMessageId full_message_id, td_api::object_ptr &&reply_markup, Promise &&promise); - void get_payment_form(FullMessageId full_message_id, Promise> &&promise); + Result get_invoice_message_id(FullMessageId full_message_id); - void validate_order_info(FullMessageId full_message_id, tl_object_ptr order_info, bool allow_save, - Promise> &&promise); - - void send_payment_form(FullMessageId full_message_id, int64 payment_form_id, const string &order_info_id, - const string &shipping_option_id, const tl_object_ptr &credentials, - int64 tip_amount, Promise> &&promise); - - void get_payment_receipt(FullMessageId full_message_id, Promise> &&promise); + Result get_payment_successful_message_id(FullMessageId full_message_id); void get_current_state(vector> &updates) const; @@ -2970,8 +2963,6 @@ class MessagesManager : public Actor { Result get_login_button_url(DialogId dialog_id, MessageId message_id, int32 button_id); - Result get_invoice_message_id(FullMessageId full_message_id); - bool is_broadcast_channel(DialogId dialog_id) const; bool is_deleted_secret_chat(const Dialog *d) const; diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 83924a84a..6ea086aef 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -13,6 +13,7 @@ #include "td/telegram/MessagesManager.h" #include "td/telegram/misc.h" #include "td/telegram/PasswordManager.h" +#include "td/telegram/ServerMessageId.h" #include "td/telegram/Td.h" #include "td/telegram/UpdatesManager.h" @@ -1110,14 +1111,15 @@ void answer_pre_checkout_query(Td *td, int64 pre_checkout_query_id, const string td->create_handler(std::move(promise))->send(pre_checkout_query_id, error_message); } -void get_payment_form(Td *td, DialogId dialog_id, ServerMessageId server_message_id, - Promise> &&promise) { - td->create_handler(std::move(promise))->send(dialog_id, server_message_id); +void get_payment_form(Td *td, FullMessageId full_message_id, Promise> &&promise) { + TRY_RESULT_PROMISE(promise, server_message_id, td->messages_manager_->get_invoice_message_id(full_message_id)); + td->create_handler(std::move(promise))->send(full_message_id.get_dialog_id(), server_message_id); } -void validate_order_info(Td *td, DialogId dialog_id, ServerMessageId server_message_id, - tl_object_ptr order_info, bool allow_save, - Promise> &&promise) { +void validate_order_info(Td *td, FullMessageId full_message_id, tl_object_ptr order_info, + bool allow_save, Promise> &&promise) { + TRY_RESULT_PROMISE(promise, server_message_id, td->messages_manager_->get_invoice_message_id(full_message_id)); + if (order_info != nullptr) { if (!clean_input_string(order_info->name_)) { return promise.set_error(Status::Error(400, "Name must be encoded in UTF-8")); @@ -1151,14 +1153,17 @@ void validate_order_info(Td *td, DialogId dialog_id, ServerMessageId server_mess } td->create_handler(std::move(promise)) - ->send(dialog_id, server_message_id, convert_order_info(std::move(order_info)), allow_save); + ->send(full_message_id.get_dialog_id(), server_message_id, convert_order_info(std::move(order_info)), allow_save); } -void send_payment_form(Td *td, DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, - const string &order_info_id, const string &shipping_option_id, - const tl_object_ptr &credentials, int64 tip_amount, - Promise> &&promise) { - CHECK(credentials != nullptr); +void send_payment_form(Td *td, FullMessageId full_message_id, int64 payment_form_id, const string &order_info_id, + const string &shipping_option_id, const tl_object_ptr &credentials, + int64 tip_amount, Promise> &&promise) { + TRY_RESULT_PROMISE(promise, server_message_id, td->messages_manager_->get_invoice_message_id(full_message_id)); + + if (credentials == nullptr) { + return promise.set_error(Status::Error(400, "Input payment credentials must be non-empty")); + } tl_object_ptr input_credentials; switch (credentials->get_id()) { @@ -1205,13 +1210,16 @@ void send_payment_form(Td *td, DialogId dialog_id, ServerMessageId server_messag } td->create_handler(std::move(promise)) - ->send(dialog_id, server_message_id, payment_form_id, order_info_id, shipping_option_id, + ->send(full_message_id.get_dialog_id(), server_message_id, payment_form_id, order_info_id, shipping_option_id, std::move(input_credentials), tip_amount); } -void get_payment_receipt(Td *td, DialogId dialog_id, ServerMessageId server_message_id, +void get_payment_receipt(Td *td, FullMessageId full_message_id, Promise> &&promise) { - td->create_handler(std::move(promise))->send(dialog_id, server_message_id); + TRY_RESULT_PROMISE(promise, server_message_id, + td->messages_manager_->get_payment_successful_message_id(full_message_id)); + td->create_handler(std::move(promise)) + ->send(full_message_id.get_dialog_id(), server_message_id); } void get_saved_order_info(Td *td, Promise> &&promise) { diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index 5fcb86d84..1947c0fc3 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -9,9 +9,9 @@ #include "td/actor/PromiseFuture.h" #include "td/telegram/DialogId.h" +#include "td/telegram/FullMessageId.h" #include "td/telegram/MessageId.h" #include "td/telegram/Photo.h" -#include "td/telegram/ServerMessageId.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" @@ -179,19 +179,16 @@ void answer_shipping_query(Td *td, int64 shipping_query_id, void answer_pre_checkout_query(Td *td, int64 pre_checkout_query_id, const string &error_message, Promise &&promise); -void get_payment_form(Td *td, DialogId dialog_id, ServerMessageId server_message_id, - Promise> &&promise); +void get_payment_form(Td *td, FullMessageId full_message_id, Promise> &&promise); -void validate_order_info(Td *td, DialogId dialog_id, ServerMessageId server_message_id, - tl_object_ptr order_info, bool allow_save, - Promise> &&promise); +void validate_order_info(Td *td, FullMessageId full_message_id, tl_object_ptr order_info, + bool allow_save, Promise> &&promise); -void send_payment_form(Td *td, DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, - const string &order_info_id, const string &shipping_option_id, - const tl_object_ptr &credentials, int64 tip_amount, - Promise> &&promise); +void send_payment_form(Td *td, FullMessageId full_message_id, int64 payment_form_id, const string &order_info_id, + const string &shipping_option_id, const tl_object_ptr &credentials, + int64 tip_amount, Promise> &&promise); -void get_payment_receipt(Td *td, DialogId dialog_id, ServerMessageId server_message_id, +void get_payment_receipt(Td *td, FullMessageId full_message_id, Promise> &&promise); void get_saved_order_info(Td *td, Promise> &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 904e03456..ad703d2f3 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -7714,34 +7714,30 @@ void Td::on_request(uint64 id, td_api::getBankCardInfo &request) { void Td::on_request(uint64 id, const td_api::getPaymentForm &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - messages_manager_->get_payment_form({DialogId(request.chat_id_), MessageId(request.message_id_)}, std::move(promise)); + get_payment_form(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, std::move(promise)); } void Td::on_request(uint64 id, td_api::validateOrderInfo &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - messages_manager_->validate_order_info({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(request.order_info_), request.allow_save_, std::move(promise)); + validate_order_info(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, + std::move(request.order_info_), request.allow_save_, std::move(promise)); } void Td::on_request(uint64 id, td_api::sendPaymentForm &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.order_info_id_); CLEAN_INPUT_STRING(request.shipping_option_id_); - if (request.credentials_ == nullptr) { - return send_error_raw(id, 400, "Input payments credentials must be non-empty"); - } CREATE_REQUEST_PROMISE(); - messages_manager_->send_payment_form({DialogId(request.chat_id_), MessageId(request.message_id_)}, - request.payment_form_id_, request.order_info_id_, request.shipping_option_id_, - request.credentials_, request.tip_amount_, std::move(promise)); + send_payment_form(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, request.payment_form_id_, + request.order_info_id_, request.shipping_option_id_, request.credentials_, request.tip_amount_, + std::move(promise)); } void Td::on_request(uint64 id, const td_api::getPaymentReceipt &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - messages_manager_->get_payment_receipt({DialogId(request.chat_id_), MessageId(request.message_id_)}, - std::move(promise)); + get_payment_receipt(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, std::move(promise)); } void Td::on_request(uint64 id, const td_api::getSavedOrderInfo &request) { From 3f1e91e7f485c439e583e05f60683fe0b48ddce8 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 15:36:25 +0300 Subject: [PATCH 160/281] Support invoice receipts in another chats. --- td/generate/scheme/td_api.tl | 10 ++-- td/telegram/MessageContent.cpp | 91 +++++++++++++++++++++++---------- td/telegram/MessageContent.h | 8 +-- td/telegram/MessagesManager.cpp | 58 ++++++++++++++------- 4 files changed, 114 insertions(+), 53 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index c8469531b..d68e1866b 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -1737,13 +1737,13 @@ messageCustomServiceAction text:string = MessageContent; //@description A new high score was achieved in a game @game_message_id Identifier of the message with the game, can be an identifier of a deleted message @game_id Identifier of the game; may be different from the games presented in the message with the game @score New score messageGameScore game_message_id:int53 game_id:int64 score:int32 = MessageContent; -//@description A payment has been completed @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for the price of the product @total_amount Total price for the product, in the smallest units of the currency -messagePaymentSuccessful invoice_message_id:int53 currency:string total_amount:int53 = MessageContent; +//@description A payment has been completed @invoice_chat_id Identifier of the chat, containing the corresponding invoice message; 0 if unknown @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for the price of the product @total_amount Total price for the product, in the smallest units of the currency +messagePaymentSuccessful invoice_chat_id:int53 invoice_message_id:int53 currency:string total_amount:int53 = MessageContent; -//@description A payment has been completed; for bots only @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for price of the product +//@description A payment has been completed; for bots only @invoice_chat_id Identifier of the chat, containing the corresponding invoice message; 0 if unknown @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for price of the product //@total_amount Total price for the product, in the smallest units of the currency @invoice_payload Invoice payload @shipping_option_id Identifier of the shipping option chosen by the user; may be empty if not applicable @order_info Information about the order; may be null //@telegram_payment_charge_id Telegram payment identifier @provider_payment_charge_id Provider payment identifier -messagePaymentSuccessfulBot invoice_message_id:int53 currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo telegram_payment_charge_id:string provider_payment_charge_id:string = MessageContent; +messagePaymentSuccessfulBot invoice_chat_id:int53 invoice_message_id:int53 currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo telegram_payment_charge_id:string provider_payment_charge_id:string = MessageContent; //@description A contact has registered with Telegram messageContactRegistered = MessageContent; @@ -3809,7 +3809,7 @@ getMessage chat_id:int53 message_id:int53 = Message; //@description Returns information about a message, if it is available locally without sending network request. This is an offline request @chat_id Identifier of the chat the message belongs to @message_id Identifier of the message to get getMessageLocally chat_id:int53 message_id:int53 = Message; -//@description Returns information about a message that is replied by a given message. Also returns the pinned message, the game message, and the invoice message for messages of the types messagePinMessage, messageGameScore, and messagePaymentSuccessful respectively +//@description Returns information about a message that is replied by a given message. Also returns the pinned message, the game message, and the invoice message for messages of the types messagePinMessage, messageGameScore, and messagePaymentSuccessful/messagePaymentSuccessfulBot respectively //@chat_id Identifier of the chat the message belongs to @message_id Identifier of the message reply to which to get getRepliedMessage chat_id:int53 message_id:int53 = Message; diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 7b42a85d0..eb8b748b7 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -482,6 +482,7 @@ class MessageInvoice : public MessageContent { class MessagePaymentSuccessful : public MessageContent { public: + DialogId invoice_dialog_id; MessageId invoice_message_id; string currency; int64 total_amount = 0; @@ -494,8 +495,12 @@ class MessagePaymentSuccessful : public MessageContent { string provider_payment_charge_id; MessagePaymentSuccessful() = default; - MessagePaymentSuccessful(MessageId invoice_message_id, string &¤cy, int64 total_amount) - : invoice_message_id(invoice_message_id), currency(std::move(currency)), total_amount(total_amount) { + MessagePaymentSuccessful(DialogId invoice_dialog_id, MessageId invoice_message_id, string &¤cy, + int64 total_amount) + : invoice_dialog_id(invoice_dialog_id) + , invoice_message_id(invoice_message_id) + , currency(std::move(currency)) + , total_amount(total_amount) { } MessageContentType get_type() const override { @@ -905,6 +910,7 @@ static void store(const MessageContent *content, StorerT &storer) { bool has_provider_payment_charge_id = !m->provider_payment_charge_id.empty(); bool has_invoice_message_id = m->invoice_message_id.is_valid(); bool is_correctly_stored = true; + bool has_invoice_dialog_id = m->invoice_dialog_id.is_valid(); BEGIN_STORE_FLAGS(); STORE_FLAG(has_payload); STORE_FLAG(has_shipping_option_id); @@ -913,6 +919,7 @@ static void store(const MessageContent *content, StorerT &storer) { STORE_FLAG(has_provider_payment_charge_id); STORE_FLAG(has_invoice_message_id); STORE_FLAG(is_correctly_stored); + STORE_FLAG(has_invoice_dialog_id); END_STORE_FLAGS(); store(m->currency, storer); store(m->total_amount, storer); @@ -934,6 +941,9 @@ static void store(const MessageContent *content, StorerT &storer) { if (has_invoice_message_id) { store(m->invoice_message_id, storer); } + if (has_invoice_dialog_id) { + store(m->invoice_dialog_id, storer); + } break; } case MessageContentType::ContactRegistered: @@ -1267,6 +1277,7 @@ static void parse(unique_ptr &content, ParserT &parser) { bool has_provider_payment_charge_id; bool has_invoice_message_id; bool is_correctly_stored; + bool has_invoice_dialog_id; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_payload); PARSE_FLAG(has_shipping_option_id); @@ -1275,6 +1286,7 @@ static void parse(unique_ptr &content, ParserT &parser) { PARSE_FLAG(has_provider_payment_charge_id); PARSE_FLAG(has_invoice_message_id); PARSE_FLAG(is_correctly_stored); + PARSE_FLAG(has_invoice_dialog_id); END_PARSE_FLAGS(); parse(m->currency, parser); parse(m->total_amount, parser); @@ -1305,6 +1317,9 @@ static void parse(unique_ptr &content, ParserT &parser) { if (has_invoice_message_id) { parse(m->invoice_message_id, parser); } + if (has_invoice_dialog_id) { + parse(m->invoice_dialog_id, parser); + } if (is_correctly_stored) { content = std::move(m); } else { @@ -2548,16 +2563,19 @@ MessageId get_message_content_pinned_message_id(const MessageContent *content) { } } -MessageId get_message_content_replied_message_id(const MessageContent *content) { +FullMessageId get_message_content_replied_message_id(DialogId dialog_id, const MessageContent *content) { switch (content->get_type()) { case MessageContentType::PinMessage: - return static_cast(content)->message_id; + return {dialog_id, static_cast(content)->message_id}; case MessageContentType::GameScore: - return static_cast(content)->game_message_id; - case MessageContentType::PaymentSuccessful: - return static_cast(content)->invoice_message_id; + return {dialog_id, static_cast(content)->game_message_id}; + case MessageContentType::PaymentSuccessful: { + auto *m = static_cast(content); + auto reply_in_dialog_id = m->invoice_dialog_id.is_valid() ? m->invoice_dialog_id : dialog_id; + return {reply_in_dialog_id, m->invoice_message_id}; + } default: - return MessageId(); + return FullMessageId(); } } @@ -2705,8 +2723,9 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo if (old_->text.text != new_->text.text) { if (need_message_changed_warning && need_message_text_changed_warning(old_, new_)) { LOG(ERROR) << "Message text has changed from " - << to_string(get_message_content_object(old_content, td, -1, false)) << ". New content is " - << to_string(get_message_content_object(new_content, td, -1, false)); + << to_string(get_message_content_object(old_content, td, dialog_id, -1, false)) + << ". New content is " + << to_string(get_message_content_object(new_content, td, dialog_id, -1, false)); } need_update = true; } @@ -2716,8 +2735,9 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo old_->text.entities.size() <= MAX_CUSTOM_ENTITIES_COUNT && need_message_entities_changed_warning(old_->text.entities, new_->text.entities)) { LOG(WARNING) << "Entities has changed from " - << to_string(get_message_content_object(old_content, td, -1, false)) << ". New content is " - << to_string(get_message_content_object(new_content, td, -1, false)); + << to_string(get_message_content_object(old_content, td, dialog_id, -1, false)) + << ". New content is " + << to_string(get_message_content_object(new_content, td, dialog_id, -1, false)); } need_update = true; } @@ -3065,9 +3085,9 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo case MessageContentType::PaymentSuccessful: { auto old_ = static_cast(old_content); auto new_ = static_cast(new_content); - if (old_->invoice_message_id != new_->invoice_message_id || old_->currency != new_->currency || - old_->total_amount != new_->total_amount || old_->invoice_payload != new_->invoice_payload || - old_->shipping_option_id != new_->shipping_option_id || + if (old_->invoice_dialog_id != new_->invoice_dialog_id || old_->invoice_message_id != new_->invoice_message_id || + old_->currency != new_->currency || old_->total_amount != new_->total_amount || + old_->invoice_payload != new_->invoice_payload || old_->shipping_option_id != new_->shipping_option_id || old_->telegram_payment_charge_id != new_->telegram_payment_charge_id || old_->provider_payment_charge_id != new_->provider_payment_charge_id || ((old_->order_info != nullptr || new_->order_info != nullptr) && @@ -4187,7 +4207,8 @@ unique_ptr dup_message_content(Td *td, DialogId dialog_id, const } unique_ptr get_action_message_content(Td *td, tl_object_ptr &&action, - DialogId owner_dialog_id, MessageId reply_to_message_id) { + DialogId owner_dialog_id, DialogId reply_in_dialog_id, + MessageId reply_to_message_id) { CHECK(action != nullptr); switch (action->get_id()) { @@ -4283,6 +4304,12 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr(std::move(channel_migrate_from->title_), chat_id); } case telegram_api::messageActionPinMessage::ID: { + if (reply_in_dialog_id.is_valid() && reply_in_dialog_id != owner_dialog_id) { + LOG(ERROR) << "Receive pinned message with " << reply_to_message_id << " in " << owner_dialog_id + << " in another " << reply_in_dialog_id; + reply_to_message_id = MessageId(); + reply_in_dialog_id = DialogId(); + } if (!reply_to_message_id.is_valid()) { // possible in basic groups LOG(INFO) << "Receive pinned message with " << reply_to_message_id << " in " << owner_dialog_id; @@ -4291,6 +4318,12 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr(reply_to_message_id); } case telegram_api::messageActionGameScore::ID: { + if (reply_in_dialog_id.is_valid() && reply_in_dialog_id != owner_dialog_id) { + LOG(ERROR) << "Receive game score with " << reply_to_message_id << " in " << owner_dialog_id << " in another " + << reply_in_dialog_id; + reply_to_message_id = MessageId(); + reply_in_dialog_id = DialogId(); + } if (!reply_to_message_id.is_valid()) { // possible in basic groups LOG(INFO) << "Receive game score with " << reply_to_message_id << " in " << owner_dialog_id; @@ -4318,8 +4351,8 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr(action); - return td::make_unique(reply_to_message_id, std::move(payment_sent->currency_), - payment_sent->total_amount_); + return td::make_unique(reply_in_dialog_id, reply_to_message_id, + std::move(payment_sent->currency_), payment_sent->total_amount_); } case telegram_api::messageActionPaymentSentMe::ID: { LOG_IF(ERROR, !td->auth_manager_->is_bot()) << "Receive MessageActionPaymentSentMe in " << owner_dialog_id; @@ -4328,8 +4361,8 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr(action); - auto result = td::make_unique(reply_to_message_id, std::move(payment_sent->currency_), - payment_sent->total_amount_); + auto result = td::make_unique( + reply_in_dialog_id, reply_to_message_id, std::move(payment_sent->currency_), payment_sent->total_amount_); result->invoice_payload = payment_sent->payload_.as_slice().str(); result->shipping_option_id = std::move(payment_sent->shipping_option_id_); result->order_info = get_order_info(std::move(payment_sent->info_)); @@ -4425,7 +4458,8 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr get_message_content_object(const MessageContent *content, Td *td, - int32 message_date, bool is_content_secret) { + DialogId dialog_id, int32 message_date, + bool is_content_secret) { CHECK(content != nullptr); switch (content->get_type()) { case MessageContentType::Animation: { @@ -4570,13 +4604,15 @@ tl_object_ptr get_message_content_object(const MessageCo } case MessageContentType::PaymentSuccessful: { const MessagePaymentSuccessful *m = static_cast(content); + auto invoice_dialog_id = m->invoice_dialog_id.is_valid() ? m->invoice_dialog_id : dialog_id; if (td->auth_manager_->is_bot()) { return make_tl_object( - m->invoice_message_id.get(), m->currency, m->total_amount, m->invoice_payload, m->shipping_option_id, - get_order_info_object(m->order_info), m->telegram_payment_charge_id, m->provider_payment_charge_id); + invoice_dialog_id.get(), m->invoice_message_id.get(), m->currency, m->total_amount, m->invoice_payload, + m->shipping_option_id, get_order_info_object(m->order_info), m->telegram_payment_charge_id, + m->provider_payment_charge_id); } else { - return make_tl_object(m->invoice_message_id.get(), m->currency, - m->total_amount); + return make_tl_object(invoice_dialog_id.get(), m->invoice_message_id.get(), + m->currency, m->total_amount); } } case MessageContentType::ContactRegistered: @@ -5124,8 +5160,11 @@ void add_message_content_dependencies(Dependencies &dependencies, const MessageC break; case MessageContentType::Call: break; - case MessageContentType::PaymentSuccessful: + case MessageContentType::PaymentSuccessful: { + auto content = static_cast(message_content); + add_dialog_and_dependencies(dependencies, content->invoice_dialog_id); break; + } case MessageContentType::ContactRegistered: break; case MessageContentType::ExpiredPhoto: diff --git a/td/telegram/MessageContent.h b/td/telegram/MessageContent.h index b9dae31b8..d0186e277 100644 --- a/td/telegram/MessageContent.h +++ b/td/telegram/MessageContent.h @@ -130,7 +130,7 @@ int32 get_message_content_index_mask(const MessageContent *content, const Td *td MessageId get_message_content_pinned_message_id(const MessageContent *content); -MessageId get_message_content_replied_message_id(const MessageContent *content); +FullMessageId get_message_content_replied_message_id(DialogId dialog_id, const MessageContent *content); vector get_message_content_added_user_ids(const MessageContent *content); @@ -187,10 +187,12 @@ unique_ptr dup_message_content(Td *td, DialogId dialog_id, const MessageContentDupType type, MessageCopyOptions &©_options); unique_ptr get_action_message_content(Td *td, tl_object_ptr &&action, - DialogId owner_dialog_id, MessageId reply_to_message_id); + DialogId owner_dialog_id, DialogId reply_in_dialog_id, + MessageId reply_to_message_id); tl_object_ptr get_message_content_object(const MessageContent *content, Td *td, - int32 message_date, bool is_content_secret); + DialogId dialog_id, int32 message_date, + bool is_content_secret); const FormattedText *get_message_content_text(const MessageContent *content); diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 8dc2bde36..245ce5b8a 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -6653,9 +6653,10 @@ void MessagesManager::on_update_service_notification(tl_object_ptrget_type()); if ((update->flags_ & telegram_api::updateServiceNotification::POPUP_MASK) != 0) { - send_closure(G()->td(), &Td::send_update, - td_api::make_object( - update->type_, get_message_content_object(content.get(), td_, date, is_content_secret))); + send_closure( + G()->td(), &Td::send_update, + td_api::make_object( + update->type_, get_message_content_object(content.get(), td_, owner_dialog_id, date, is_content_secret))); } if (has_date && is_user) { Dialog *d = get_service_notifications_dialog(); @@ -13331,10 +13332,23 @@ MessagesManager::MessageInfo MessagesManager::parse_telegram_api_message( message_info.ttl_period = message->ttl_period_; } message_info.flags = message->flags_; - auto reply_to_message_id = - MessageId(ServerMessageId(message->reply_to_ == nullptr ? 0 : message->reply_to_->reply_to_msg_id_)); - message_info.content = - get_action_message_content(td_, std::move(message->action_), message_info.dialog_id, reply_to_message_id); + + DialogId reply_in_dialog_id; + MessageId reply_to_message_id; + if (message_info.reply_header != nullptr) { + reply_to_message_id = MessageId(ServerMessageId(message_info.reply_header->reply_to_msg_id_)); + auto reply_to_peer_id = std::move(message_info.reply_header->reply_to_peer_id_); + if (reply_to_peer_id != nullptr) { + reply_in_dialog_id = DialogId(reply_to_peer_id); + if (!reply_in_dialog_id.is_valid()) { + LOG(ERROR) << "Receive reply in invalid " << to_string(reply_to_peer_id); + reply_to_message_id = MessageId(); + reply_in_dialog_id = DialogId(); + } + } + } + message_info.content = get_action_message_content(td_, std::move(message->action_), message_info.dialog_id, + reply_in_dialog_id, reply_to_message_id); break; } default: @@ -13437,7 +13451,7 @@ std::pair> MessagesManager::creat */ } - MessageId reply_to_message_id = message_info.reply_to_message_id; + MessageId reply_to_message_id = message_info.reply_to_message_id; // for secret messages DialogId reply_in_dialog_id; MessageId top_thread_message_id; if (message_info.reply_header != nullptr) { @@ -13446,12 +13460,16 @@ std::pair> MessagesManager::creat if (reply_to_peer_id != nullptr) { reply_in_dialog_id = DialogId(reply_to_peer_id); if (!reply_in_dialog_id.is_valid()) { - LOG(ERROR) << " Receive reply in invalid " << to_string(reply_to_peer_id); + LOG(ERROR) << "Receive reply in invalid " << to_string(reply_to_peer_id); reply_to_message_id = MessageId(); reply_in_dialog_id = DialogId(); } + if (reply_in_dialog_id == dialog_id) { + reply_in_dialog_id = DialogId(); // just in case + } } - if (reply_to_message_id.is_valid() && !td_->auth_manager_->is_bot() && !message_id.is_scheduled()) { + if (reply_to_message_id.is_valid() && !td_->auth_manager_->is_bot() && !message_id.is_scheduled() && + !reply_in_dialog_id.is_valid()) { if ((message_info.reply_header->flags_ & telegram_api::messageReplyHeader::REPLY_TO_TOP_ID_MASK) != 0) { top_thread_message_id = MessageId(ServerMessageId(message_info.reply_header->reply_to_top_id_)); } else if (!is_broadcast_channel(dialog_id)) { @@ -13581,8 +13599,8 @@ std::pair> MessagesManager::creat if (!is_allowed_media_group_content(content_type)) { LOG(ERROR) << "Receive media group identifier " << message_info.media_album_id << " in " << message_id << " from " << dialog_id << " with content " - << oneline(to_string( - get_message_content_object(message->content.get(), td_, message->date, is_content_secret))); + << oneline(to_string(get_message_content_object(message->content.get(), td_, dialog_id, message->date, + is_content_secret))); } else { message->media_album_id = message_info.media_album_id; } @@ -16755,10 +16773,10 @@ MessagesManager::Message *MessagesManager::get_message_force(FullMessageId full_ } FullMessageId MessagesManager::get_replied_message_id(DialogId dialog_id, const Message *m) { - auto message_id = get_message_content_replied_message_id(m->content.get()); - if (message_id.is_valid()) { + auto full_message_id = get_message_content_replied_message_id(dialog_id, m->content.get()); + if (full_message_id.get_message_id().is_valid()) { CHECK(!m->reply_to_message_id.is_valid()); - return {dialog_id, message_id}; + return full_message_id; } if (!m->reply_to_message_id.is_valid()) { return {}; @@ -22870,7 +22888,7 @@ tl_object_ptr MessagesManager::get_message_object(DialogId dial get_message_interaction_info_object(dialog_id, m), reply_in_dialog_id.get(), reply_to_message_id, top_thread_message_id, ttl, ttl_expires_in, via_bot_user_id, m->author_signature, media_album_id, get_restriction_reason_description(m->restriction_reasons), - get_message_content_object(m->content.get(), td_, live_location_date, m->is_content_secret), + get_message_content_object(m->content.get(), td_, dialog_id, live_location_date, m->is_content_secret), get_reply_markup_object(m->reply_markup)); } @@ -24233,7 +24251,8 @@ void MessagesManager::do_send_message_group(int64 media_album_id) { << file_view.has_alive_remote_location() << " " << file_view.has_active_upload_remote_location() << " " << file_view.has_active_download_remote_location() << " " << file_view.is_encrypted() << " " << is_web << " " << file_view.has_url() << " " - << to_string(get_message_content_object(m->content.get(), td_, m->date, m->is_content_secret)); + << to_string( + get_message_content_object(m->content.get(), td_, dialog_id, m->date, m->is_content_secret)); } auto entities = get_input_message_entities(td_->contacts_manager_.get(), caption, "do_send_message_group"); int32 input_single_media_flags = 0; @@ -28293,7 +28312,7 @@ void MessagesManager::send_update_message_content(DialogId dialog_id, MessageId LOG(INFO) << "Send updateMessageContent for " << message_id << " in " << dialog_id << " from " << source; LOG_CHECK(have_dialog(dialog_id)) << "Send updateMessageContent in unknown " << dialog_id << " from " << source << " with load count " << loaded_dialogs_.count(dialog_id); - auto content_object = get_message_content_object(content, td_, message_date, is_content_secret); + auto content_object = get_message_content_object(content, td_, dialog_id, message_date, is_content_secret); send_closure( G()->td(), &Td::send_update, td_api::make_object(dialog_id.get(), message_id.get(), std::move(content_object))); @@ -30572,7 +30591,8 @@ void MessagesManager::on_send_dialog_action_timeout(DialogId dialog_id) { auto file_id = get_message_content_upload_file_id(m->content.get()); if (!file_id.is_valid()) { LOG(ERROR) << "Have no file in " - << to_string(get_message_content_object(m->content.get(), td_, m->date, m->is_content_secret)); + << to_string( + get_message_content_object(m->content.get(), td_, dialog_id, m->date, m->is_content_secret)); return; } auto file_view = td_->file_manager_->get_file_view(file_id); From b7e77765be57aae9da8e68243551f39791350d36 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 15:44:53 +0300 Subject: [PATCH 161/281] Fix accessing group call's leave_version. --- td/telegram/GroupCallManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 1751a8f32..3dfb6c8e3 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1391,12 +1391,12 @@ void GroupCallManager::on_update_group_call_participants( continue; } if (participant.joined_date == 0) { - if (version > group_call->leave_version) { + if (group_call == nullptr || version > group_call->leave_version) { diff--; } remove_recent_group_call_speaker(input_group_call_id, participant.dialog_id); } else { - if (participant.is_just_joined && version >= group_call->leave_version) { + if (participant.is_just_joined && (group_call == nullptr || version >= group_call->leave_version)) { diff++; } on_participant_speaking_in_group_call(input_group_call_id, participant); From b86a3fe227bf31dd80506a4496adccd7e190e1e6 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 15:50:51 +0300 Subject: [PATCH 162/281] Fix misprint. --- td/telegram/Log.h | 2 +- td/telegram/td_log.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/td/telegram/Log.h b/td/telegram/Log.h index eb37a006a..f204ece7d 100644 --- a/td/telegram/Log.h +++ b/td/telegram/Log.h @@ -21,7 +21,7 @@ namespace td { * Interface for managing the internal logging of TDLib. * By default TDLib writes logs to stderr or an OS specific log and uses a verbosity level of 5. * These functions are deprecated since TDLib 1.4.0 in favor of the td::td_api::setLogVerbosityLevel, - * td::td_api::setLogStream and other synchronous requests for managing the intrenal TDLib logging. + * td::td_api::setLogStream and other synchronous requests for managing the internal TDLib logging. */ class Log { public: diff --git a/td/telegram/td_log.h b/td/telegram/td_log.h index a3cc4b12b..24db9e9c9 100644 --- a/td/telegram/td_log.h +++ b/td/telegram/td_log.h @@ -11,7 +11,7 @@ * C interface for managing the internal logging of TDLib. * By default TDLib writes logs to stderr or an OS specific log and uses a verbosity level of 5. * These functions are deprecated since TDLib 1.4.0 in favor of the setLogVerbosityLevel, setLogStream and - * other synchronous requests for managing the intrenal TDLib logging. + * other synchronous requests for managing the internal TDLib logging. */ #include "td/telegram/tdjson_export.h" From 1bb13c0ab33f82cd3abd6234027cf750251bf9a3 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 16:07:45 +0300 Subject: [PATCH 163/281] Remove unused parameter in add_message_dependencies. --- td/telegram/MessagesManager.cpp | 20 ++++++++++---------- td/telegram/MessagesManager.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index ecaeeb3c4..3c7b65710 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -22248,7 +22248,7 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId last_added_message_id = m->message_id; } if (old_message == nullptr) { - add_message_dependencies(dependencies, dialog_id, m); + add_message_dependencies(dependencies, m); added_new_message = true; } else if (m->message_id != from_message_id) { added_new_message = true; @@ -22587,7 +22587,7 @@ void MessagesManager::on_get_scheduled_messages_from_database(DialogId dialog_id Message *m = add_scheduled_message_to_dialog(d, std::move(message), false, &need_update, "on_get_scheduled_messages_from_database"); if (m != nullptr) { - add_message_dependencies(dependencies, dialog_id, m); + add_message_dependencies(dependencies, m); added_message_ids.push_back(m->message_id); } } @@ -23439,7 +23439,7 @@ bool MessagesManager::is_message_auto_read(DialogId dialog_id, bool is_outgoing) } } -void MessagesManager::add_message_dependencies(Dependencies &dependencies, DialogId dialog_id, const Message *m) { +void MessagesManager::add_message_dependencies(Dependencies &dependencies, const Message *m) { dependencies.user_ids.insert(m->sender_user_id); add_dialog_and_dependencies(dependencies, m->sender_dialog_id); add_dialog_and_dependencies(dependencies, m->reply_in_dialog_id); @@ -31853,7 +31853,7 @@ MessagesManager::Message *MessagesManager::on_get_message_from_database(DialogId } Dependencies dependencies; - add_message_dependencies(dependencies, d->dialog_id, m.get()); + add_message_dependencies(dependencies, m.get()); resolve_dependencies_force(td_, dependencies, "on_get_message_from_database"); m->have_previous = false; @@ -34965,7 +34965,7 @@ unique_ptr MessagesManager::parse_dialog(DialogId dialo add_message_sender_dependencies(dependencies, d->default_join_group_call_as_dialog_id); } if (d->messages != nullptr) { - add_message_dependencies(dependencies, dialog_id, d->messages.get()); + add_message_dependencies(dependencies, d->messages.get()); } if (d->draft_message != nullptr) { add_formatted_text_dependencies(dependencies, &d->draft_message->input_message_text.text); @@ -36229,7 +36229,7 @@ void MessagesManager::on_binlog_events(vector &&events) { Dependencies dependencies; add_dialog_dependencies(dependencies, dialog_id); - add_message_dependencies(dependencies, dialog_id, m.get()); + add_message_dependencies(dependencies, m.get()); resolve_dependencies_force(td_, dependencies, "SendMessageLogEvent"); m->content = @@ -36259,7 +36259,7 @@ void MessagesManager::on_binlog_events(vector &&events) { Dependencies dependencies; add_dialog_dependencies(dependencies, dialog_id); - add_message_dependencies(dependencies, dialog_id, m.get()); + add_message_dependencies(dependencies, m.get()); resolve_dependencies_force(td_, dependencies, "SendBotStartMessageLogEvent"); auto bot_user_id = log_event.bot_user_id; @@ -36296,7 +36296,7 @@ void MessagesManager::on_binlog_events(vector &&events) { Dependencies dependencies; add_dialog_dependencies(dependencies, dialog_id); - add_message_dependencies(dependencies, dialog_id, m.get()); + add_message_dependencies(dependencies, m.get()); resolve_dependencies_force(td_, dependencies, "SendInlineQueryResultMessageLogEvent"); m->content = dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::SendViaBot, @@ -36325,7 +36325,7 @@ void MessagesManager::on_binlog_events(vector &&events) { Dependencies dependencies; add_dialog_dependencies(dependencies, dialog_id); - add_message_dependencies(dependencies, dialog_id, m.get()); + add_message_dependencies(dependencies, m.get()); resolve_dependencies_force(td_, dependencies, "SendScreenshotTakenNotificationMessageLogEvent"); auto result_message = continue_send_message(dialog_id, std::move(m), event.id_); @@ -36351,7 +36351,7 @@ void MessagesManager::on_binlog_events(vector &&events) { add_dialog_dependencies(dependencies, to_dialog_id); add_dialog_dependencies(dependencies, from_dialog_id); for (auto &m : messages) { - add_message_dependencies(dependencies, to_dialog_id, m.get()); + add_message_dependencies(dependencies, m.get()); } resolve_dependencies_force(td_, dependencies, "ForwardMessagesLogEvent"); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 4275d8aed..26c0c6798 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2921,7 +2921,7 @@ class MessagesManager : public Actor { static void dump_debug_message_op(const Dialog *d, int priority = 0); - static void add_message_dependencies(Dependencies &dependencies, DialogId dialog_id, const Message *m); + static void add_message_dependencies(Dependencies &dependencies, const Message *m); void save_send_message_log_event(DialogId dialog_id, const Message *m); From 5508721497888932d1598bc04dffd32196d0677b Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 16:17:25 +0300 Subject: [PATCH 164/281] Use add_message_dependencies to reliably find all dependent dialogs. --- td/telegram/MessagesManager.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 3c7b65710..219f01226 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -34143,8 +34143,11 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab d->debug_last_new_message_id = d->last_new_message_id; if (last_database_message != nullptr) { + Dependencies dependencies; + add_message_dependencies(dependencies, last_database_message.get()); + int32 dependent_dialog_count = 0; - auto depend_on_dialog = [&](DialogId other_dialog_id) { + for (auto &other_dialog_id : dependencies.dialog_ids) { if (other_dialog_id.is_valid() && !have_dialog(other_dialog_id)) { LOG(INFO) << "Postpone adding of last message in " << dialog_id << " because of cyclic dependency with " << other_dialog_id; @@ -34152,13 +34155,6 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab dependent_dialog_count++; } }; - if (last_database_message->forward_info != nullptr) { - depend_on_dialog(last_database_message->forward_info->sender_dialog_id); - depend_on_dialog(last_database_message->forward_info->from_dialog_id); - } - depend_on_dialog(last_database_message->sender_dialog_id); - depend_on_dialog(last_database_message->reply_in_dialog_id); - depend_on_dialog(last_database_message->real_forward_from_dialog_id); if (dependent_dialog_count == 0) { add_dialog_last_database_message(d, std::move(last_database_message)); From ea0280c5898089f58429e3441ebe4f43f9dfbf67 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 31 Mar 2021 17:51:51 +0300 Subject: [PATCH 165/281] Fix convert_address. --- td/telegram/Payments.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 3af931db2..358caa059 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -186,9 +186,9 @@ static tl_object_ptr convert_address(tl_object_ptr(std::move(address->country_code_), std::move(address->state_), - std::move(address->city_), std::move(address->street_line1_), - std::move(address->street_line2_), std::move(address->postal_code_)); + return make_tl_object(std::move(address->street_line1_), std::move(address->street_line2_), + std::move(address->city_), std::move(address->state_), + std::move(address->country_code_), std::move(address->postal_code_)); } static tl_object_ptr convert_order_info( From ffab6fe0186b94b7d5c8f8f328d4bf8a3f3af66e Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 1 Apr 2021 21:10:25 +0300 Subject: [PATCH 166/281] Remove top_thread_message_id from scheduled messages. --- td/telegram/MessagesManager.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 219f01226..6ef73a636 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -6308,7 +6308,7 @@ int32 MessagesManager::get_message_index_mask(DialogId dialog_id, const Message void MessagesManager::update_reply_count_by_message(Dialog *d, int diff, const Message *m) { if (td_->auth_manager_->is_bot() || !m->top_thread_message_id.is_valid() || - m->top_thread_message_id == m->message_id || !m->message_id.is_server()) { + m->top_thread_message_id == m->message_id || !m->message_id.is_valid() || !m->message_id.is_server()) { return; } @@ -13428,7 +13428,7 @@ std::pair> MessagesManager::creat reply_in_dialog_id = DialogId(); } } - if (reply_to_message_id.is_valid() && !td_->auth_manager_->is_bot()) { + if (reply_to_message_id.is_valid() && !td_->auth_manager_->is_bot() && !message_id.is_scheduled()) { if ((message_info.reply_header->flags_ & telegram_api::messageReplyHeader::REPLY_TO_TOP_ID_MASK) != 0) { top_thread_message_id = MessageId(ServerMessageId(message_info.reply_header->reply_to_top_id_)); } else if (!is_broadcast_channel(dialog_id)) { @@ -13491,7 +13491,7 @@ std::pair> MessagesManager::creat } MessageReplyInfo reply_info(std::move(message_info.reply_info), td_->auth_manager_->is_bot()); if (!top_thread_message_id.is_valid() && !is_broadcast_channel(dialog_id) && - is_active_message_reply_info(dialog_id, reply_info)) { + is_active_message_reply_info(dialog_id, reply_info) && !message_id.is_scheduled()) { top_thread_message_id = message_id; } if (top_thread_message_id.is_valid() && dialog_type != DialogType::Channel) { @@ -13634,10 +13634,8 @@ FullMessageId MessagesManager::on_get_message(MessageInfo &&message_info, bool f MessageId old_message_id = find_old_message_id(dialog_id, message_id); bool is_sent_message = false; - if (old_message_id.is_valid()) { - LOG(INFO) << "Found temporary " << old_message_id << " for " << FullMessageId{dialog_id, message_id}; - } if (old_message_id.is_valid() || old_message_id.is_valid_scheduled()) { + LOG(INFO) << "Found temporary " << old_message_id << " for " << FullMessageId{dialog_id, message_id}; Dialog *d = get_dialog(dialog_id); CHECK(d != nullptr); @@ -13744,7 +13742,7 @@ FullMessageId MessagesManager::on_get_message(MessageInfo &&message_info, bool f update_message_count_by_index(d, +1, m); } - if (is_sent_message || need_update) { + if (is_sent_message || (need_update && !message_id.is_scheduled())) { update_reply_count_by_message(d, +1, m); update_forward_count(dialog_id, m); } @@ -22932,11 +22930,13 @@ MessagesManager::Message *MessagesManager::get_message_to_send( m->send_date = G()->unix_time(); m->date = is_scheduled ? options.schedule_date : m->send_date; m->reply_to_message_id = reply_to_message_id; - m->top_thread_message_id = top_thread_message_id; - if (reply_to_message_id.is_valid()) { - const Message *reply_m = get_message(d, reply_to_message_id); - if (reply_m != nullptr && reply_m->top_thread_message_id.is_valid()) { - m->top_thread_message_id = reply_m->top_thread_message_id; + if (!is_scheduled) { + m->top_thread_message_id = top_thread_message_id; + if (reply_to_message_id.is_valid()) { + const Message *reply_m = get_message(d, reply_to_message_id); + if (reply_m != nullptr && reply_m->top_thread_message_id.is_valid()) { + m->top_thread_message_id = reply_m->top_thread_message_id; + } } } m->is_channel_post = is_channel_post; @@ -26696,7 +26696,7 @@ Result MessagesManager::add_local_message( } m->date = G()->unix_time(); m->reply_to_message_id = get_reply_to_message_id(d, MessageId(), reply_to_message_id, false); - if (m->reply_to_message_id.is_valid()) { + if (m->reply_to_message_id.is_valid() && !message_id.is_scheduled()) { const Message *reply_m = get_message(d, m->reply_to_message_id); if (reply_m != nullptr) { m->top_thread_message_id = reply_m->top_thread_message_id; @@ -31931,7 +31931,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } } if (!message->top_thread_message_id.is_valid() && !is_broadcast_channel(dialog_id) && - is_visible_message_reply_info(dialog_id, message.get())) { + is_visible_message_reply_info(dialog_id, message.get()) && !message_id.is_scheduled()) { message->top_thread_message_id = message_id; } @@ -32653,6 +32653,8 @@ MessagesManager::Message *MessagesManager::add_scheduled_message_to_dialog(Dialo CHECK(!message->notification_id.is_valid()); CHECK(!message->removed_notification_id.is_valid()); + message->top_thread_message_id = MessageId(); + if (d->deleted_message_ids.count(message_id)) { LOG(INFO) << "Skip adding deleted " << message_id << " to " << dialog_id << " from " << source; debug_add_message_to_dialog_fail_reason_ = "adding deleted scheduled message"; From e75d8ccadcda9e1863487c14be2f7f8ee7b18029 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 1 Apr 2021 21:27:40 +0300 Subject: [PATCH 167/281] Add check. --- td/telegram/MessagesManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 6ef73a636..ad0b10593 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -34176,6 +34176,7 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab if (default_join_group_call_as_dialog_id != d->default_join_group_call_as_dialog_id) { CHECK(default_join_group_call_as_dialog_id.is_valid()); + CHECK(!d->default_join_group_call_as_dialog_id.is_valid()); if (!have_dialog(default_join_group_call_as_dialog_id)) { LOG(INFO) << "Postpone adding of default join voice chat as " << default_join_group_call_as_dialog_id << " in " << dialog_id; From 5b6301c40c6757e68f13e2f25216f817af47087a Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 1 Apr 2021 21:53:23 +0300 Subject: [PATCH 168/281] Fix payments native provider data. --- td/telegram/Payments.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 358caa059..22ebb11e3 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -158,12 +158,16 @@ static tl_object_ptr convert_payment_provider( auto r_need_postal_code = get_json_object_bool_field(value.get_object(), "need_zip", false); auto r_need_cardholder_name = get_json_object_bool_field(value.get_object(), "need_cardholder_name", false); auto r_publishable_key = get_json_object_string_field(value.get_object(), "publishable_key", false); + // TODO support "gpay_parameters":{"gateway":"stripe","stripe:publishableKey":"...","stripe:version":"..."} - if (value.get_object().size() != 4 || r_need_country.is_error() || r_need_postal_code.is_error() || - r_need_cardholder_name.is_error() || r_publishable_key.is_error()) { - LOG(WARNING) << "Unsupported JSON data \"" << native_parameters->data_ << '"'; + if (r_need_country.is_error() || r_need_postal_code.is_error() || r_need_cardholder_name.is_error() || + r_publishable_key.is_error()) { + LOG(ERROR) << "Unsupported JSON data \"" << native_parameters->data_ << '"'; return nullptr; } + if (value.get_object().size() != 5) { + LOG(ERROR) << "Unsupported JSON data \"" << native_parameters->data_ << '"'; + } return make_tl_object(r_publishable_key.move_as_ok(), r_need_country.move_as_ok(), r_need_postal_code.move_as_ok(), From 40740597f7b50f4c1d7bb4aae7c1690b5b9ee469 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 2 Apr 2021 16:30:10 +0300 Subject: [PATCH 169/281] Add ChainBufferReader::advance debug. --- tdutils/td/utils/buffer.cpp | 13 +++++++++++++ tdutils/td/utils/buffer.h | 5 +---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tdutils/td/utils/buffer.cpp b/tdutils/td/utils/buffer.cpp index 0e97c47d6..05da3e220 100644 --- a/tdutils/td/utils/buffer.cpp +++ b/tdutils/td/utils/buffer.cpp @@ -6,6 +6,7 @@ // #include "td/utils/buffer.h" +#include "td/utils/logging.h" #include "td/utils/port/thread_local.h" #include "td/utils/ThreadSafeCounter.h" @@ -106,6 +107,12 @@ void BufferAllocator::dec_ref_cnt(BufferRaw *ptr) { } } +size_t ChainBufferReader::advance(size_t offset, MutableSlice dest) { + LOG_CHECK(offset <= size()) << offset << " " << size() << " " << end_.offset() << " " << begin_.offset() << " " + << sync_flag_ << " " << dest.size(); + return begin_.advance(offset, dest); +} + BufferRaw *BufferAllocator::create_buffer_raw(size_t size) { size = (size + 7) & -8; @@ -124,6 +131,7 @@ void BufferBuilder::append(BufferSlice slice) { } append_slow(std::move(slice)); } + void BufferBuilder::append(Slice slice) { if (append_inplace(slice)) { return; @@ -137,6 +145,7 @@ void BufferBuilder::prepend(BufferSlice slice) { } prepend_slow(std::move(slice)); } + void BufferBuilder::prepend(Slice slice) { if (prepend_inplace(slice)) { return; @@ -177,9 +186,11 @@ bool BufferBuilder::append_inplace(Slice slice) { buffer_writer_.confirm_append(slice.size()); return true; } + void BufferBuilder::append_slow(BufferSlice slice) { to_append_.push_back(std::move(slice)); } + bool BufferBuilder::prepend_inplace(Slice slice) { if (!to_prepend_.empty()) { return false; @@ -193,7 +204,9 @@ bool BufferBuilder::prepend_inplace(Slice slice) { buffer_writer_.confirm_prepend(slice.size()); return true; } + void BufferBuilder::prepend_slow(BufferSlice slice) { to_prepend_.push_back(std::move(slice)); } + } // namespace td diff --git a/tdutils/td/utils/buffer.h b/tdutils/td/utils/buffer.h index 36844b90a..b37c67ca3 100644 --- a/tdutils/td/utils/buffer.h +++ b/tdutils/td/utils/buffer.h @@ -610,10 +610,7 @@ class ChainBufferReader { begin_.confirm_read(size); } - size_t advance(size_t offset, MutableSlice dest = MutableSlice()) { - CHECK(offset <= size()); - return begin_.advance(offset, dest); - } + size_t advance(size_t offset, MutableSlice dest = MutableSlice()); size_t size() const { return end_.offset() - begin_.offset(); From 1bbcc01091c8ca92f79821790b8857edb5a1b6b4 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 2 Apr 2021 17:04:51 +0300 Subject: [PATCH 170/281] Fix MessagePaymentSuccessful storing. --- td/telegram/MessageContent.cpp | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index d134482bc..8bd03a05b 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -936,6 +936,7 @@ static void store(const MessageContent *content, StorerT &storer) { bool has_telegram_payment_charge_id = !m->telegram_payment_charge_id.empty(); bool has_provider_payment_charge_id = !m->provider_payment_charge_id.empty(); bool has_invoice_message_id = m->invoice_message_id.is_valid(); + bool is_correctly_stored = true; BEGIN_STORE_FLAGS(); STORE_FLAG(has_payload); STORE_FLAG(has_shipping_option_id); @@ -943,14 +944,15 @@ static void store(const MessageContent *content, StorerT &storer) { STORE_FLAG(has_telegram_payment_charge_id); STORE_FLAG(has_provider_payment_charge_id); STORE_FLAG(has_invoice_message_id); + STORE_FLAG(is_correctly_stored); END_STORE_FLAGS(); store(m->currency, storer); store(m->total_amount, storer); if (has_payload) { - store(m->total_amount, storer); + store(m->invoice_payload, storer); } if (has_shipping_option_id) { - store(m->invoice_payload, storer); + store(m->shipping_option_id, storer); } if (has_order_info) { store(m->order_info, storer); @@ -1309,6 +1311,7 @@ static void parse(unique_ptr &content, ParserT &parser) { bool has_telegram_payment_charge_id; bool has_provider_payment_charge_id; bool has_invoice_message_id; + bool is_correctly_stored; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_payload); PARSE_FLAG(has_shipping_option_id); @@ -1316,14 +1319,24 @@ static void parse(unique_ptr &content, ParserT &parser) { PARSE_FLAG(has_telegram_payment_charge_id); PARSE_FLAG(has_provider_payment_charge_id); PARSE_FLAG(has_invoice_message_id); + PARSE_FLAG(is_correctly_stored); END_PARSE_FLAGS(); parse(m->currency, parser); parse(m->total_amount, parser); - if (has_payload) { - parse(m->total_amount, parser); - } - if (has_shipping_option_id) { - parse(m->invoice_payload, parser); + if (is_correctly_stored) { + if (has_payload) { + parse(m->invoice_payload, parser); + } + if (has_shipping_option_id) { + parse(m->shipping_option_id, parser); + } + } else { + if (has_payload) { + parse(m->total_amount, parser); + } + if (has_shipping_option_id) { + parse(m->invoice_payload, parser); + } } if (has_order_info) { parse(m->order_info, parser); @@ -1337,7 +1350,11 @@ static void parse(unique_ptr &content, ParserT &parser) { if (has_invoice_message_id) { parse(m->invoice_message_id, parser); } - content = std::move(m); + if (is_correctly_stored) { + content = std::move(m); + } else { + content = make_unique(0); + } break; } case MessageContentType::ContactRegistered: From bee68243e8541c3d3038679f0a0c7a4aadf81ed8 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 3 Apr 2021 02:19:30 +0300 Subject: [PATCH 171/281] Fix CHECK. --- td/telegram/MessagesManager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index ad0b10593..63df32454 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -10970,7 +10970,11 @@ void MessagesManager::unload_dialog(DialogId dialog_id) { Dialog *d = get_dialog(dialog_id); CHECK(d != nullptr); - CHECK(d->has_unload_timeout); + + if (!d->has_unload_timeout) { + // possible right after the dialog was opened + return; + } if (!is_message_unload_enabled()) { // just in case From 5a885bd06d783cee8253f290638277c42e906a8a Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 3 Apr 2021 02:46:56 +0300 Subject: [PATCH 172/281] Add more logging. --- td/telegram/MessagesManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 63df32454..9c3a9be12 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -34561,8 +34561,9 @@ bool MessagesManager::set_dialog_order(Dialog *d, int64 new_order, bool need_sen } auto folder_ptr = get_dialog_folder(d->folder_id); - LOG_CHECK(folder_ptr != nullptr) << dialog_id << ' ' << d->folder_id << ' ' << is_loaded_from_database << ' ' - << source; + LOG_CHECK(folder_ptr != nullptr) << is_inited_ << ' ' << G()->close_flag() << ' ' << dialog_id << ' ' << d->folder_id + << ' ' << is_loaded_from_database << ' ' << td_->auth_manager_->is_authorized() + << ' ' << td_->auth_manager_->was_authorized() << ' ' << source; auto &folder = *folder_ptr; if (old_date == new_date) { if (new_order == DEFAULT_ORDER) { From efb9c6b41dc6a5ce62ff88e5e16ed277a54835df Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sat, 3 Apr 2021 12:46:22 +0200 Subject: [PATCH 173/281] Add optiona pull-based backpressure system for get_channel_difference --- README.md | 4 ++-- td/generate/scheme/td_api.tl | 6 +++++ td/telegram/MessagesManager.cpp | 40 ++++++++++++++++++++------------- td/telegram/MessagesManager.h | 19 +++++++++++++++- td/telegram/Td.cpp | 16 ++++++++++--- td/telegram/Td.h | 2 ++ 6 files changed, 66 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 75b777968..9d14dacca 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,8 @@ We added some options: * **delete_file_reference_after_seconds** (positive number) During cleanup, free the memory of the files that have not been touched for more than X seconds * **experiment_enable_file_reference_cleanup** (**true**/false) During cleanup, free the memory of the file references * **experiment_enable_chat_access_hash_cleanup** (**true**/false) During cleanup, clean chats and channels access hash -* **get_channel_difference_delay_milliseconds** (**0**) Delay get_channel_difference n milliseconds every ~3000pts (~300msg). - Don't modify this option unless you have a very large bot that struggles to keep up with start-up updates throughput. +* **enable_pull_based_backpressure** (true/**false**) Enable manual `get_channel_difference` execution by calling `getChannelDifference(channel_difference_id)`. + Don't modify this option unless you have a very large bot that struggles to keep up with start-up updates throughput, or you want to implement a pull-based async library. ## Custom API functions ### TdApi.OptimizeMemory diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 87b860fe4..ef2da6499 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -3346,6 +3346,9 @@ updateAuthorizationState authorization_state:AuthorizationState = Update; //@description A new message was received; can also be an outgoing message @message The new message updateNewMessage message:message = Update; +//@description A new channel difference part was received @channel_difference_id The channel difference id +updateNewChannelDifferencePart channel_difference_id:int64 = Update; + //@description A request to send a message has reached the Telegram server. This doesn't mean that the message will be sent successfully or even that the send message request will be processed. This update will be sent only if the option "use_quick_ack" is set to true. This update may be sent multiple times for the same message //@chat_id The chat identifier of the sent message @message_id A temporary message identifier updateMessageSendAcknowledged chat_id:int53 message_id:int53 = Update; @@ -3823,6 +3826,9 @@ getMessageThread chat_id:int53 message_id:int53 = MessageThreadInfo; //@description Returns information about a file; this is an offline request @file_id Identifier of the file to get getFile file_id:int32 = File; +//@description Execute a channel difference @channel_difference_id Identifier of the channel difference to execute +getChannelDifference channel_difference_id:int64 = Ok; + //@description Returns information about a file by its remote ID; this is an offline request. Can be used to register a URL as a file for further uploading, or sending as a message. Even the request succeeds, the file can be used only if it is still accessible to the user. //-For example, if the file is from a message, then the message must be not deleted and accessible to the user. If the file database is disabled, then the corresponding object with the file must be preloaded by the application //@remote_file_id Remote identifier of the file to get @file_type File type, if known diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 449bc3395..8eba7b3b8 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -32718,14 +32718,14 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq auto next_message = *it; if (next_message != nullptr) { if (next_message->message_id.is_server()) { - if (G()->shared_config().get_option_integer("get_channel_difference_delay_milliseconds", 0) <= 0) { + if (G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false) == false) { LOG(ERROR) << "Attach " << message_id << " from " << source << " before " << next_message->message_id << " and after " << previous_message_id << " in " << dialog_id; dump_debug_message_op(d); } } } else { - if (G()->shared_config().get_option_integer("get_channel_difference_delay_milliseconds", 0) <= 0) { + if (G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false) == false) { LOG(ERROR) << "Have_next is true, but there is no next message after " << previous_message_id << " from " << source << " in " << dialog_id; dump_debug_message_op(d); @@ -35794,22 +35794,32 @@ class MessagesManager::GetChannelDifferenceLogEvent { }; void MessagesManager::get_channel_difference_delayed(DialogId dialog_id, int32 pts, - bool force, double delay_seconds, const char *source) { - if (delay_seconds <= 0.0) { + bool force, bool enable_pull_based_backpressure, const char *source) { + if (!enable_pull_based_backpressure) { // Execute get_channel_difference immediatly get_channel_difference(dialog_id,pts, force, "on_get_channel_difference"); } else { - // Schedule get_channel_difference - create_actor( - "GetChannelDifferenceDelayedActor", delay_seconds, - PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, pts, force](Result result) { - send_closure(actor_id, &MessagesManager::get_channel_difference, dialog_id, pts, force, - "on_get_channel_difference"); - })) - .release(); + auto channel_difference_id = ++last_pending_channel_difference_; + pending_channel_difference_ + .emplace(channel_difference_id, td::make_unique(dialog_id, pts, force, source)); + send_closure(G()->td(), &Td::send_update, + make_tl_object(channel_difference_id)); } } +bool MessagesManager::run_get_channel_difference_request(long id) { + auto pending_channel_difference_entry = pending_channel_difference_.find(id); + if (pending_channel_difference_entry == pending_channel_difference_.end()) { + return false; + } + pending_channel_difference_.erase(pending_channel_difference_entry->first); + // Run get_channel_difference + get_channel_difference(pending_channel_difference_entry->second->dialog_id, + pending_channel_difference_entry->second->pts, pending_channel_difference_entry->second->force, + "on_get_channel_difference"); + return true; +} + void MessagesManager::get_channel_difference(DialogId dialog_id, int32 pts, bool force, const char *source) { if (channel_get_difference_retry_timeout_.has_timeout(dialog_id.get())) { LOG(INFO) << "Skip running channels.getDifference for " << dialog_id << " from " << source @@ -36226,9 +36236,9 @@ void MessagesManager::on_get_channel_difference( if (!is_final) { LOG_IF(ERROR, timeout > 0) << "Have timeout in not final ChannelDifference in " << dialog_id; - auto delay_seconds = static_cast(G()->shared_config() - .get_option_integer("get_channel_difference_delay_milliseconds", 0)) / 1000.0; - get_channel_difference_delayed(dialog_id, d->pts, true, delay_seconds, "on_get_channel_difference"); + auto enable_pull_based_backpressure + = G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false); + get_channel_difference_delayed(dialog_id, d->pts, true, enable_pull_based_backpressure, "on_get_channel_difference"); return; } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index b9bf51c79..0b90b2add 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -195,6 +195,8 @@ class MessagesManager : public Actor { void get_channel_difference_if_needed(DialogId dialog_id, MessagesInfo &&messages_info, Promise &&promise); + bool run_get_channel_difference_request(long id); + void on_get_messages(vector> &&messages, bool is_channel_message, bool is_scheduled, const char *source); @@ -2788,7 +2790,8 @@ class MessagesManager : public Actor { void on_channel_get_difference_timeout(DialogId dialog_id); - void get_channel_difference_delayed(DialogId dialog_id, int32 pts, bool force, double timeout, const char *source); + void get_channel_difference_delayed(DialogId dialog_id, int32 pts, bool force, bool enable_pull_based_backpressure, + const char *source); void get_channel_difference(DialogId dialog_id, int32 pts, bool force, const char *source); @@ -3130,6 +3133,20 @@ class MessagesManager : public Actor { }; std::unordered_map> pending_message_imports_; + struct PendingChannelDifference { + DialogId dialog_id; + int32 pts; + bool force; + const char *source; + + PendingChannelDifference(DialogId dialog_id, int32 pts, bool force, const char *source) + : dialog_id(dialog_id), pts(pts), force(force), source(source) { + + } + }; + std::unordered_map> pending_channel_difference_; + int64 last_pending_channel_difference_ = 0; + struct PendingMessageGroupSend { DialogId dialog_id; size_t finished_count = 0; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index c8ec6598f..2988e4e64 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5177,6 +5177,18 @@ void Td::on_request(uint64 id, const td_api::getFile &request) { send_closure(actor_id(this), &Td::send_result, id, file_manager_->get_file_object(FileId(request.file_id_, 0))); } +void Td::on_request(uint64 id, const td_api::getChannelDifference &request) { + auto result = messages_manager_->run_get_channel_difference_request(request.channel_difference_id_); + if (result) { + send_closure(actor_id(this), &Td::send_result, id, + td_api::make_object()); + } else { + send_closure(actor_id(this), &Td::send_result, id, + td_api::make_object( + 400, "Channel diffence identifier already executed or nonexistent")); + } +} + void Td::on_request(uint64 id, td_api::getRemoteFile &request) { CLEAN_INPUT_STRING(request.remote_file_id_); auto file_type = request.file_type_ == nullptr ? FileType::Temp : get_file_type(*request.file_type_); @@ -7540,9 +7552,7 @@ void Td::on_request(uint64 id, td_api::setOption &request) { if (set_boolean_option("experiment_old_postponed_pts_updates_behavior")) { return; } - break; - case 'g': - if (set_integer_option("get_channel_difference_delay_milliseconds")) { + if (set_boolean_option("enable_pull_based_backpressure")) { return; } break; diff --git a/td/telegram/Td.h b/td/telegram/Td.h index a657d80b1..c5381f55d 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -525,6 +525,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::getFile &request); + void on_request(uint64 id, const td_api::getChannelDifference &request); + void on_request(uint64 id, td_api::getRemoteFile &request); void on_request(uint64 id, td_api::getStorageStatistics &request); From 9c67d7a6b71fe8b844a9aab04faa6f2119b4ae2b Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sat, 3 Apr 2021 13:10:25 +0200 Subject: [PATCH 174/281] Fix disable_minithumbnails --- td/telegram/Photo.cpp | 18 +++++++++++++++--- td/telegram/VideoNotesManager.cpp | 7 ++++++- td/telegram/VideosManager.cpp | 6 +++++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/td/telegram/Photo.cpp b/td/telegram/Photo.cpp index 5a39f9408..4001e2330 100644 --- a/td/telegram/Photo.cpp +++ b/td/telegram/Photo.cpp @@ -401,9 +401,17 @@ Variant get_photo_size(FileManager *file_manager, PhotoSizeSo } else { LOG(ERROR) << "Receive unexpected JPEG minithumbnail in photo of format " << format; } - return std::move(res); + if (G()->shared_config().get_option_boolean("disable_minithumbnails")) { + return ""; + } else { + return std::move(res); + } + } + if (G()->shared_config().get_option_boolean("disable_minithumbnails")) { + return ""; + } else { + return size->bytes_.as_slice().str(); } - return size->bytes_.as_slice().str(); } case telegram_api::photoSizeProgressive::ID: { auto size = move_tl_object_as(size_ptr); @@ -734,7 +742,11 @@ Photo get_photo(FileManager *file_manager, tl_object_ptr && } res.photos.push_back(std::move(size)); } else { - res.minithumbnail = std::move(photo_size.get<1>()); + if (G()->shared_config().get_option_boolean("disable_minithumbnails")) { + res.minithumbnail = ""; + } else { + res.minithumbnail = std::move(photo_size.get<1>()); + } } } diff --git a/td/telegram/VideoNotesManager.cpp b/td/telegram/VideoNotesManager.cpp index 5829192cd..b8fa68972 100644 --- a/td/telegram/VideoNotesManager.cpp +++ b/td/telegram/VideoNotesManager.cpp @@ -12,6 +12,7 @@ #include "td/telegram/files/FileManager.h" #include "td/telegram/SecretChatActor.h" +#include "td/telegram/ConfigShared.h" #include "td/telegram/Td.h" #include "td/utils/logging.h" @@ -170,7 +171,11 @@ void VideoNotesManager::create_video_note(FileId file_id, string minithumbnail, } else { LOG(INFO) << "Receive wrong video note dimensions " << dimensions; } - v->minithumbnail = std::move(minithumbnail); + if (G()->shared_config().get_option_boolean("disable_minithumbnails")) { + v->minithumbnail = ""; + } else { + v->minithumbnail = std::move(minithumbnail); + } v->thumbnail = std::move(thumbnail); on_get_video_note(std::move(v), replace); } diff --git a/td/telegram/VideosManager.cpp b/td/telegram/VideosManager.cpp index 0417fe423..c78049c85 100644 --- a/td/telegram/VideosManager.cpp +++ b/td/telegram/VideosManager.cpp @@ -215,7 +215,11 @@ void VideosManager::create_video(FileId file_id, string minithumbnail, PhotoSize v->mime_type = std::move(mime_type); v->duration = max(duration, 0); v->dimensions = dimensions; - v->minithumbnail = std::move(minithumbnail); + if (G()->shared_config().get_option_boolean("disable_minithumbnails")) { + v->minithumbnail = ""; + } else { + v->minithumbnail = std::move(minithumbnail); + } v->thumbnail = std::move(thumbnail); v->animated_thumbnail = std::move(animated_thumbnail); v->supports_streaming = supports_streaming; From 4a8d8a3ffb21d1449c659f8ad3467edfb8191d12 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sat, 3 Apr 2021 14:52:16 +0200 Subject: [PATCH 175/281] Bugfix --- td/telegram/Photo.cpp | 4 ++-- td/telegram/VideosManager.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/td/telegram/Photo.cpp b/td/telegram/Photo.cpp index 4001e2330..090af902a 100644 --- a/td/telegram/Photo.cpp +++ b/td/telegram/Photo.cpp @@ -402,13 +402,13 @@ Variant get_photo_size(FileManager *file_manager, PhotoSizeSo LOG(ERROR) << "Receive unexpected JPEG minithumbnail in photo of format " << format; } if (G()->shared_config().get_option_boolean("disable_minithumbnails")) { - return ""; + return std::string(""); } else { return std::move(res); } } if (G()->shared_config().get_option_boolean("disable_minithumbnails")) { - return ""; + return std::string(""); } else { return size->bytes_.as_slice().str(); } diff --git a/td/telegram/VideosManager.cpp b/td/telegram/VideosManager.cpp index c78049c85..640e54b91 100644 --- a/td/telegram/VideosManager.cpp +++ b/td/telegram/VideosManager.cpp @@ -9,6 +9,7 @@ #include "td/telegram/secret_api.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/ConfigShared.h" #include "td/telegram/files/FileManager.h" #include "td/telegram/Td.h" From 84194768ae963ee91b2ca2a5fb018ca8c1003fd8 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 3 Apr 2021 22:41:26 +0300 Subject: [PATCH 176/281] Add check that chats aren't created before MessagesManager is inited. --- td/telegram/MessagesManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 9c3a9be12..d5dc8d544 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -33739,6 +33739,7 @@ MessageId MessagesManager::get_message_id_by_random_id(Dialog *d, int64 random_i void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source, bool expect_no_access, bool force_update_dialog_pos) { LOG_CHECK(dialog_id.is_valid()) << source; + LOG_CHECK(is_inited_) << dialog_id << ' ' << source << ' ' << expect_no_access << ' ' << force_update_dialog_pos; Dialog *d = get_dialog_force(dialog_id); if (d == nullptr) { LOG(INFO) << "Force create " << dialog_id << " from " << source; @@ -33829,6 +33830,7 @@ MessagesManager::Dialog *MessagesManager::add_dialog(DialogId dialog_id) { MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&d, bool is_loaded_from_database) { auto dialog_id = d->dialog_id; + LOG_CHECK(is_inited_) << dialog_id << ' ' << is_loaded_from_database; switch (dialog_id.get_type()) { case DialogType::User: if (dialog_id == get_my_dialog_id() && d->last_read_inbox_message_id == MessageId::max() && From 6285d98479cfbacd53b5c70e1dc433ab6dcaf182 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 4 Apr 2021 00:40:37 +0300 Subject: [PATCH 177/281] Fix writev on Windows. --- tdutils/td/utils/port/FileFd.cpp | 11 ++++++++++- tdutils/td/utils/port/IoSlice.h | 2 +- tdutils/td/utils/port/SocketFd.cpp | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/tdutils/td/utils/port/FileFd.cpp b/tdutils/td/utils/port/FileFd.cpp index d5c0db9dc..6b8ba9078 100644 --- a/tdutils/td/utils/port/FileFd.cpp +++ b/tdutils/td/utils/port/FileFd.cpp @@ -36,6 +36,8 @@ #include #include #include +#else +#include #endif #if TD_PORT_WINDOWS && defined(WIN32_LEAN_AND_MEAN) @@ -271,9 +273,16 @@ Result FileFd::writev(Span slices) { return OS_ERROR(PSLICE() << "Writev to " << get_native_fd() << " has failed"); #else size_t res = 0; - for (auto slice : slices) { + for (const auto &slice : slices) { + if (slice.size() > std::numeric_limits::max() - res) { + break; + } TRY_RESULT(size, write(slice)); res += size; + if (size != slice.size()) { + CHECK(size < slice.size()); + break; + } } return res; #endif diff --git a/tdutils/td/utils/port/IoSlice.h b/tdutils/td/utils/port/IoSlice.h index f1d356dd1..47fa230d8 100644 --- a/tdutils/td/utils/port/IoSlice.h +++ b/tdutils/td/utils/port/IoSlice.h @@ -25,7 +25,7 @@ inline IoSlice as_io_slice(Slice slice) { return res; } -inline Slice as_slice(const IoSlice io_slice) { +inline Slice as_slice(const IoSlice &io_slice) { return Slice(static_cast(io_slice.iov_base), io_slice.iov_len); } diff --git a/tdutils/td/utils/port/SocketFd.cpp b/tdutils/td/utils/port/SocketFd.cpp index 05e6aee4b..36719ef61 100644 --- a/tdutils/td/utils/port/SocketFd.cpp +++ b/tdutils/td/utils/port/SocketFd.cpp @@ -30,6 +30,8 @@ #include #include #include +#else +#include #endif #include @@ -98,7 +100,9 @@ class SocketFdImpl : private Iocp::Callback { Result writev(Span slices) { size_t total_size = 0; for (auto io_slice : slices) { - total_size += as_slice(io_slice).size(); + auto size = as_slice(io_slice).size(); + CHECK(size <= std::numeric_limits::max() - total_size); + total_size += size; } auto left_size = total_size; From e246201cf0fd77d106078ce253462fc03fee9396 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 4 Apr 2021 00:47:30 +0300 Subject: [PATCH 178/281] Add checks that FileFd::read/write/pread/pwrite/writev return correct response. --- tdutils/td/utils/port/FileFd.cpp | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/tdutils/td/utils/port/FileFd.cpp b/tdutils/td/utils/port/FileFd.cpp index 6b8ba9078..8ee8c4a40 100644 --- a/tdutils/td/utils/port/FileFd.cpp +++ b/tdutils/td/utils/port/FileFd.cpp @@ -256,7 +256,9 @@ Result FileFd::write(Slice slice) { BOOL success = WriteFile(native_fd, slice.data(), narrow_cast(slice.size()), &bytes_written, nullptr); #endif if (success) { - return narrow_cast(bytes_written); + auto result = narrow_cast(bytes_written); + CHECK(result <= slice.size()); + return result; } return OS_ERROR(PSLICE() << "Write to " << get_native_fd() << " has failed"); } @@ -268,7 +270,15 @@ Result FileFd::writev(Span slices) { auto bytes_written = detail::skip_eintr([&] { return ::writev(native_fd, slices.begin(), slices_size); }); bool success = bytes_written >= 0; if (success) { - return narrow_cast(bytes_written); + auto result = narrow_cast(bytes_written); + auto left = result; + for (const auto &slice : slices) { + if (left <= slice.iov_len) { + return result; + } + left -= slice.iov_len; + } + UNREACHABLE(); } return OS_ERROR(PSLICE() << "Writev to " << get_native_fd() << " has failed"); #else @@ -314,7 +324,9 @@ Result FileFd::read(MutableSlice slice) { if (is_eof) { get_poll_info().clear_flags(PollFlags::Read()); } - return static_cast(bytes_read); + auto result = narrow_cast(bytes_read); + CHECK(result <= slice.size()); + return result; } return OS_ERROR(PSLICE() << "Read from " << get_native_fd() << " has failed"); } @@ -338,7 +350,9 @@ Result FileFd::pwrite(Slice slice, int64 offset) { BOOL success = WriteFile(native_fd, slice.data(), narrow_cast(slice.size()), &bytes_written, &overlapped); #endif if (success) { - return narrow_cast(bytes_written); + auto result = narrow_cast(bytes_written); + CHECK(result <= slice.size()); + return result; } return OS_ERROR(PSLICE() << "Pwrite to " << get_native_fd() << " at offset " << offset << " has failed"); } @@ -361,7 +375,9 @@ Result FileFd::pread(MutableSlice slice, int64 offset) const { BOOL success = ReadFile(native_fd, slice.data(), narrow_cast(slice.size()), &bytes_read, &overlapped); #endif if (success) { - return narrow_cast(bytes_read); + auto result = narrow_cast(bytes_read); + CHECK(result <= slice.size()); + return result; } return OS_ERROR(PSLICE() << "Pread from " << get_native_fd() << " at offset " << offset << " has failed"); } From 2ab94b9ca75e0607b5384f04f0681213966547de Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 4 Apr 2021 01:08:53 +0300 Subject: [PATCH 179/281] Add checks that SocketFd::read/write/writev return correct response. --- tdutils/td/utils/port/SocketFd.cpp | 36 +++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/tdutils/td/utils/port/SocketFd.cpp b/tdutils/td/utils/port/SocketFd.cpp index 36719ef61..83d418a0c 100644 --- a/tdutils/td/utils/port/SocketFd.cpp +++ b/tdutils/td/utils/port/SocketFd.cpp @@ -18,6 +18,8 @@ #include "td/utils/port/detail/Iocp.h" #include "td/utils/SpinLock.h" #include "td/utils/VectorQueue.h" + +#include #endif #if TD_PORT_POSIX @@ -30,8 +32,6 @@ #include #include #include -#else -#include #endif #include @@ -403,7 +403,19 @@ class SocketFdImpl { return ::writev(native_fd, slices.begin(), slices_size); #endif }); - return write_finish(write_res); + if (write_res >= 0) { + auto result = narrow_cast(write_res); + auto left = result; + for (const auto &slice : slices) { + if (left <= slice.iov_len) { + return result; + } + left -= slice.iov_len; + } + LOG(FATAL) << "Receive " << result << " as writev response, but tried to write only " << result - left + << " bytes"; + } + return write_finish(); } Result write(Slice slice) { @@ -416,15 +428,17 @@ class SocketFdImpl { ::write(native_fd, slice.begin(), slice.size()); #endif }); - return write_finish(write_res); + if (write_res >= 0) { + auto result = narrow_cast(write_res); + LOG_CHECK(result <= slice.size()) << "Receive " << result << " as write response, but tried to write only " + << slice.size() << " bytes"; + return result; + } + return write_finish(); } - Result write_finish(ssize_t write_res) { + Result write_finish() { auto write_errno = errno; - if (write_res >= 0) { - return narrow_cast(write_res); - } - if (write_errno == EAGAIN #if EAGAIN != EWOULDBLOCK || write_errno == EWOULDBLOCK @@ -472,7 +486,9 @@ class SocketFdImpl { get_poll_info().clear_flags(PollFlags::Read()); get_poll_info().add_flags(PollFlags::Close()); } - return narrow_cast(read_res); + auto result = narrow_cast(read_res); + CHECK(result <= slice.size()); + return result; } if (read_errno == EAGAIN #if EAGAIN != EWOULDBLOCK From 6dfe45c03c9b96da85e204a71ec76949fb24351d Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 4 Apr 2021 01:59:45 +0300 Subject: [PATCH 180/281] Fix unpinning of unknown chats. --- td/telegram/MessagesManager.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index d5dc8d544..46e8ceb0e 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -14685,7 +14685,13 @@ void MessagesManager::on_get_dialogs(FolderId folder_id, vector Date: Sun, 4 Apr 2021 02:58:59 +0300 Subject: [PATCH 181/281] Fix MoveFileExFromAppW. --- tdutils/td/utils/port/FromApp.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tdutils/td/utils/port/FromApp.h b/tdutils/td/utils/port/FromApp.h index bab7324a8..71cdfb9bb 100644 --- a/tdutils/td/utils/port/FromApp.h +++ b/tdutils/td/utils/port/FromApp.h @@ -76,11 +76,15 @@ inline BOOL DeleteFileFromAppW(_In_ LPCWSTR lpFileName) { } inline BOOL MoveFileExFromAppW(_In_ LPCWSTR lpExistingFileName, _In_ LPCWSTR lpNewFileName, _In_ DWORD dwFlags) { - auto func = get_from_app_function<4>("MoveFileFromAppW", &MoveFileEx); - if (func != &MoveFileEx && (dwFlags & MOVEFILE_REPLACE_EXISTING) != 0) { + auto func = get_from_app_function<4>("MoveFileFromAppW", &MoveFile); + if (func == &MoveFile || (dwFlags & ~MOVEFILE_REPLACE_EXISTING) != 0) { + // if can't find MoveFileFromAppW or have unsupported flags, call MoveFileEx directly + return MoveFileEx(lpExistingFileName, lpNewFileName, dwFlags); + } + if ((dwFlags & MOVEFILE_REPLACE_EXISTING) != 0) { td::DeleteFileFromAppW(lpNewFileName); } - return func(lpExistingFileName, lpNewFileName, dwFlags); + return func(lpExistingFileName, lpNewFileName); } inline HANDLE FindFirstFileExFromAppW(_In_ LPCWSTR lpFileName, _In_ FINDEX_INFO_LEVELS fInfoLevelId, From 8039660cfe4b3f33a4a70e57abc0a7521b1c37e9 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 4 Apr 2021 03:23:22 +0300 Subject: [PATCH 182/281] Reload objects from server if failed to resolve their dependencies. --- td/telegram/ContactsManager.cpp | 18 +++++++++++++++--- td/telegram/Dependencies.cpp | 12 ++++++++++-- td/telegram/Dependencies.h | 2 +- td/telegram/MessageContent.cpp | 1 + td/telegram/MessageContent.h | 2 +- td/telegram/MessageEntity.cpp | 1 + td/telegram/MessageEntity.h | 2 +- td/telegram/MessagesManager.cpp | 24 +++++++++++++++--------- td/telegram/MessagesManager.h | 8 +------- 9 files changed, 46 insertions(+), 24 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 943f9f38d..151bde49e 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -9231,7 +9231,11 @@ void ContactsManager::on_load_user_full_from_database(UserId user_id, string val Dependencies dependencies; dependencies.user_ids.insert(user_id); - resolve_dependencies_force(td_, dependencies, "user_full"); + if (!resolve_dependencies_force(td_, dependencies, "user_full")) { + users_full_.erase(user_id); + G()->td_db()->get_sqlite_pmc()->erase(get_user_full_database_key(user_id), Auto()); + return; + } if (user_full->need_phone_number_privacy_exception && is_user_contact(user_id)) { user_full->need_phone_number_privacy_exception = false; @@ -9418,7 +9422,11 @@ void ContactsManager::on_load_chat_full_from_database(ChatId chat_id, string val dependencies.user_ids.insert(participant.inviter_user_id); } dependencies.user_ids.insert(chat_full->invite_link.get_creator_user_id()); - resolve_dependencies_force(td_, dependencies, "chat_full"); + if (!resolve_dependencies_force(td_, dependencies, "chat_full")) { + chats_full_.erase(chat_id); + G()->td_db()->get_sqlite_pmc()->erase(get_chat_full_database_key(chat_id), Auto()); + return; + } for (auto &participant : chat_full->participants) { get_bot_info_force(participant.user_id); @@ -9522,7 +9530,11 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s dependencies.chat_ids.insert(channel_full->migrated_from_chat_id); dependencies.user_ids.insert(channel_full->bot_user_ids.begin(), channel_full->bot_user_ids.end()); dependencies.user_ids.insert(channel_full->invite_link.get_creator_user_id()); - resolve_dependencies_force(td_, dependencies, "channel_full"); + if (!resolve_dependencies_force(td_, dependencies, "channel_full")) { + channels_full_.erase(channel_id); + G()->td_db()->get_sqlite_pmc()->erase(get_channel_full_database_key(channel_id), Auto()); + return; + } for (auto &user_id : channel_full->bot_user_ids) { get_bot_info_force(user_id); diff --git a/td/telegram/Dependencies.cpp b/td/telegram/Dependencies.cpp index ca117eede..86be67156 100644 --- a/td/telegram/Dependencies.cpp +++ b/td/telegram/Dependencies.cpp @@ -51,38 +51,46 @@ void add_message_sender_dependencies(Dependencies &dependencies, DialogId dialog } } -void resolve_dependencies_force(Td *td, const Dependencies &dependencies, const char *source) { +bool resolve_dependencies_force(Td *td, const Dependencies &dependencies, const char *source) { + bool success = true; for (auto user_id : dependencies.user_ids) { if (user_id.is_valid() && !td->contacts_manager_->have_user_force(user_id)) { LOG(ERROR) << "Can't find " << user_id << " from " << source; + success = false; } } for (auto chat_id : dependencies.chat_ids) { if (chat_id.is_valid() && !td->contacts_manager_->have_chat_force(chat_id)) { LOG(ERROR) << "Can't find " << chat_id << " from " << source; + success = false; } } for (auto channel_id : dependencies.channel_ids) { if (channel_id.is_valid() && !td->contacts_manager_->have_channel_force(channel_id)) { LOG(ERROR) << "Can't find " << channel_id << " from " << source; + success = false; } } for (auto secret_chat_id : dependencies.secret_chat_ids) { if (secret_chat_id.is_valid() && !td->contacts_manager_->have_secret_chat_force(secret_chat_id)) { LOG(ERROR) << "Can't find " << secret_chat_id << " from " << source; + success = false; } } for (auto dialog_id : dependencies.dialog_ids) { if (dialog_id.is_valid() && !td->messages_manager_->have_dialog_force(dialog_id)) { LOG(ERROR) << "Can't find " << dialog_id << " from " << source; - td->messages_manager_->force_create_dialog(dialog_id, "resolve_dependencies_force"); + td->messages_manager_->force_create_dialog(dialog_id, "resolve_dependencies_force", true); + success = false; } } for (auto web_page_id : dependencies.web_page_ids) { if (web_page_id.is_valid()) { td->web_pages_manager_->have_web_page_force(web_page_id); + success = false; } } + return success; } } // namespace td diff --git a/td/telegram/Dependencies.h b/td/telegram/Dependencies.h index 4e1e5734d..711715b92 100644 --- a/td/telegram/Dependencies.h +++ b/td/telegram/Dependencies.h @@ -34,6 +34,6 @@ void add_dialog_dependencies(Dependencies &dependencies, DialogId dialog_id); void add_message_sender_dependencies(Dependencies &dependencies, DialogId dialog_id); -void resolve_dependencies_force(Td *td, const Dependencies &dependencies, const char *source); +bool resolve_dependencies_force(Td *td, const Dependencies &dependencies, const char *source); } // namespace td diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 8bd03a05b..5d1f967c2 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -16,6 +16,7 @@ #include "td/telegram/ChatId.h" #include "td/telegram/Contact.h" #include "td/telegram/ContactsManager.h" +#include "td/telegram/Dependencies.h" #include "td/telegram/Document.h" #include "td/telegram/DocumentsManager.h" #include "td/telegram/DocumentsManager.hpp" diff --git a/td/telegram/MessageContent.h b/td/telegram/MessageContent.h index 398d2d4c4..179f2c9d6 100644 --- a/td/telegram/MessageContent.h +++ b/td/telegram/MessageContent.h @@ -6,7 +6,6 @@ // #pragma once -#include "td/telegram/Dependencies.h" #include "td/telegram/DialogId.h" #include "td/telegram/files/FileId.h" #include "td/telegram/FullMessageId.h" @@ -36,6 +35,7 @@ namespace td { +struct Dependencies; class Game; struct Photo; class Td; diff --git a/td/telegram/MessageEntity.cpp b/td/telegram/MessageEntity.cpp index 79556ac5b..cf3ebb349 100644 --- a/td/telegram/MessageEntity.cpp +++ b/td/telegram/MessageEntity.cpp @@ -7,6 +7,7 @@ #include "td/telegram/MessageEntity.h" #include "td/telegram/ContactsManager.h" +#include "td/telegram/Dependencies.h" #include "td/telegram/misc.h" #include "td/telegram/SecretChatActor.h" diff --git a/td/telegram/MessageEntity.h b/td/telegram/MessageEntity.h index b63127787..4a4dae5e3 100644 --- a/td/telegram/MessageEntity.h +++ b/td/telegram/MessageEntity.h @@ -6,7 +6,6 @@ // #pragma once -#include "td/telegram/Dependencies.h" #include "td/telegram/DialogId.h" #include "td/telegram/UserId.h" @@ -25,6 +24,7 @@ namespace td { class ContactsManager; +struct Dependencies; class MessageEntity { public: diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 46e8ceb0e..8ff9f4312 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -10,6 +10,7 @@ #include "td/telegram/ChatId.h" #include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" +#include "td/telegram/Dependencies.h" #include "td/telegram/DialogDb.h" #include "td/telegram/DialogFilter.h" #include "td/telegram/DialogFilter.hpp" @@ -11396,7 +11397,7 @@ void MessagesManager::repair_channel_server_unread_count(Dialog *d) { } LOG(INFO) << "Reload ChannelFull for " << d->dialog_id << " to repair unread message counts"; - get_dialog_info_full(d->dialog_id, Promise()); + get_dialog_info_full(d->dialog_id, Auto()); } void MessagesManager::read_history_inbox(DialogId dialog_id, MessageId max_message_id, int32 unread_count, @@ -22292,7 +22293,7 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId is_first = false; pos++; } - resolve_dependencies_force(td_, dependencies, "get_history"); + resolve_dependencies_force(td_, dependencies, "on_get_history_from_database"); if (from_the_end && !last_added_message_id.is_valid() && last_received_message_id < d->first_database_message_id && !d->have_full_history) { @@ -22607,7 +22608,7 @@ void MessagesManager::on_get_scheduled_messages_from_database(DialogId dialog_id added_message_ids.push_back(m->message_id); } } - resolve_dependencies_force(td_, dependencies, "get_scheduled_messages"); + resolve_dependencies_force(td_, dependencies, "on_get_scheduled_messages_from_database"); // for (auto message_id : added_message_ids) { // send_update_new_message(d, get_message(d, message_id)); @@ -29323,7 +29324,7 @@ void MessagesManager::on_update_dialog_draft_message(DialogId dialog_id, if (!have_input_peer(dialog_id, AccessRights::Read)) { LOG(ERROR) << "Have no read access to " << dialog_id << " to repair chat draft message"; } else { - send_get_dialog_query(dialog_id, Promise(), 0, "on_update_dialog_draft_message"); + send_get_dialog_query(dialog_id, Auto(), 0, "on_update_dialog_draft_message"); } return; } @@ -31849,7 +31850,7 @@ MessagesManager::Message *MessagesManager::on_get_message_from_database(DialogId CHECK(d != nullptr); } - if (!have_input_peer(d->dialog_id, AccessRights::Read)) { + if (!have_input_peer(dialog_id, AccessRights::Read)) { return nullptr; } @@ -31872,7 +31873,10 @@ MessagesManager::Message *MessagesManager::on_get_message_from_database(DialogId Dependencies dependencies; add_message_dependencies(dependencies, m.get()); - resolve_dependencies_force(td_, dependencies, "on_get_message_from_database"); + if (!resolve_dependencies_force(td_, dependencies, "on_get_message_from_database")) { + FullMessageId full_message_id{dialog_id, m->message_id}; + get_message_from_server(full_message_id, Auto()); + } m->have_previous = false; m->have_next = false; @@ -31882,7 +31886,7 @@ MessagesManager::Message *MessagesManager::on_get_message_from_database(DialogId auto result = add_message_to_dialog(d, std::move(m), false, &need_update, &need_update_dialog_pos, source); if (need_update_dialog_pos) { LOG(ERROR) << "Need update dialog pos after load " << (result == nullptr ? MessageId() : result->message_id) - << " in " << d->dialog_id << " from " << source; + << " in " << dialog_id << " from " << source; send_update_chat_last_message(d, source); } return result; @@ -34990,7 +34994,9 @@ unique_ptr MessagesManager::parse_dialog(DialogId dialo if (d->draft_message != nullptr) { add_formatted_text_dependencies(dependencies, &d->draft_message->input_message_text.text); } - resolve_dependencies_force(td_, dependencies, "parse_dialog"); + if (!resolve_dependencies_force(td_, dependencies, "parse_dialog")) { + send_get_dialog_query(dialog_id, Auto(), 0, "parse_dialog"); + } return d; } @@ -36874,7 +36880,7 @@ void MessagesManager::on_binlog_events(vector &&events) { break; } - send_get_dialog_query(dialog_id, Promise(), event.id_, "GetDialogFromServerLogEvent"); + send_get_dialog_query(dialog_id, Auto(), event.id_, "GetDialogFromServerLogEvent"); break; } case LogEvent::HandlerType::UnpinAllDialogMessagesOnServer: { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 26c0c6798..6c81d05a8 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -8,7 +8,6 @@ #include "td/telegram/AccessRights.h" #include "td/telegram/ChannelId.h" -#include "td/telegram/Dependencies.h" #include "td/telegram/DialogAction.h" #include "td/telegram/DialogDate.h" #include "td/telegram/DialogDb.h" @@ -81,17 +80,12 @@ namespace td { struct BinlogEvent; - +struct Dependencies; class DialogFilter; - class DraftMessage; - struct InputMessageContent; - class MessageContent; - class MultiSequenceDispatcher; - class Td; class MessagesManager : public Actor { From d44e9e55778aec88948ff64f9ff9245f15c8932e Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 4 Apr 2021 03:54:27 +0300 Subject: [PATCH 183/281] Add source to delete_dialog_messages. --- td/telegram/MessagesManager.cpp | 19 ++++++++++--------- td/telegram/MessagesManager.h | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 8ff9f4312..608e6cea0 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -7625,7 +7625,7 @@ void MessagesManager::process_channel_update(tl_object_ptr } auto dialog_id = DialogId(channel_id); - delete_dialog_messages(dialog_id, message_ids, true, false); + delete_dialog_messages(dialog_id, message_ids, true, false, "updateDeleteChannelMessages"); break; } case telegram_api::updateEditChannelMessage::ID: { @@ -9288,7 +9288,7 @@ void MessagesManager::after_get_difference() { void MessagesManager::on_get_empty_messages(DialogId dialog_id, vector empty_message_ids) { if (!empty_message_ids.empty()) { - delete_dialog_messages(dialog_id, std::move(empty_message_ids), true, true); + delete_dialog_messages(dialog_id, std::move(empty_message_ids), true, true, "on_get_empty_messages"); } } @@ -10107,10 +10107,11 @@ void MessagesManager::delete_messages_from_updates(const vector &mess } void MessagesManager::delete_dialog_messages(DialogId dialog_id, const vector &message_ids, - bool from_updates, bool skip_update_for_not_found_messages) { + bool from_updates, bool skip_update_for_not_found_messages, + const char *source) { Dialog *d = get_dialog_force(dialog_id); if (d == nullptr) { - LOG(INFO) << "Ignore deleteChannelMessages for unknown " << dialog_id; + LOG(INFO) << "Ignore deleteChannelMessages for unknown " << dialog_id << " from " << source; CHECK(from_updates); CHECK(dialog_id.get_type() == DialogType::Channel); return; @@ -10122,7 +10123,7 @@ void MessagesManager::delete_dialog_messages(DialogId dialog_id, const vectordeleted_message_ids.count(message_id) != 0; - auto message = delete_message(d, message_id, true, &need_update_dialog_pos, "delete_dialog_messages"); + auto message = delete_message(d, message_id, true, &need_update_dialog_pos, source); if (message == nullptr) { if (!skip_update_for_not_found_messages && !was_already_deleted) { deleted_message_ids.push_back(message_id.get()); @@ -10140,7 +10141,7 @@ void MessagesManager::delete_dialog_messages(DialogId dialog_id, const vector &message_ids); void delete_dialog_messages(DialogId dialog_id, const vector &message_ids, bool from_updates, - bool skip_update_for_not_found_messages); + bool skip_update_for_not_found_messages, const char *source); void update_dialog_pinned_messages_from_updates(DialogId dialog_id, const vector &message_ids, bool is_pin); From d84dcceae421ba6bbf91b604164715e88302166b Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sun, 4 Apr 2021 15:56:58 +0200 Subject: [PATCH 184/281] Bugfix --- td/telegram/MessagesManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 896f89304..2b28e3e3c 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -35809,10 +35809,11 @@ void MessagesManager::get_channel_difference_delayed(DialogId dialog_id, int32 p bool MessagesManager::run_get_channel_difference_request(long id) { auto pending_channel_difference_entry = pending_channel_difference_.find(id); - if (pending_channel_difference_entry == pending_channel_difference_.end()) { + if (pending_channel_difference_entry == pending_channel_difference_.end() || + pending_channel_difference_entry->second == nullptr) { return false; } - pending_channel_difference_.erase(pending_channel_difference_entry->first); + pending_channel_difference_.erase(pending_channel_difference_entry); // Run get_channel_difference get_channel_difference(pending_channel_difference_entry->second->dialog_id, pending_channel_difference_entry->second->pts, pending_channel_difference_entry->second->force, From 28a655151aa345165da5f6224a2a40e10a0316e9 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sun, 4 Apr 2021 16:11:40 +0200 Subject: [PATCH 185/281] Bugfix --- td/telegram/MessagesManager.cpp | 2 +- td/telegram/MessagesManager.h | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 2b28e3e3c..7281a6f77 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -35801,7 +35801,7 @@ void MessagesManager::get_channel_difference_delayed(DialogId dialog_id, int32 p } else { auto channel_difference_id = ++last_pending_channel_difference_; pending_channel_difference_ - .emplace(channel_difference_id, td::make_unique(dialog_id, pts, force, source)); + .emplace(channel_difference_id, td::make_unique(dialog_id, pts, force)); send_closure(G()->td(), &Td::send_update, make_tl_object(channel_difference_id)); } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 299e95113..b5760d5a9 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -3137,10 +3137,9 @@ class MessagesManager : public Actor { DialogId dialog_id; int32 pts; bool force; - const char *source; - PendingChannelDifference(DialogId dialog_id, int32 pts, bool force, const char *source) - : dialog_id(dialog_id), pts(pts), force(force), source(source) { + PendingChannelDifference(DialogId dialog_id, int32 pts, bool force) + : dialog_id(dialog_id), pts(pts), force(force) { } }; From a21920a7bdb8ad8ee8af6b17bfe74f1825a997d4 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sun, 4 Apr 2021 16:23:07 +0200 Subject: [PATCH 186/281] Bugfix --- td/telegram/MessagesManager.cpp | 11 +++++------ td/telegram/MessagesManager.h | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 7281a6f77..419cabdb5 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -35800,8 +35800,8 @@ void MessagesManager::get_channel_difference_delayed(DialogId dialog_id, int32 p get_channel_difference(dialog_id,pts, force, "on_get_channel_difference"); } else { auto channel_difference_id = ++last_pending_channel_difference_; - pending_channel_difference_ - .emplace(channel_difference_id, td::make_unique(dialog_id, pts, force)); + PendingChannelDifference pendingChannelDifference = {dialog_id, pts, force}; + pending_channel_difference_.emplace(channel_difference_id, pendingChannelDifference); send_closure(G()->td(), &Td::send_update, make_tl_object(channel_difference_id)); } @@ -35809,14 +35809,13 @@ void MessagesManager::get_channel_difference_delayed(DialogId dialog_id, int32 p bool MessagesManager::run_get_channel_difference_request(long id) { auto pending_channel_difference_entry = pending_channel_difference_.find(id); - if (pending_channel_difference_entry == pending_channel_difference_.end() || - pending_channel_difference_entry->second == nullptr) { + if (pending_channel_difference_entry == pending_channel_difference_.end()) { return false; } pending_channel_difference_.erase(pending_channel_difference_entry); // Run get_channel_difference - get_channel_difference(pending_channel_difference_entry->second->dialog_id, - pending_channel_difference_entry->second->pts, pending_channel_difference_entry->second->force, + get_channel_difference(pending_channel_difference_entry->second.dialog_id, + pending_channel_difference_entry->second.pts, pending_channel_difference_entry->second.force, "on_get_channel_difference"); return true; } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index b5760d5a9..784a4574d 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -3143,7 +3143,7 @@ class MessagesManager : public Actor { } }; - std::unordered_map> pending_channel_difference_; + std::unordered_map pending_channel_difference_; int64 last_pending_channel_difference_ = 0; struct PendingMessageGroupSend { From eefe39f16f04d8ab2c6c6cf52af4e68665ccaca3 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sun, 4 Apr 2021 16:50:56 +0200 Subject: [PATCH 187/281] Update MessagesManager.cpp --- td/telegram/MessagesManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 3b3db6979..97b37fc15 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -35822,7 +35822,7 @@ void MessagesManager::get_channel_difference_delayed(DialogId dialog_id, int32 p } else { auto channel_difference_id = ++last_pending_channel_difference_; PendingChannelDifference pendingChannelDifference = {dialog_id, pts, force}; - pending_channel_difference_.emplace(channel_difference_id, pendingChannelDifference); + pending_channel_difference_[channel_difference_id] = pendingChannelDifference; send_closure(G()->td(), &Td::send_update, make_tl_object(channel_difference_id)); } @@ -35833,11 +35833,11 @@ bool MessagesManager::run_get_channel_difference_request(long id) { if (pending_channel_difference_entry == pending_channel_difference_.end()) { return false; } - pending_channel_difference_.erase(pending_channel_difference_entry); // Run get_channel_difference get_channel_difference(pending_channel_difference_entry->second.dialog_id, pending_channel_difference_entry->second.pts, pending_channel_difference_entry->second.force, "on_get_channel_difference"); + pending_channel_difference_.erase(pending_channel_difference_entry); return true; } From 1928c14a76c9b43158641b88dd539eb7d726b43f Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sun, 4 Apr 2021 16:58:56 +0200 Subject: [PATCH 188/281] Bugfix --- td/telegram/MessagesManager.cpp | 4 ++-- td/telegram/MessagesManager.h | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 97b37fc15..dbba87a29 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -35821,8 +35821,8 @@ void MessagesManager::get_channel_difference_delayed(DialogId dialog_id, int32 p get_channel_difference(dialog_id,pts, force, "on_get_channel_difference"); } else { auto channel_difference_id = ++last_pending_channel_difference_; - PendingChannelDifference pendingChannelDifference = {dialog_id, pts, force}; - pending_channel_difference_[channel_difference_id] = pendingChannelDifference; + PendingChannelDifference pending_channel_difference = {dialog_id, pts, force}; + pending_channel_difference_[channel_difference_id] = pending_channel_difference; send_closure(G()->td(), &Td::send_update, make_tl_object(channel_difference_id)); } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 784a4574d..3efa4b0b5 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -3137,11 +3137,6 @@ class MessagesManager : public Actor { DialogId dialog_id; int32 pts; bool force; - - PendingChannelDifference(DialogId dialog_id, int32 pts, bool force) - : dialog_id(dialog_id), pts(pts), force(force) { - - } }; std::unordered_map pending_channel_difference_; int64 last_pending_channel_difference_ = 0; From 0b53ace8d01c116389ffef66a2f93fb0d320b13c Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 4 Apr 2021 22:59:56 +0300 Subject: [PATCH 189/281] Improve deletion of deleted being sent messages. --- td/telegram/MessagesManager.cpp | 36 ++++++++++++++++++++------------- td/telegram/MessagesManager.h | 2 +- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 608e6cea0..8fb41cb58 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -10458,13 +10458,25 @@ void MessagesManager::delete_messages(DialogId dialog_id, const vector old_message = delete_message(d, old_message_id, false, &need_update_dialog_pos, "add sent message"); if (old_message == nullptr) { - // message has already been deleted by the user or sent to inaccessible channel - // don't need to send update to the user, because the message has already been deleted - LOG(INFO) << "Delete already deleted sent " << new_message->message_id << " from server"; - delete_message_from_server(dialog_id, new_message->message_id, true); + delete_sent_message_from_server(dialog_id, new_message->message_id); being_readded_message_id_ = FullMessageId(); return FullMessageId(); } @@ -26961,6 +26970,7 @@ bool MessagesManager::on_update_message_id(int64 random_id, MessageId new_messag being_sent_messages_.erase(it); LOG(INFO) << "Save correspondence from " << new_message_id << " in " << dialog_id << " to " << old_message_id; + CHECK(old_message_id.is_yet_unsent()); update_message_ids_[FullMessageId(dialog_id, new_message_id)] = old_message_id; return true; } @@ -26985,6 +26995,7 @@ bool MessagesManager::on_update_scheduled_message_id(int64 random_id, ScheduledS being_sent_messages_.erase(it); LOG(INFO) << "Save correspondence from " << new_message_id << " in " << dialog_id << " to " << old_message_id; + CHECK(old_message_id.is_yet_unsent()); update_scheduled_message_ids_[dialog_id][new_message_id] = old_message_id; return true; } @@ -28771,10 +28782,7 @@ FullMessageId MessagesManager::on_send_message_success(int64 random_id, MessageI being_readded_message_id_ = {dialog_id, old_message_id}; unique_ptr sent_message = delete_message(d, old_message_id, false, &need_update_dialog_pos, source); if (sent_message == nullptr) { - // message has already been deleted by the user or sent to inaccessible channel - // don't need to send update to the user, because the message has already been deleted - LOG(INFO) << "Delete already deleted sent " << new_message_id << " from server"; - delete_message_from_server(dialog_id, new_message_id, true); + delete_sent_message_from_server(dialog_id, new_message_id); being_readded_message_id_ = FullMessageId(); return {}; } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 8aacc9571..03dd95dc1 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1906,7 +1906,7 @@ class MessagesManager : public Actor { void do_delete_all_dialog_messages(Dialog *d, unique_ptr &message, bool is_permanently_deleted, vector &deleted_message_ids); - void delete_message_from_server(DialogId dialog_id, MessageId message_ids, bool revoke); + void delete_sent_message_from_server(DialogId dialog_id, MessageId message_id); void delete_messages_from_server(DialogId dialog_id, vector message_ids, bool revoke, uint64 log_event_id, Promise &&promise); From 2246b81d6f1a0f67462d10e740ef6d338e8a7c04 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 4 Apr 2021 23:17:01 +0300 Subject: [PATCH 190/281] Immediately delete already deleted sent message instead of storing updateMessageID. --- td/telegram/MessagesManager.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 8fb41cb58..79157d970 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -10439,11 +10439,11 @@ void MessagesManager::delete_messages(DialogId dialog_id, const vector deleted_message_ids; for (auto message_id : message_ids) { - need_update_chat_has_scheduled_messages |= message_id.is_scheduled(); auto m = delete_message(d, message_id, true, &need_update_dialog_pos, DELETE_MESSAGE_USER_REQUEST_SOURCE); if (m == nullptr) { LOG(INFO) << "Can't delete " << message_id << " because it is not found"; } else { + need_update_chat_has_scheduled_messages |= m->message_id.is_scheduled(); deleted_message_ids.push_back(m->message_id.get()); } } @@ -10467,7 +10467,9 @@ void MessagesManager::delete_sent_message_from_server(DialogId dialog_id, Messag } LOG(INFO) << "Delete already deleted sent " << message_id << " in " << dialog_id << " from server"; - if (have_message_force({dialog_id, message_id}, "delete_sent_message_from_server")) { + Dialog *d = get_dialog(dialog_id); + CHECK(d != nullptr); + if (get_message(d, message_id) != nullptr) { delete_messages(dialog_id, {message_id}, true, Auto()); } else { if (message_id.is_valid()) { @@ -10477,6 +10479,11 @@ void MessagesManager::delete_sent_message_from_server(DialogId dialog_id, Messag CHECK(message_id.is_scheduled_server()); delete_scheduled_messages_from_server(dialog_id, {message_id}, 0, Auto()); } + + bool need_update_dialog_pos = false; + auto m = delete_message(d, message_id, true, &need_update_dialog_pos, "delete_sent_message_from_server"); + CHECK(m == nullptr); + CHECK(need_update_dialog_pos == false); } } @@ -26969,6 +26976,11 @@ bool MessagesManager::on_update_message_id(int64 random_id, MessageId new_messag being_sent_messages_.erase(it); + if (!have_message_force({dialog_id, old_message_id}, "on_update_message_id")) { + delete_sent_message_from_server(dialog_id, new_message_id); + return true; + } + LOG(INFO) << "Save correspondence from " << new_message_id << " in " << dialog_id << " to " << old_message_id; CHECK(old_message_id.is_yet_unsent()); update_message_ids_[FullMessageId(dialog_id, new_message_id)] = old_message_id; @@ -26994,6 +27006,11 @@ bool MessagesManager::on_update_scheduled_message_id(int64 random_id, ScheduledS being_sent_messages_.erase(it); + if (!have_message_force({dialog_id, old_message_id}, "on_update_scheduled_message_id")) { + delete_sent_message_from_server(dialog_id, MessageId(new_message_id, std::numeric_limits::max())); + return true; + } + LOG(INFO) << "Save correspondence from " << new_message_id << " in " << dialog_id << " to " << old_message_id; CHECK(old_message_id.is_yet_unsent()); update_scheduled_message_ids_[dialog_id][new_message_id] = old_message_id; From d3030445c5bd5b625ced1b173c1a615fd3ce6354 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 4 Apr 2021 23:31:08 +0300 Subject: [PATCH 191/281] Improve logging. --- td/telegram/MessagesManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 79157d970..46f3c5d18 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -33081,7 +33081,9 @@ void MessagesManager::delete_message_from_database(Dialog *d, MessageId message_ if (message_id.is_any_server()) { auto old_message_id = find_old_message_id(d->dialog_id, message_id); if (old_message_id.is_valid()) { - LOG(WARNING) << "Sent " << FullMessageId{d->dialog_id, message_id} << " was deleted before it was received"; + bool have_old_message = get_message(d, old_message_id) != nullptr; + LOG(WARNING) << "Sent " << FullMessageId{d->dialog_id, message_id} + << " was deleted before it was received. Have old message = " << have_old_message; send_closure_later(actor_id(this), &MessagesManager::delete_messages, d->dialog_id, vector{old_message_id}, false, Promise()); delete_update_message_id(d->dialog_id, message_id); From 02c9caafc0cb32d2c5f8659b8fc3a9a0dd31de90 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 4 Apr 2021 23:39:45 +0300 Subject: [PATCH 192/281] Fix FromApp building for UWP. --- tdutils/td/utils/port/FromApp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tdutils/td/utils/port/FromApp.h b/tdutils/td/utils/port/FromApp.h index 71cdfb9bb..db607b543 100644 --- a/tdutils/td/utils/port/FromApp.h +++ b/tdutils/td/utils/port/FromApp.h @@ -76,8 +76,8 @@ inline BOOL DeleteFileFromAppW(_In_ LPCWSTR lpFileName) { } inline BOOL MoveFileExFromAppW(_In_ LPCWSTR lpExistingFileName, _In_ LPCWSTR lpNewFileName, _In_ DWORD dwFlags) { - auto func = get_from_app_function<4>("MoveFileFromAppW", &MoveFile); - if (func == &MoveFile || (dwFlags & ~MOVEFILE_REPLACE_EXISTING) != 0) { + auto func = get_from_app_function<4>("MoveFileFromAppW", static_cast(nullptr)); + if (func == nullptr || (dwFlags & ~MOVEFILE_REPLACE_EXISTING) != 0) { // if can't find MoveFileFromAppW or have unsupported flags, call MoveFileEx directly return MoveFileEx(lpExistingFileName, lpNewFileName, dwFlags); } From 09859193b11e82ebb33e690b0f8ba55a7bb08476 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 5 Apr 2021 00:33:21 +0300 Subject: [PATCH 193/281] Add source to on_group_call_left_impl. --- td/telegram/GroupCallManager.cpp | 8 +++++--- td/telegram/GroupCallManager.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 3dfb6c8e3..5dc260c3b 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1577,7 +1577,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup bool need_update = set_group_call_participant_count(group_call, group_call->participant_count + diff, "process_pending_group_call_participant_updates"); if (is_left && group_call->is_joined) { - on_group_call_left_impl(group_call, need_rejoin); + on_group_call_left_impl(group_call, need_rejoin, "process_pending_group_call_participant_updates"); need_update = true; } if (need_update) { @@ -3179,13 +3179,15 @@ void GroupCallManager::on_group_call_left(InputGroupCallId input_group_call_id, auto *group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); if (group_call->is_joined && group_call->audio_source == audio_source) { - on_group_call_left_impl(group_call, need_rejoin); + on_group_call_left_impl(group_call, need_rejoin, "on_group_call_left"); send_update_group_call(group_call, "on_group_call_left"); } } -void GroupCallManager::on_group_call_left_impl(GroupCall *group_call, bool need_rejoin) { +void GroupCallManager::on_group_call_left_impl(GroupCall *group_call, bool need_rejoin, const char *source) { CHECK(group_call != nullptr && group_call->is_inited && group_call->is_joined); + LOG(INFO) << "Leave " << group_call->group_call_id << " in " << group_call->dialog_id + << " with need_rejoin = " << need_rejoin << " from " << source; group_call->is_joined = false; group_call->need_rejoin = need_rejoin && !group_call->is_being_left; if (group_call->need_rejoin && group_call->dialog_id.is_valid()) { diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 9afad8059..1cb83828b 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -257,7 +257,7 @@ class GroupCallManager : public Actor { void on_group_call_left(InputGroupCallId input_group_call_id, int32 audio_source, bool need_rejoin); - void on_group_call_left_impl(GroupCall *group_call, bool need_rejoin); + void on_group_call_left_impl(GroupCall *group_call, bool need_rejoin, const char *source); InputGroupCallId update_group_call(const tl_object_ptr &group_call_ptr, DialogId dialog_id); From 62a858807ae45dccbe1e1452d120cdbf4ecb7ded Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 5 Apr 2021 01:14:45 +0300 Subject: [PATCH 194/281] Drop loaded_all_participants if new user was added to the end of the list. --- td/telegram/GroupCallManager.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 5dc260c3b..7392e0955 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1521,6 +1521,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup } }; + bool need_update = false; while (!pending_version_updates.empty()) { process_mute_updates(); @@ -1532,7 +1533,12 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup auto &participant = participant_it.second; on_participant_speaking_in_group_call(input_group_call_id, participant); if (participant.is_self || participant.joined_date != 0) { - diff += process_group_call_participant(input_group_call_id, std::move(participant)); + auto cur_diff = process_group_call_participant(input_group_call_id, std::move(participant)); + if (cur_diff > 0 && group_call->loaded_all_participants && group_call->joined_date_asc) { + group_call->loaded_all_participants = false; + need_update = true; + } + diff += cur_diff; } } LOG(INFO) << "Ignore already applied updateGroupCallParticipants with version " << version << " in " @@ -1552,7 +1558,12 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup need_rejoin = false; } } - diff += process_group_call_participant(input_group_call_id, std::move(participant)); + auto cur_diff = process_group_call_participant(input_group_call_id, std::move(participant)); + if (cur_diff > 0 && group_call->loaded_all_participants && group_call->joined_date_asc) { + group_call->loaded_all_participants = false; + need_update = true; + } + diff += cur_diff; } pending_version_updates.erase(it); } else if (!group_call->syncing_participants) { @@ -1574,8 +1585,8 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup sync_participants_timeout_.cancel_timeout(group_call->group_call_id.get()); } - bool need_update = set_group_call_participant_count(group_call, group_call->participant_count + diff, - "process_pending_group_call_participant_updates"); + need_update |= set_group_call_participant_count(group_call, group_call->participant_count + diff, + "process_pending_group_call_participant_updates"); if (is_left && group_call->is_joined) { on_group_call_left_impl(group_call, need_rejoin, "process_pending_group_call_participant_updates"); need_update = true; @@ -3659,6 +3670,7 @@ bool GroupCallManager::set_group_call_participant_count(GroupCall *group_call, i count = 0; } + bool result = false; auto input_group_call_id = get_input_group_call_id(group_call->group_call_id).ok(); if (need_group_call_participants(input_group_call_id, group_call)) { auto known_participant_count = @@ -3671,12 +3683,17 @@ bool GroupCallManager::set_group_call_participant_count(GroupCall *group_call, i } count = known_participant_count; } else if (group_call->loaded_all_participants && count > known_participant_count) { - count = known_participant_count; + if (group_call->joined_date_asc) { + group_call->loaded_all_participants = false; + result = true; + } else { + count = known_participant_count; + } } } if (group_call->participant_count == count) { - return false; + return result; } group_call->participant_count = count; From 9aef50a2eedc3972f329d00c2cd8613b4ba31243 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 5 Apr 2021 01:19:08 +0300 Subject: [PATCH 195/281] Fix GroupCallParticipantOrder::get_group_call_participant_order_object. --- td/telegram/GroupCallParticipantOrder.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/td/telegram/GroupCallParticipantOrder.cpp b/td/telegram/GroupCallParticipantOrder.cpp index 08486c441..6809d16d3 100644 --- a/td/telegram/GroupCallParticipantOrder.cpp +++ b/td/telegram/GroupCallParticipantOrder.cpp @@ -24,6 +24,9 @@ bool GroupCallParticipantOrder::is_valid() const { } string GroupCallParticipantOrder::get_group_call_participant_order_object() const { + if (!is_valid()) { + return string(); + } return PSTRING() << lpad0(to_string(active_date), 10) << lpad0(to_string(raise_hand_rating), 19) << lpad0(to_string(joined_date), 10); } From f51e7b54817d07d6324d9235925dd65c95bacc13 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 5 Apr 2021 01:52:20 +0300 Subject: [PATCH 196/281] Fix handling of group call participant list with one participant. --- td/telegram/GroupCallManager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 7392e0955..69a69b5cd 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1654,7 +1654,9 @@ GroupCallParticipantOrder GroupCallManager::get_real_participant_order( void GroupCallManager::process_group_call_participants( InputGroupCallId input_group_call_id, vector> &&participants, int32 version, const string &offset, bool is_load, bool is_sync) { - if (offset.empty() && is_load && !participants.empty() && participants[0]->self_) { + // if receive exactly one participant, then the current user is the only participant + // there are no reasons to process it independently + if (offset.empty() && is_load && participants.size() >= 2 && participants[0]->self_) { GroupCallParticipant participant(participants[0], version); if (participant.is_valid()) { process_my_group_call_participant(input_group_call_id, std::move(participant)); @@ -3137,6 +3139,10 @@ void GroupCallManager::load_group_call_participants(GroupCallId group_call_id, i CHECK(participants_it->second != nullptr); next_offset = participants_it->second->next_offset; } + if (limit == 1 && next_offset.empty()) { + // prevent removing self as the first user and deducing that there are no more participants + limit = 2; + } td_->create_handler(std::move(promise)) ->send(input_group_call_id, std::move(next_offset), limit); } From 514777aaf191da32b2b724532cbf9667b9aabeea Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 5 Apr 2021 02:27:13 +0300 Subject: [PATCH 197/281] Fix infinite updates processing. --- td/telegram/GroupCallManager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 69a69b5cd..facbfdb90 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1566,11 +1566,13 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup diff += cur_diff; } pending_version_updates.erase(it); - } else if (!group_call->syncing_participants) { + } else { // found a gap - LOG(INFO) << "Receive " << participants.size() << " group call participant updates with version " << version - << ", but current version is " << group_call->version; - sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(), 1.0); + if (!group_call->syncing_participants) { + LOG(INFO) << "Receive " << participants.size() << " group call participant updates with version " << version + << ", but current version is " << group_call->version; + sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(), 1.0); + } break; } } From c4eb613a7a37a3c7d99cb39da4efbd14955ff94f Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 5 Apr 2021 03:02:52 +0300 Subject: [PATCH 198/281] Always include self to participant count in joined calls. --- td/telegram/GroupCallManager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index facbfdb90..3132e326c 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1300,6 +1300,9 @@ void GroupCallManager::on_get_group_call_participants( } auto real_participant_count = participants->count_; + if (!group_call->is_joined) { + real_participant_count++; + } if (is_empty) { auto known_participant_count = participants_it != group_call_participants_.end() ? static_cast(participants_it->second->participants.size()) @@ -3361,6 +3364,10 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrdialog_id.is_valid()) { group_call->dialog_id = dialog_id; } + if (call.is_active && join_params.empty() && !group_call->is_joined && + (group_call->need_rejoin || is_group_call_being_joined(input_group_call_id))) { + call.participant_count++; + } LOG(INFO) << "Update " << call.group_call_id << " with " << group_call->participant_count << " participants and version " << group_call->version; if (!group_call->is_inited) { From 70e15f4707d19a96bb79242c8f6be1b16ac5875f Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Mon, 5 Apr 2021 16:42:23 +0200 Subject: [PATCH 199/281] Update MessagesManager --- td/telegram/MessagesManager.cpp | 44 ++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index dbba87a29..916947ec7 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -6927,11 +6927,17 @@ void MessagesManager::on_update_channel_too_long(tl_object_ptr d->pts) { - get_channel_difference(dialog_id, d->pts, true, "on_update_channel_too_long 1"); + auto enable_pull_based_backpressure + = G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false); + get_channel_difference_delayed(dialog_id, d->pts, true, enable_pull_based_backpressure, + "on_update_channel_too_long 1"); } } else { if (force_apply) { - get_channel_difference(dialog_id, -1, true, "on_update_channel_too_long 2"); + auto enable_pull_based_backpressure + = G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false); + get_channel_difference_delayed(dialog_id, -1, true, enable_pull_based_backpressure, + "on_update_channel_too_long 2"); } else { td_->updates_manager_->schedule_get_difference("on_update_channel_too_long 3"); } @@ -7006,7 +7012,10 @@ void MessagesManager::update_message_interaction_info(FullMessageId full_message LOG(INFO) << "Ignore message interaction info about unknown " << full_message_id; if (!message_id.is_scheduled() && message_id > d->last_new_message_id && dialog_id.get_type() == DialogType::Channel) { - get_channel_difference(dialog_id, d->pts, true, "update_message_interaction_info"); + auto enable_pull_based_backpressure + = G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false); + get_channel_difference_delayed(dialog_id, d->pts, true, enable_pull_based_backpressure, + "update_message_interaction_info"); } return; } @@ -7578,7 +7587,9 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p << ", update is from " << source << ": " << oneline(to_string(update)); last_channel_pts_jump_warning_time_ = now; } - get_channel_difference(dialog_id, old_pts, true, "add_pending_channel_update old"); + auto enable_pull_based_backpressure + = G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false); + get_channel_difference_delayed(dialog_id, old_pts, true, enable_pull_based_backpressure, "old"); } if (update->get_id() == telegram_api::updateNewChannelMessage::ID) { @@ -7626,7 +7637,10 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p d->postponed_channel_updates.emplace(new_pts, PendingPtsUpdate(std::move(update), new_pts, pts_count, std::move(promise))); - get_channel_difference(dialog_id, old_pts, true, "add_pending_channel_update pts mismatch"); + auto enable_pull_based_backpressure + = G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false); + get_channel_difference_delayed(dialog_id, old_pts, true, enable_pull_based_backpressure, + "add_pending_channel_update pts mismatch"); return; } } @@ -11438,7 +11452,10 @@ void MessagesManager::read_channel_message_content_from_updates(Dialog *d, Messa if (m != nullptr) { read_message_content(d, m, false, "read_channel_message_content_from_updates"); } else if (message_id > d->last_new_message_id) { - get_channel_difference(d->dialog_id, d->pts, true, "read_channel_message_content_from_updates"); + auto enable_pull_based_backpressure + = G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false); + get_channel_difference_delayed(d->dialog_id, d->pts, true, enable_pull_based_backpressure, + "read_channel_message_content_from_updates"); } } @@ -29056,7 +29073,10 @@ void MessagesManager::check_send_message_result(int64 random_id, DialogId dialog return; } if (dialog_id.get_type() == DialogType::Channel) { - get_channel_difference(dialog_id, d->pts, true, "check_send_message_result"); + auto enable_pull_based_backpressure + = G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false); + get_channel_difference_delayed(dialog_id, d->pts, true, enable_pull_based_backpressure, + "check_send_message_result"); } else { td_->updates_manager_->schedule_get_difference("check_send_message_result"); } @@ -35768,7 +35788,10 @@ void MessagesManager::run_after_channel_difference(DialogId dialog_id, Promisepts, true, "run_after_channel_difference"); + auto enable_pull_based_backpressure + = G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false); + get_channel_difference_delayed(dialog_id, d->pts, true, enable_pull_based_backpressure, + "run_after_channel_difference"); } bool MessagesManager::running_get_channel_difference(DialogId dialog_id) const { @@ -35786,7 +35809,10 @@ void MessagesManager::on_channel_get_difference_timeout(DialogId dialog_id) { LOG(ERROR) << "Unknown dialog " << dialog_id; return; } - get_channel_difference(dialog_id, d->pts, true, "on_channel_get_difference_timeout"); + auto enable_pull_based_backpressure + = G()->shared_config().get_option_boolean("enable_pull_based_backpressure", false); + get_channel_difference_delayed(dialog_id, d->pts, true, enable_pull_based_backpressure, + "on_channel_get_difference_timeout"); } class MessagesManager::GetChannelDifferenceLogEvent { From a54be3de0d0b2f04764f9f3475e0b97f5e8a08bb Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 5 Apr 2021 21:26:14 +0300 Subject: [PATCH 200/281] Improve logging. --- td/telegram/MessagesManager.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 46f3c5d18..a227604e9 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -35379,7 +35379,8 @@ void MessagesManager::set_channel_pts(Dialog *d, int32 new_pts, const char *sour CHECK(d->dialog_id.get_type() == DialogType::Channel); LOG_IF(ERROR, running_get_channel_difference(d->dialog_id)) - << "Set pts of " << d->dialog_id << " to " << new_pts << " while running getChannelDifference"; + << "Set pts of " << d->dialog_id << " to " << new_pts << " from " << source + << " while running getChannelDifference"; if (is_debug_message_op_enabled()) { d->debug_message_op.emplace_back(Dialog::MessageOp::SetPts, new_pts, source); @@ -35387,7 +35388,7 @@ void MessagesManager::set_channel_pts(Dialog *d, int32 new_pts, const char *sour // TODO delete_first_messages support in channels if (new_pts == std::numeric_limits::max()) { - LOG(ERROR) << "Update " << d->dialog_id << " pts to -1"; + LOG(ERROR) << "Update " << d->dialog_id << " pts to -1 from " << source; G()->td_db()->get_binlog_pmc()->erase(get_channel_pts_key(d->dialog_id)); d->pts = std::numeric_limits::max(); if (d->pending_read_channel_inbox_pts != 0) { @@ -35397,9 +35398,10 @@ void MessagesManager::set_channel_pts(Dialog *d, int32 new_pts, const char *sour } if (new_pts > d->pts || (0 < new_pts && new_pts < d->pts - 99999)) { // pts can only go up or drop cardinally if (new_pts < d->pts - 99999) { - LOG(WARNING) << "Pts of " << d->dialog_id << " decreases from " << d->pts << " to " << new_pts; + LOG(WARNING) << "Pts of " << d->dialog_id << " decreases from " << d->pts << " to " << new_pts << " from " + << source; } else { - LOG(INFO) << "Update " << d->dialog_id << " pts to " << new_pts; + LOG(INFO) << "Update " << d->dialog_id << " pts to " << new_pts << " from " << source; } d->pts = new_pts; @@ -35418,7 +35420,8 @@ void MessagesManager::set_channel_pts(Dialog *d, int32 new_pts, const char *sour G()->td_db()->get_binlog_pmc()->set(get_channel_pts_key(d->dialog_id), to_string(new_pts)); } } else if (new_pts < d->pts) { - LOG(ERROR) << "Receive wrong pts " << new_pts << " in " << d->dialog_id << ". Current pts is " << d->pts; + LOG(ERROR) << "Receive wrong pts " << new_pts << " in " << d->dialog_id << " from " << source << ". Current pts is " + << d->pts; } } From 8b4410d2bfe4b8ba9b8398d8ac4300cec80a270a Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 5 Apr 2021 22:16:35 +0300 Subject: [PATCH 201/281] Improve group call participant logging. --- td/telegram/GroupCallManager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 3132e326c..046fa271e 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1653,6 +1653,10 @@ GroupCallParticipantOrder GroupCallManager::get_real_participant_order( if (participant.is_self) { return participants->min_order; } + if (real_order.is_valid()) { + LOG(DEBUG) << "Order " << real_order << " of " << participant.dialog_id << " is less than last known order " + << participants->min_order; + } return GroupCallParticipantOrder(); } @@ -1902,12 +1906,12 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou CHECK(!participant.is_min); int diff = participant.is_just_joined ? 1 : 0; + participant.order = get_real_participant_order(can_manage, participant, participants); if (participant.is_just_joined) { LOG(INFO) << "Add new " << participant; } else { LOG(INFO) << "Receive new " << participant; } - participant.order = get_real_participant_order(can_manage, participant, participants); participant.is_just_joined = false; update_group_call_participant_can_be_muted(can_manage, participants, participant); participants->participants.push_back(std::move(participant)); From 2c154f5e4a6bb3ca4495aa28780fe4e21c8d87ed Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 5 Apr 2021 22:39:38 +0300 Subject: [PATCH 202/281] Add source to send_update_group_call_participant. --- td/telegram/GroupCallManager.cpp | 51 +++++++++++++++++++------------- td/telegram/GroupCallManager.h | 7 +++-- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 046fa271e..005e9951e 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -751,7 +751,8 @@ void GroupCallManager::on_update_group_call_participant_order_timeout(GroupCallI auto new_order = get_real_participant_order(can_manage, participant, participants); if (new_order != participant.order) { participant.order = new_order; - send_update_group_call_participant(input_group_call_id, participant); + send_update_group_call_participant(input_group_call_id, participant, + "on_update_group_call_participant_order_timeout"); } } update_group_call_participant_order_timeout_.set_timeout_in(group_call_id.get(), @@ -1748,7 +1749,8 @@ void GroupCallManager::process_group_call_participants( if (participant.is_self) { if (participant.order != min_order) { participant.order = min_order; - send_update_group_call_participant(input_group_call_id, participant); + send_update_group_call_participant(input_group_call_id, participant, + "process_group_call_participants self"); } ++participant_it; continue; @@ -1758,7 +1760,7 @@ void GroupCallManager::process_group_call_participants( if (participant.order.is_valid()) { CHECK(participant.order >= participants_it->second->min_order); participant.order = GroupCallParticipantOrder(); - send_update_group_call_participant(input_group_call_id, participant); + send_update_group_call_participant(input_group_call_id, participant, "process_group_call_participants sync"); } on_remove_group_call_participant(input_group_call_id, participant.dialog_id); participant_it = group_participants.erase(participant_it); @@ -1782,7 +1784,8 @@ void GroupCallManager::process_group_call_participants( if (old_min_order > real_order && real_order >= min_order) { CHECK(!participant.order.is_valid() || participant.is_self); participant.order = real_order; - send_update_group_call_participant(input_group_call_id, participant); + send_update_group_call_participant(input_group_call_id, participant, + "process_group_call_participants load"); } } @@ -1811,7 +1814,8 @@ void GroupCallManager::update_group_call_participants_can_be_muted(InputGroupCal for (auto &participant : participants->participants) { if (update_group_call_participant_can_be_muted(can_manage, participants, participant) && participant.order.is_valid()) { - send_update_group_call_participant(input_group_call_id, participant); + send_update_group_call_participant(input_group_call_id, participant, + "update_group_call_participants_can_be_muted"); } } } @@ -1864,7 +1868,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (participant.joined_date == 0) { LOG(INFO) << "Remove " << old_participant; if (old_participant.order.is_valid()) { - send_update_group_call_participant(input_group_call_id, participant); + send_update_group_call_participant(input_group_call_id, participant, "process_group_call_participant remove"); } on_remove_group_call_participant(input_group_call_id, old_participant.dialog_id); remove_recent_group_call_speaker(input_group_call_id, old_participant.dialog_id); @@ -1890,7 +1894,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou LOG(INFO) << "Edit " << old_participant << " to " << participant; if (old_participant != participant && (old_participant.order.is_valid() || participant.order.is_valid())) { - send_update_group_call_participant(input_group_call_id, participant); + send_update_group_call_participant(input_group_call_id, participant, "process_group_call_participant edit"); } on_participant_speaking_in_group_call(input_group_call_id, participant); old_participant = std::move(participant); @@ -1916,7 +1920,8 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou update_group_call_participant_can_be_muted(can_manage, participants, participant); participants->participants.push_back(std::move(participant)); if (participants->participants.back().order.is_valid()) { - send_update_group_call_participant(input_group_call_id, participants->participants.back()); + send_update_group_call_participant(input_group_call_id, participants->participants.back(), + "process_group_call_participant add"); } on_add_group_call_participant(input_group_call_id, participants->participants.back().dialog_id); on_participant_speaking_in_group_call(input_group_call_id, participants->participants.back()); @@ -1954,7 +1959,7 @@ void GroupCallManager::on_update_dialog_about(DialogId dialog_id, const string & if ((from_server || participant->is_fake) && participant->about != about) { participant->about = about; if (participant->order.is_valid()) { - send_update_group_call_participant(input_group_call_id, *participant); + send_update_group_call_participant(input_group_call_id, *participant, "on_update_dialog_about"); } } } @@ -2897,7 +2902,7 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ participant->pending_is_muted_generation = ++toggle_is_muted_generation_; if (participant->order.is_valid()) { - send_update_group_call_participant(input_group_call_id, *participant); + send_update_group_call_participant(input_group_call_id, *participant, "toggle_group_call_participant_is_muted"); } auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, dialog_id, @@ -2937,7 +2942,8 @@ void GroupCallManager::on_toggle_group_call_participant_is_muted(InputGroupCallI participant->server_is_muted_locally != participant->pending_is_muted_locally) { LOG(ERROR) << "Failed to mute/unmute " << dialog_id << " in " << input_group_call_id; if (participant->order.is_valid()) { - send_update_group_call_participant(input_group_call_id, *participant); + send_update_group_call_participant(input_group_call_id, *participant, + "on_toggle_group_call_participant_is_muted"); } } promise.set_value(Unit()); @@ -2987,7 +2993,7 @@ void GroupCallManager::set_group_call_participant_volume_level(GroupCallId group participant->pending_volume_level = volume_level; participant->pending_volume_level_generation = ++set_volume_level_generation_; if (participant->order.is_valid()) { - send_update_group_call_participant(input_group_call_id, *participant); + send_update_group_call_participant(input_group_call_id, *participant, "set_group_call_participant_volume_level"); } auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, dialog_id, @@ -3025,7 +3031,8 @@ void GroupCallManager::on_set_group_call_participant_volume_level(InputGroupCall LOG(ERROR) << "Failed to set volume level of " << dialog_id << " in " << input_group_call_id; participant->pending_volume_level = 0; if (participant->order.is_valid()) { - send_update_group_call_participant(input_group_call_id, *participant); + send_update_group_call_participant(input_group_call_id, *participant, + "on_set_group_call_participant_volume_level"); } } else { participant->pending_volume_level = 0; @@ -3082,7 +3089,8 @@ void GroupCallManager::toggle_group_call_participant_is_hand_raised(GroupCallId participant->pending_is_hand_raised = is_hand_raised; participant->pending_is_hand_raised_generation = ++toggle_is_hand_raised_generation_; if (participant->order.is_valid()) { - send_update_group_call_participant(input_group_call_id, *participant); + send_update_group_call_participant(input_group_call_id, *participant, + "toggle_group_call_participant_is_hand_raised"); } auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, dialog_id, @@ -3120,7 +3128,8 @@ void GroupCallManager::on_toggle_group_call_participant_is_hand_raised(InputGrou if (participant->get_is_hand_raised() != participant->pending_is_hand_raised) { LOG(ERROR) << "Failed to change raised hand state for " << dialog_id << " in " << input_group_call_id; if (participant->order.is_valid()) { - send_update_group_call_participant(input_group_call_id, *participant); + send_update_group_call_participant(input_group_call_id, *participant, + "on_toggle_group_call_participant_is_hand_raised"); } } promise.set_value(Unit()); @@ -3291,7 +3300,7 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ if (participant.order.is_valid()) { CHECK(participant.order >= participants->min_order); participant.order = GroupCallParticipantOrder(); - send_update_group_call_participant(input_group_call_id, participant); + send_update_group_call_participant(input_group_call_id, participant, "try_clear_group_call_participants"); } on_remove_group_call_participant(input_group_call_id, participant.dialog_id); } @@ -3664,7 +3673,8 @@ DialogId GroupCallManager::set_group_call_participant_is_speaking_by_source(Inpu bool can_manage = can_manage_group_call(input_group_call_id); participant.order = get_real_participant_order(can_manage, participant, participants_it->second.get()); if (participant.order.is_valid()) { - send_update_group_call_participant(input_group_call_id, participant); + send_update_group_call_participant(input_group_call_id, participant, + "set_group_call_participant_is_speaking_by_source"); } } @@ -3819,15 +3829,16 @@ void GroupCallManager::send_update_group_call(const GroupCall *group_call, const } void GroupCallManager::send_update_group_call_participant(GroupCallId group_call_id, - const GroupCallParticipant &participant) { + const GroupCallParticipant &participant, const char *source) { + LOG(INFO) << "Send update about " << participant << " in " << group_call_id << " from " << source; send_closure(G()->td(), &Td::send_update, get_update_group_call_participant_object(group_call_id, participant)); } void GroupCallManager::send_update_group_call_participant(InputGroupCallId input_group_call_id, - const GroupCallParticipant &participant) { + const GroupCallParticipant &participant, const char *source) { auto group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); - send_update_group_call_participant(group_call->group_call_id, participant); + send_update_group_call_participant(group_call->group_call_id, participant, source); } } // namespace td diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 1cb83828b..e1cc7b0a1 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -297,10 +297,11 @@ class GroupCallManager : public Actor { void send_update_group_call(const GroupCall *group_call, const char *source); - void send_update_group_call_participant(GroupCallId group_call_id, const GroupCallParticipant &participant); + void send_update_group_call_participant(GroupCallId group_call_id, const GroupCallParticipant &participant, + const char *source); - void send_update_group_call_participant(InputGroupCallId input_group_call_id, - const GroupCallParticipant &participant); + void send_update_group_call_participant(InputGroupCallId input_group_call_id, const GroupCallParticipant &participant, + const char *source); Td *td_; ActorShared<> parent_; From 35d6145d664059c4251a2b286b956853ff112ede Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 5 Apr 2021 22:50:57 +0300 Subject: [PATCH 203/281] Drop loaded_all_participants if receive a group call participant in non-loaded part of the list. --- td/telegram/GroupCallManager.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 005e9951e..61502eabb 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1537,12 +1537,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup auto &participant = participant_it.second; on_participant_speaking_in_group_call(input_group_call_id, participant); if (participant.is_self || participant.joined_date != 0) { - auto cur_diff = process_group_call_participant(input_group_call_id, std::move(participant)); - if (cur_diff > 0 && group_call->loaded_all_participants && group_call->joined_date_asc) { - group_call->loaded_all_participants = false; - need_update = true; - } - diff += cur_diff; + diff += process_group_call_participant(input_group_call_id, std::move(participant)); } } LOG(INFO) << "Ignore already applied updateGroupCallParticipants with version " << version << " in " @@ -1562,12 +1557,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup need_rejoin = false; } } - auto cur_diff = process_group_call_participant(input_group_call_id, std::move(participant)); - if (cur_diff > 0 && group_call->loaded_all_participants && group_call->joined_date_asc) { - group_call->loaded_all_participants = false; - need_update = true; - } - diff += cur_diff; + diff += process_group_call_participant(input_group_call_id, std::move(participant)); } pending_version_updates.erase(it); } else { @@ -1855,7 +1845,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou auto can_self_unmute = !participant.get_is_muted_by_admin(); if (can_self_unmute != group_call->can_self_unmute) { group_call->can_self_unmute = can_self_unmute; - send_update_group_call(group_call, "process_group_call_participant"); + send_update_group_call(group_call, "process_group_call_participant 1"); } } } @@ -1922,6 +1912,13 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (participants->participants.back().order.is_valid()) { send_update_group_call_participant(input_group_call_id, participants->participants.back(), "process_group_call_participant add"); + } else { + auto *group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr && group_call->is_inited); + if (group_call->loaded_all_participants) { + group_call->loaded_all_participants = false; + send_update_group_call(group_call, "process_group_call_participant 2"); + } } on_add_group_call_participant(input_group_call_id, participants->participants.back().dialog_id); on_participant_speaking_in_group_call(input_group_call_id, participants->participants.back()); From bb1b82731e67009d0bc21f3793eccf92da688028 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 6 Apr 2021 00:24:05 +0300 Subject: [PATCH 204/281] Add messageVoiceChatScheduled. --- td/generate/scheme/td_api.tl | 3 +++ td/telegram/MessageContent.cpp | 39 ++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index d68e1866b..2503d001d 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -1683,6 +1683,9 @@ messageInvoice title:string description:string photo:photo currency:string total //@description A message with information about an ended call @is_video True, if the call was a video call @discard_reason Reason why the call was discarded @duration Call duration, in seconds messageCall is_video:Bool discard_reason:CallDiscardReason duration:int32 = MessageContent; +//@description A new voice chat was scheduled @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall @start_date Point in time (Unix timestamp) when the group call will be started +messageVoiceChatScheduled group_call_id:int32 start_date:int32 = MessageContent; + //@description A newly created voice chat @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall messageVoiceChatStarted group_call_id:int32 = MessageContent; diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index eb8b748b7..d8aa2cada 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -438,7 +438,7 @@ class MessageChatSetTtl : public MessageContent { class MessageUnsupported : public MessageContent { public: - static constexpr int32 CURRENT_VERSION = 6; + static constexpr int32 CURRENT_VERSION = 7; int32 version = CURRENT_VERSION; MessageUnsupported() = default; @@ -695,10 +695,11 @@ class MessageGroupCall : public MessageContent { public: InputGroupCallId input_group_call_id; int32 duration = -1; + int32 schedule_date = -1; MessageGroupCall() = default; - MessageGroupCall(InputGroupCallId input_group_call_id, int32 duration) - : input_group_call_id(input_group_call_id), duration(duration) { + MessageGroupCall(InputGroupCallId input_group_call_id, int32 duration, int32 schedule_date) + : input_group_call_id(input_group_call_id), duration(duration), schedule_date(schedule_date) { } MessageContentType get_type() const override { @@ -994,13 +995,18 @@ static void store(const MessageContent *content, StorerT &storer) { case MessageContentType::GroupCall: { auto m = static_cast(content); bool has_duration = m->duration >= 0; + bool has_schedule_date = m->schedule_date > 0; BEGIN_STORE_FLAGS(); STORE_FLAG(has_duration); + STORE_FLAG(has_schedule_date); END_STORE_FLAGS(); store(m->input_group_call_id, storer); if (has_duration) { store(m->duration, storer); } + if (has_schedule_date) { + store(m->schedule_date, storer); + } break; } case MessageContentType::InviteToGroupCall: { @@ -1393,13 +1399,18 @@ static void parse(unique_ptr &content, ParserT &parser) { case MessageContentType::GroupCall: { auto m = make_unique(); bool has_duration; + bool has_schedule_date; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_duration); + PARSE_FLAG(has_schedule_date); END_PARSE_FLAGS(); parse(m->input_group_call_id, parser); if (has_duration) { parse(m->duration, parser); } + if (has_schedule_date) { + parse(m->schedule_date, parser); + } content = std::move(m); break; } @@ -3165,7 +3176,8 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo case MessageContentType::GroupCall: { auto old_ = static_cast(old_content); auto new_ = static_cast(new_content); - if (old_->input_group_call_id != new_->input_group_call_id || old_->duration != new_->duration) { + if (old_->input_group_call_id != new_->input_group_call_id || old_->duration != new_->duration || + old_->schedule_date != new_->schedule_date) { need_update = true; } if (!old_->input_group_call_id.is_identical(new_->input_group_call_id)) { @@ -4419,7 +4431,7 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptr(InputGroupCallId(group_call->call_), duration); + return make_unique(InputGroupCallId(group_call->call_), duration, -1); } case telegram_api::messageActionInviteToGroupCall::ID: { auto invite_to_group_call = move_tl_object_as(action); @@ -4444,11 +4456,16 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptrbot_id_); + if (!seller_bot_user_id.is_valid()) { + LOG(ERROR) << "Receive invalid seller " << seller_bot_user_id; + return on_error(id, Status::Error(500, "Receive invalid seller identifier")); + } + auto photo = get_web_document_photo(td->file_manager_.get(), std::move(payment_receipt->photo_), dialog_id_); promise_.set_value(make_tl_object( - payment_receipt->date_, td->contacts_manager_->get_user_id_object(payments_provider_user_id, "paymentReceipt"), + payment_receipt->title_, payment_receipt->description_, get_photo_object(td->file_manager_.get(), photo), + payment_receipt->date_, td->contacts_manager_->get_user_id_object(seller_bot_user_id, "paymentReceipt seller"), + td->contacts_manager_->get_user_id_object(payments_provider_user_id, "paymentReceipt provider"), convert_invoice(std::move(payment_receipt->invoice_)), convert_order_info(std::move(payment_receipt->info_)), - convert_shipping_option(std::move(payment_receipt->shipping_)), - std::move(payment_receipt->credentials_title_))); + convert_shipping_option(std::move(payment_receipt->shipping_)), std::move(payment_receipt->credentials_title_), + payment_receipt->tip_amount_)); } void on_error(uint64 id, Status status) override { From b9faeb92d05a326fc87845028ac1d67947365743 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 6 Apr 2021 01:16:57 +0300 Subject: [PATCH 207/281] Add seller and provider IDs to td_api::paymentForm. --- td/generate/scheme/td_api.tl | 15 ++++++++++++--- td/telegram/Payments.cpp | 12 ++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index b58017ffc..a5d716bf9 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -1349,9 +1349,18 @@ inputCredentialsGooglePay data:string = InputCredentials; //@description Stripe payment provider @publishable_key Stripe API publishable key @need_country True, if the user country must be provided @need_postal_code True, if the user ZIP/postal code must be provided @need_cardholder_name True, if the cardholder name must be provided paymentsProviderStripe publishable_key:string need_country:Bool need_postal_code:Bool need_cardholder_name:Bool = PaymentsProviderStripe; -//@description Contains information about an invoice payment form @id The payment form identifier @invoice Full information of the invoice @url Payment form URL @payments_provider Contains information about the payment provider, if available, to support it natively without the need for opening the URL; may be null -//@saved_order_info Saved server-side order information; may be null @saved_credentials Contains information about saved card credentials; may be null @can_save_credentials True, if the user can choose to save credentials @need_password True, if the user will be able to save credentials protected by a password they set up -paymentForm id:int64 invoice:invoice url:string payments_provider:paymentsProviderStripe saved_order_info:orderInfo saved_credentials:savedCredentials can_save_credentials:Bool need_password:Bool = PaymentForm; +//@description Contains information about an invoice payment form +//@id The payment form identifier +//@invoice Full information of the invoice +//@url Payment form URL +//@seller_bot_user_id User identifier of the seller bot +//@payments_provider_user_id User identifier of the payment provider bot +//@payments_provider Contains information about the payment provider, if available, to support it natively without the need for opening the URL; may be null +//@saved_order_info Saved server-side order information; may be null +//@saved_credentials Contains information about saved card credentials; may be null +//@can_save_credentials True, if the user can choose to save credentials +//@need_password True, if the user will be able to save credentials protected by a password they set up +paymentForm id:int64 invoice:invoice url:string seller_bot_user_id:int32 payments_provider_user_id:int32 payments_provider:paymentsProviderStripe saved_order_info:orderInfo saved_credentials:savedCredentials can_save_credentials:Bool need_password:Bool = PaymentForm; //@description Contains a temporary identifier of validated order information, which is stored for one hour. Also contains the available shipping options @order_info_id Temporary identifier of the order information @shipping_options Available shipping options validatedOrderInfo order_info_id:string shipping_options:vector = ValidatedOrderInfo; diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index b74c0b61a..a9ff2085a 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -289,11 +289,23 @@ class GetPaymentFormQuery : public Td::ResultHandler { td->contacts_manager_->on_get_users(std::move(payment_form->users_), "GetPaymentFormQuery"); + UserId payments_provider_user_id(payment_form->provider_id_); + if (!payments_provider_user_id.is_valid()) { + LOG(ERROR) << "Receive invalid payments provider " << payments_provider_user_id; + return on_error(id, Status::Error(500, "Receive invalid payments provider identifier")); + } + UserId seller_bot_user_id(payment_form->bot_id_); + if (!seller_bot_user_id.is_valid()) { + LOG(ERROR) << "Receive invalid seller " << seller_bot_user_id; + return on_error(id, Status::Error(500, "Receive invalid seller identifier")); + } bool can_save_credentials = (payment_form->flags_ & telegram_api::payments_paymentForm::CAN_SAVE_CREDENTIALS_MASK) != 0; bool need_password = (payment_form->flags_ & telegram_api::payments_paymentForm::PASSWORD_MISSING_MASK) != 0; promise_.set_value(make_tl_object( payment_form->form_id_, convert_invoice(std::move(payment_form->invoice_)), std::move(payment_form->url_), + td->contacts_manager_->get_user_id_object(seller_bot_user_id, "paymentForm seller"), + td->contacts_manager_->get_user_id_object(payments_provider_user_id, "paymentForm provider"), convert_payment_provider(payment_form->native_provider_, std::move(payment_form->native_params_)), convert_order_info(std::move(payment_form->saved_info_)), convert_saved_credentials(std::move(payment_form->saved_credentials_)), can_save_credentials, need_password)); From c171c9a743bb79a8836567610828618db6d586ac Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 6 Apr 2021 01:19:30 +0300 Subject: [PATCH 208/281] Improve fatal error message. --- tddb/td/db/SqliteKeyValue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tddb/td/db/SqliteKeyValue.cpp b/tddb/td/db/SqliteKeyValue.cpp index fe9e4d882..c51325b2d 100644 --- a/tddb/td/db/SqliteKeyValue.cpp +++ b/tddb/td/db/SqliteKeyValue.cpp @@ -66,7 +66,7 @@ SqliteKeyValue::SeqNo SqliteKeyValue::set(Slice key, Slice value) { set_stmt_.bind_blob(2, value).ensure(); auto status = set_stmt_.step(); if (status.is_error()) { - LOG(FATAL) << "Failed to set \"" << key << '"'; + LOG(FATAL) << "Failed to set \"" << key << "\": " << status.error(); } // set_stmt_.step().ensure(); set_stmt_.reset(); From 47066bbffb2200ee35c54b216804673d9005bc7b Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 6 Apr 2021 01:48:41 +0300 Subject: [PATCH 209/281] Take into account raised hands when sorting group call participants for non-muted users. --- td/telegram/GroupCallManager.cpp | 31 +++++++++++++++++----------- td/telegram/GroupCallManager.h | 4 +++- td/telegram/GroupCallParticipant.cpp | 4 ++-- td/telegram/GroupCallParticipant.h | 2 +- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index d5f4857dd..1a225b038 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -746,10 +746,10 @@ void GroupCallManager::on_update_group_call_participant_order_timeout(GroupCallI return; } - bool can_manage = can_manage_group_call(input_group_call_id); + bool can_self_unmute = get_group_call_can_self_unmute(input_group_call_id); auto *participants = add_group_call_participants(input_group_call_id); for (auto &participant : participants->participants) { - auto new_order = get_real_participant_order(can_manage, participant, participants); + auto new_order = get_real_participant_order(can_self_unmute, participant, participants); if (new_order != participant.order) { participant.order = new_order; send_update_group_call_participant(input_group_call_id, participant, @@ -1009,6 +1009,12 @@ bool GroupCallManager::can_manage_group_call(InputGroupCallId input_group_call_i return can_manage_group_calls(group_call->dialog_id).is_ok(); } +bool GroupCallManager::get_group_call_can_self_unmute(InputGroupCallId input_group_call_id) const { + auto group_call = get_group_call(input_group_call_id); + CHECK(group_call != nullptr && group_call->is_inited); + return group_call->can_self_unmute; +} + bool GroupCallManager::get_group_call_joined_date_asc(InputGroupCallId input_group_call_id) const { auto group_call = get_group_call(input_group_call_id); CHECK(group_call != nullptr && group_call->is_inited); @@ -1107,7 +1113,6 @@ void GroupCallManager::on_update_group_call_rights(InputGroupCallId input_group_ } reload_group_call(input_group_call_id, Auto()); - sync_group_call_participants(input_group_call_id); // participant order is different for administrators } void GroupCallManager::reload_group_call(InputGroupCallId input_group_call_id, @@ -1637,8 +1642,8 @@ void GroupCallManager::on_sync_group_call_participants_failed(InputGroupCallId i } GroupCallParticipantOrder GroupCallManager::get_real_participant_order( - bool can_manage, const GroupCallParticipant &participant, const GroupCallParticipants *participants) const { - auto real_order = participant.get_real_order(can_manage, participants->joined_date_asc, false); + bool can_self_unmute, const GroupCallParticipant &participant, const GroupCallParticipants *participants) const { + auto real_order = participant.get_real_order(can_self_unmute, participants->joined_date_asc, false); if (real_order >= participants->min_order) { return real_order; } @@ -1693,7 +1698,7 @@ void GroupCallManager::process_group_call_participants( auto min_order = GroupCallParticipantOrder::max(); DialogId min_order_dialog_id; - bool can_manage = can_manage_group_call(input_group_call_id); + bool can_self_unmute = get_group_call_can_self_unmute(input_group_call_id); bool joined_date_asc = get_group_call_joined_date_asc(input_group_call_id); for (auto &group_call_participant : participants) { GroupCallParticipant participant(group_call_participant, version); @@ -1710,7 +1715,7 @@ void GroupCallManager::process_group_call_participants( } if (is_load) { - auto real_order = participant.get_real_order(can_manage, joined_date_asc, true); + auto real_order = participant.get_real_order(can_self_unmute, joined_date_asc, true); if (real_order > min_order) { LOG(ERROR) << "Receive call participant " << participant.dialog_id << " with order " << real_order << " after call participant " << min_order_dialog_id << " with order " << min_order; @@ -1770,7 +1775,7 @@ void GroupCallManager::process_group_call_participants( participants_it->second->min_order = min_order; for (auto &participant : participants_it->second->participants) { - auto real_order = get_real_participant_order(can_manage, participant, participants_it->second.get()); + auto real_order = get_real_participant_order(can_self_unmute, participant, participants_it->second.get()); if (old_min_order > real_order && real_order >= min_order) { CHECK(!participant.order.is_valid() || participant.is_self); participant.order = real_order; @@ -1845,10 +1850,12 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou if (can_self_unmute != group_call->can_self_unmute) { group_call->can_self_unmute = can_self_unmute; send_update_group_call(group_call, "process_group_call_participant 1"); + sync_group_call_participants(input_group_call_id); // participant order is different for administrators } } } + bool can_self_unmute = get_group_call_can_self_unmute(input_group_call_id); bool can_manage = can_manage_group_call(input_group_call_id); auto *participants = add_group_call_participants(input_group_call_id); for (size_t i = 0; i < participants->participants.size(); i++) { @@ -1878,7 +1885,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou participant.update_from(old_participant); participant.is_just_joined = false; - participant.order = get_real_participant_order(can_manage, participant, participants); + participant.order = get_real_participant_order(can_self_unmute, participant, participants); update_group_call_participant_can_be_muted(can_manage, participants, participant); LOG(INFO) << "Edit " << old_participant << " to " << participant; @@ -1899,7 +1906,7 @@ int GroupCallManager::process_group_call_participant(InputGroupCallId input_grou CHECK(!participant.is_min); int diff = participant.is_just_joined ? 1 : 0; - participant.order = get_real_participant_order(can_manage, participant, participants); + participant.order = get_real_participant_order(can_self_unmute, participant, participants); if (participant.is_just_joined) { LOG(INFO) << "Add new " << participant; } else { @@ -3668,8 +3675,8 @@ DialogId GroupCallManager::set_group_call_participant_is_speaking_by_source(Inpu if (is_speaking) { participant.local_active_date = max(participant.local_active_date, date); } - bool can_manage = can_manage_group_call(input_group_call_id); - participant.order = get_real_participant_order(can_manage, participant, participants_it->second.get()); + bool can_self_unmute = get_group_call_can_self_unmute(input_group_call_id); + participant.order = get_real_participant_order(can_self_unmute, participant, participants_it->second.get()); if (participant.order.is_valid()) { send_update_group_call_participant(input_group_call_id, participant, "set_group_call_participant_is_speaking_by_source"); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index e1cc7b0a1..f0dd222fa 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -160,6 +160,8 @@ class GroupCallManager : public Actor { bool can_manage_group_call(InputGroupCallId input_group_call_id) const; + bool get_group_call_can_self_unmute(InputGroupCallId input_group_call_id) const; + bool get_group_call_joined_date_asc(InputGroupCallId input_group_call_id) const; void on_voice_chat_created(DialogId dialog_id, InputGroupCallId input_group_call_id, Promise &&promise); @@ -191,7 +193,7 @@ class GroupCallManager : public Actor { void on_sync_group_call_participants_failed(InputGroupCallId input_group_call_id); - GroupCallParticipantOrder get_real_participant_order(bool can_manage, const GroupCallParticipant &participant, + GroupCallParticipantOrder get_real_participant_order(bool can_self_unmute, const GroupCallParticipant &participant, const GroupCallParticipants *participants) const; void process_my_group_call_participant(InputGroupCallId input_group_call_id, GroupCallParticipant &&participant); diff --git a/td/telegram/GroupCallParticipant.cpp b/td/telegram/GroupCallParticipant.cpp index 8a339deac..05fd7b276 100644 --- a/td/telegram/GroupCallParticipant.cpp +++ b/td/telegram/GroupCallParticipant.cpp @@ -62,13 +62,13 @@ bool GroupCallParticipant::is_versioned_update(const tl_object_ptrjust_joined_ || participant->left_ || participant->versioned_; } -GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_manage, bool joined_date_asc, +GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_self_unmute, bool joined_date_asc, bool keep_active_date) const { auto sort_active_date = td::max(active_date, local_active_date); if (!keep_active_date && sort_active_date < G()->unix_time() - 300) { sort_active_date = 0; } - auto sort_raise_hand_rating = can_manage ? raise_hand_rating : 0; + auto sort_raise_hand_rating = can_self_unmute ? raise_hand_rating : 0; auto sort_joined_date = joined_date_asc ? std::numeric_limits::max() - joined_date : joined_date; return GroupCallParticipantOrder(sort_active_date, sort_raise_hand_rating, sort_joined_date); } diff --git a/td/telegram/GroupCallParticipant.h b/td/telegram/GroupCallParticipant.h index 7044ddee9..cbd5d65c3 100644 --- a/td/telegram/GroupCallParticipant.h +++ b/td/telegram/GroupCallParticipant.h @@ -73,7 +73,7 @@ struct GroupCallParticipant { bool set_pending_is_muted(bool is_muted, bool can_manage, bool is_admin); - GroupCallParticipantOrder get_real_order(bool can_manage, bool joined_date_asc, bool keep_active_date) const; + GroupCallParticipantOrder get_real_order(bool can_self_unmute, bool joined_date_asc, bool keep_active_date) const; bool is_valid() const { return dialog_id.is_valid(); From 02fe7e47e66be74696f89adaca8dd033860543b6 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 6 Apr 2021 02:13:57 +0300 Subject: [PATCH 210/281] Allow to specify title of created voice chats. --- td/generate/scheme/td_api.tl | 5 +++-- td/telegram/GroupCallManager.cpp | 13 +++++++++---- td/telegram/GroupCallManager.h | 2 +- td/telegram/Td.cpp | 6 ++++-- td/telegram/Td.h | 2 +- td/telegram/cli.cpp | 5 ++++- 6 files changed, 22 insertions(+), 11 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index a5d716bf9..1afa2fab0 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4600,8 +4600,9 @@ sendCallDebugInformation call_id:int32 debug_information:string = Ok; //@description Returns list of user and chat, which can be used as aliases to join a voice chat in the chat @chat_id Chat identifier getAvailableVoiceChatAliases chat_id:int53 = MessageSenders; -//@description Creates a voice chat (a group call bound to a chat). Available only for basic groups, supergroups and channels; requires can_manage_voice_chats rights @chat_id Chat identifier -createVoiceChat chat_id:int53 = GroupCallId; +//@description Creates a voice chat (a group call bound to a chat). Available only for basic groups, supergroups and channels; requires can_manage_voice_chats rights +//@chat_id Chat identifier @title Group call title; if empty, chat title will be used +createVoiceChat chat_id:int53 title:string = GroupCallId; //@description Returns information about a group call @group_call_id Group call identifier getGroupCall group_call_id:int32 = GroupCall; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 1a225b038..482ee3307 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -131,15 +131,18 @@ class CreateGroupCallQuery : public Td::ResultHandler { explicit CreateGroupCallQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(DialogId dialog_id) { + void send(DialogId dialog_id, const string &title) { dialog_id_ = dialog_id; auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); CHECK(input_peer != nullptr); int32 flags = 0; + if (!title.empty()) { + flags |= telegram_api::phone_createGroupCall::TITLE_MASK; + } send_query(G()->net_query_creator().create( - telegram_api::phone_createGroupCall(flags, std::move(input_peer), Random::secure_int32(), string(), 0))); + telegram_api::phone_createGroupCall(flags, std::move(input_peer), Random::secure_int32(), title, 0))); } void on_result(uint64 id, BufferSlice packet) override { @@ -1036,7 +1039,7 @@ void GroupCallManager::get_group_call_join_as(DialogId dialog_id, td_->create_handler(std::move(promise))->send(dialog_id); } -void GroupCallManager::create_voice_chat(DialogId dialog_id, Promise &&promise) { +void GroupCallManager::create_voice_chat(DialogId dialog_id, string title, Promise &&promise) { if (!dialog_id.is_valid()) { return promise.set_error(Status::Error(400, "Invalid chat identifier specified")); } @@ -1049,6 +1052,8 @@ void GroupCallManager::create_voice_chat(DialogId dialog_id, Promise result) mutable { if (result.is_error()) { @@ -1058,7 +1063,7 @@ void GroupCallManager::create_voice_chat(DialogId dialog_id, Promisecreate_handler(std::move(query_promise))->send(dialog_id); + td_->create_handler(std::move(query_promise))->send(dialog_id, title); } void GroupCallManager::on_voice_chat_created(DialogId dialog_id, InputGroupCallId input_group_call_id, diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index f0dd222fa..13e27ff52 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -48,7 +48,7 @@ class GroupCallManager : public Actor { void get_group_call_join_as(DialogId dialog_id, Promise> &&promise); - void create_voice_chat(DialogId dialog_id, Promise &&promise); + void create_voice_chat(DialogId dialog_id, string title, Promise &&promise); void get_group_call(GroupCallId group_call_id, Promise> &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index ad703d2f3..cfceee249 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5974,8 +5974,9 @@ void Td::on_request(uint64 id, const td_api::getAvailableVoiceChatAliases &reque group_call_manager_->get_group_call_join_as(DialogId(request.chat_id_), std::move(promise)); } -void Td::on_request(uint64 id, const td_api::createVoiceChat &request) { +void Td::on_request(uint64 id, td_api::createVoiceChat &request) { CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.title_); CREATE_REQUEST_PROMISE(); auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result result) mutable { if (result.is_error()) { @@ -5984,7 +5985,8 @@ void Td::on_request(uint64 id, const td_api::createVoiceChat &request) { promise.set_value(td_api::make_object(result.ok().get())); } }); - group_call_manager_->create_voice_chat(DialogId(request.chat_id_), std::move(query_promise)); + group_call_manager_->create_voice_chat(DialogId(request.chat_id_), std::move(request.title_), + std::move(query_promise)); } void Td::on_request(uint64 id, const td_api::getGroupCall &request) { diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 8061c38bc..22aa4d61a 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -703,7 +703,7 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::getAvailableVoiceChatAliases &request); - void on_request(uint64 id, const td_api::createVoiceChat &request); + void on_request(uint64 id, td_api::createVoiceChat &request); void on_request(uint64 id, const td_api::getGroupCall &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 75f33b050..adcfb922c 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2673,7 +2673,10 @@ class CliClient final : public Actor { } else if (op == "gavca") { send_request(td_api::make_object(as_chat_id(args))); } else if (op == "cvc") { - send_request(td_api::make_object(as_chat_id(args))); + string chat_id; + string title; + get_args(args, chat_id, title); + send_request(td_api::make_object(as_chat_id(chat_id), title)); } else if (op == "ggc") { send_request(td_api::make_object(as_group_call_id(args))); } else if (op == "ggcss") { From 2241058f852ddd593800bc22839cbc481c033ea3 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 6 Apr 2021 02:54:55 +0300 Subject: [PATCH 211/281] Allow to create scheduled voice chats. --- td/generate/scheme/td_api.tl | 6 ++++-- td/telegram/GroupCallManager.cpp | 12 ++++++++---- td/telegram/GroupCallManager.h | 2 +- td/telegram/Td.cpp | 2 +- td/telegram/cli.cpp | 5 +++-- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 1afa2fab0..3bd6f83ad 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4601,8 +4601,10 @@ sendCallDebugInformation call_id:int32 debug_information:string = Ok; getAvailableVoiceChatAliases chat_id:int53 = MessageSenders; //@description Creates a voice chat (a group call bound to a chat). Available only for basic groups, supergroups and channels; requires can_manage_voice_chats rights -//@chat_id Chat identifier @title Group call title; if empty, chat title will be used -createVoiceChat chat_id:int53 title:string = GroupCallId; +//@chat_id Chat identifier, in which the voice chat will be created +//@title Group call title; if empty, chat title will be used +//@start_date Point in time (Unix timestamp) when the group call will be started. Pass 0 to start the voice chat immediately +createVoiceChat chat_id:int53 title:string start_date:int32 = GroupCallId; //@description Returns information about a group call @group_call_id Group call identifier getGroupCall group_call_id:int32 = GroupCall; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 482ee3307..3d9d0f40a 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -131,7 +131,7 @@ class CreateGroupCallQuery : public Td::ResultHandler { explicit CreateGroupCallQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(DialogId dialog_id, const string &title) { + void send(DialogId dialog_id, const string &title, int32 start_date) { dialog_id_ = dialog_id; auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); @@ -141,8 +141,11 @@ class CreateGroupCallQuery : public Td::ResultHandler { if (!title.empty()) { flags |= telegram_api::phone_createGroupCall::TITLE_MASK; } + if (start_date > 0) { + flags |= telegram_api::phone_createGroupCall::SCHEDULE_DATE_MASK; + } send_query(G()->net_query_creator().create( - telegram_api::phone_createGroupCall(flags, std::move(input_peer), Random::secure_int32(), title, 0))); + telegram_api::phone_createGroupCall(flags, std::move(input_peer), Random::secure_int32(), title, start_date))); } void on_result(uint64 id, BufferSlice packet) override { @@ -1039,7 +1042,8 @@ void GroupCallManager::get_group_call_join_as(DialogId dialog_id, td_->create_handler(std::move(promise))->send(dialog_id); } -void GroupCallManager::create_voice_chat(DialogId dialog_id, string title, Promise &&promise) { +void GroupCallManager::create_voice_chat(DialogId dialog_id, string title, int32 start_date, + Promise &&promise) { if (!dialog_id.is_valid()) { return promise.set_error(Status::Error(400, "Invalid chat identifier specified")); } @@ -1063,7 +1067,7 @@ void GroupCallManager::create_voice_chat(DialogId dialog_id, string title, Promi std::move(promise)); } }); - td_->create_handler(std::move(query_promise))->send(dialog_id, title); + td_->create_handler(std::move(query_promise))->send(dialog_id, title, start_date); } void GroupCallManager::on_voice_chat_created(DialogId dialog_id, InputGroupCallId input_group_call_id, diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 13e27ff52..d4a751879 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -48,7 +48,7 @@ class GroupCallManager : public Actor { void get_group_call_join_as(DialogId dialog_id, Promise> &&promise); - void create_voice_chat(DialogId dialog_id, string title, Promise &&promise); + void create_voice_chat(DialogId dialog_id, string title, int32 start_date, Promise &&promise); void get_group_call(GroupCallId group_call_id, Promise> &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index cfceee249..0d8f846d1 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5985,7 +5985,7 @@ void Td::on_request(uint64 id, td_api::createVoiceChat &request) { promise.set_value(td_api::make_object(result.ok().get())); } }); - group_call_manager_->create_voice_chat(DialogId(request.chat_id_), std::move(request.title_), + group_call_manager_->create_voice_chat(DialogId(request.chat_id_), std::move(request.title_), request.start_date_, std::move(query_promise)); } diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index adcfb922c..5837c964d 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2675,8 +2675,9 @@ class CliClient final : public Actor { } else if (op == "cvc") { string chat_id; string title; - get_args(args, chat_id, title); - send_request(td_api::make_object(as_chat_id(chat_id), title)); + int32 start_date; + get_args(args, chat_id, title, start_date); + send_request(td_api::make_object(as_chat_id(chat_id), title, start_date)); } else if (op == "ggc") { send_request(td_api::make_object(as_group_call_id(args))); } else if (op == "ggcss") { From 49fecf40e6756799a41a9eb38bc420943c7a7d44 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 6 Apr 2021 12:08:47 +0300 Subject: [PATCH 212/281] Add groupCall.scheduled_start_date. --- td/generate/scheme/td_api.tl | 7 ++++--- td/telegram/GroupCallManager.cpp | 22 +++++++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 3bd6f83ad..397630e56 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -1702,7 +1702,7 @@ messageInvoice title:string description:string photo:photo currency:string total //@description A message with information about an ended call @is_video True, if the call was a video call @discard_reason Reason why the call was discarded @duration Call duration, in seconds messageCall is_video:Bool discard_reason:CallDiscardReason duration:int32 = MessageContent; -//@description A new voice chat was scheduled @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall @start_date Point in time (Unix timestamp) when the group call will be started +//@description A new voice chat was scheduled @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall @start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator messageVoiceChatScheduled group_call_id:int32 start_date:int32 = MessageContent; //@description A newly created voice chat @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall @@ -2144,6 +2144,7 @@ groupCallRecentSpeaker speaker:MessageSender is_speaking:Bool = GroupCallRecentS //@description Describes a group call //@id Group call identifier //@title Group call title +//@scheduled_start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator; 0 if it is already active or was ended //@is_active True, if the call is active //@is_joined True, if the call is joined //@need_rejoin True, if user was kicked from the call because of network loss and the call needs to be rejoined @@ -2156,7 +2157,7 @@ groupCallRecentSpeaker speaker:MessageSender is_speaking:Bool = GroupCallRecentS //@can_change_mute_new_participants True, if the current user can enable or disable mute_new_participants setting //@record_duration Duration of the ongoing group call recording, in seconds; 0 if none. An updateGroupCall update is not triggered when value of this field changes, but the same recording goes on //@duration Call duration; for ended calls only -groupCall id:int32 title:string is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector mute_new_participants:Bool can_change_mute_new_participants:Bool record_duration:int32 duration:int32 = GroupCall; +groupCall id:int32 title:string scheduled_start_date:int32 is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector mute_new_participants:Bool can_change_mute_new_participants:Bool record_duration:int32 duration:int32 = GroupCall; //@description Describes a payload fingerprint for interaction with tgcalls @hash Value of the field hash @setup Value of the field setup @fingerprint Value of the field fingerprint groupCallPayloadFingerprint hash:string setup:string fingerprint:string = GroupCallPayloadFingerprint; @@ -4603,7 +4604,7 @@ getAvailableVoiceChatAliases chat_id:int53 = MessageSenders; //@description Creates a voice chat (a group call bound to a chat). Available only for basic groups, supergroups and channels; requires can_manage_voice_chats rights //@chat_id Chat identifier, in which the voice chat will be created //@title Group call title; if empty, chat title will be used -//@start_date Point in time (Unix timestamp) when the group call will be started. Pass 0 to start the voice chat immediately +//@start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator. Pass 0 to start the voice chat immediately createVoiceChat chat_id:int53 title:string start_date:int32 = GroupCallId; //@description Returns information about a group call @group_call_id Group call identifier diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 3d9d0f40a..94957ab84 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -650,6 +650,7 @@ struct GroupCallManager::GroupCall { bool mute_new_participants = false; bool allowed_change_mute_new_participants = false; bool joined_date_asc = false; + int32 scheduled_start_date = 0; int32 participant_count = 0; int32 duration = 0; int32 audio_source = 0; @@ -664,6 +665,7 @@ struct GroupCallManager::GroupCall { int32 mute_version = -1; int32 stream_dc_id_version = -1; int32 record_start_date_version = -1; + int32 scheduled_start_date_version = -1; vector> after_join; bool have_pending_mute_new_participants = false; @@ -3358,11 +3360,20 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrflags_ & telegram_api::groupCall::SCHEDULE_DATE_MASK) != 0) { + call.scheduled_start_date = group_call->schedule_date_; + if (call.scheduled_start_date <= 0) { + LOG(ERROR) << "Receive invalid scheduled start date " << group_call->schedule_date_ << " in " + << input_group_call_id; + call.scheduled_start_date = 0; + } + } call.version = group_call->version_; call.title_version = group_call->version_; call.mute_version = group_call->version_; call.stream_dc_id_version = group_call->version_; call.record_start_date_version = group_call->version_; + call.scheduled_start_date_version = group_call->version_; if (group_call->params_ != nullptr) { join_params = std::move(group_call->params_->data_); } @@ -3471,6 +3482,13 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrscheduled_start_date && + call.scheduled_start_date_version >= group_call->scheduled_start_date_version) { + LOG_IF(ERROR, group_call->scheduled_start_date == 0) << call.group_call_id << " became scheduled"; + group_call->scheduled_start_date = call.scheduled_start_date; + group_call->scheduled_start_date_version = call.scheduled_start_date_version; + need_update = true; + } if (call.version > group_call->version) { if (group_call->version != -1) { // if we know group call version, then update participants only by corresponding updates @@ -3811,6 +3829,8 @@ tl_object_ptr GroupCallManager::get_group_call_object( CHECK(group_call != nullptr); CHECK(group_call->is_inited); + int32 scheduled_start_date = group_call->scheduled_start_date; + bool is_active = scheduled_start_date == 0 ? group_call->is_active : 0; bool is_joined = group_call->is_joined && !group_call->is_being_left; bool can_self_unmute = is_joined && group_call->can_self_unmute; bool mute_new_participants = get_group_call_mute_new_participants(group_call); @@ -3819,7 +3839,7 @@ tl_object_ptr GroupCallManager::get_group_call_object( int32 record_start_date = get_group_call_record_start_date(group_call); int32 record_duration = record_start_date == 0 ? 0 : max(G()->unix_time() - record_start_date + 1, 1); return td_api::make_object( - group_call->group_call_id.get(), get_group_call_title(group_call), group_call->is_active, is_joined, + group_call->group_call_id.get(), get_group_call_title(group_call), scheduled_start_date, is_active, is_joined, group_call->need_rejoin, can_self_unmute, group_call->can_be_managed, group_call->participant_count, group_call->loaded_all_participants, std::move(recent_speakers), mute_new_participants, can_change_mute_new_participants, record_duration, group_call->duration); From 55662f5db65c22ac0af5c1f3944c8ed78f96c81f Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 6 Apr 2021 12:33:08 +0300 Subject: [PATCH 213/281] Add CHECK debug. --- td/telegram/MessagesManager.cpp | 7 +++++-- td/telegram/MessagesManager.h | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index a227604e9..e09b82a24 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -32670,6 +32670,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq add_notification_id_to_message_id_correspondence(d, m->notification_id, m->message_id); } + result_message->debug_source = source; d->being_added_message_id = MessageId(); if (!td_->auth_manager_->is_bot() && from_update && d->reply_markup_message_id != MessageId()) { @@ -34336,8 +34337,10 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab if (d->messages != nullptr) { CHECK(d->messages->message_id == last_message_id); - CHECK(d->messages->left == nullptr); - CHECK(d->messages->right == nullptr); + LOG_CHECK(d->messages->left == nullptr) + << (d->messages->left->debug_source != nullptr ? d->messages->left->debug_source : "null"); + LOG_CHECK(d->messages->right == nullptr) + << (d->messages->right->debug_source != nullptr ? d->messages->right->debug_source : "null"); } } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 03dd95dc1..24ca71aac 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1106,6 +1106,8 @@ class MessagesManager : public Actor { int32 last_edit_pts = 0; + const char *debug_source = nullptr; + unique_ptr left; unique_ptr right; From ef93bde7a2411817ec08cfc1b64a9847b4b9588d Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 7 Apr 2021 01:43:47 +0300 Subject: [PATCH 214/281] Allow to send inputMessageInvoice without start_parameter. --- td/generate/scheme/td_api.tl | 36 +++++++++++++++++++----------------- td/telegram/Payments.cpp | 5 ++++- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 397630e56..be015b107 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -1919,8 +1919,10 @@ inputMessageDice emoji:string clear_draft:Bool = InputMessageContent; //@description A message with a game; not supported for channels or secret chats @bot_user_id User identifier of the bot that owns the game @game_short_name Short name of the game inputMessageGame bot_user_id:int32 game_short_name:string = InputMessageContent; -//@description A message with an invoice; can be used only by bots and only in private chats @invoice Invoice @title Product title; 1-32 characters @param_description Product description; 0-255 characters @photo_url Product photo URL; optional @photo_size Product photo size @photo_width Product photo width @photo_height Product photo height -//@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 +//@description A message with an invoice; can be used only by bots @invoice Invoice @title Product title; 1-32 characters @param_description Product description; 0-255 characters +//@photo_url Product photo URL; optional @photo_size Product photo size @photo_width Product photo width @photo_height Product photo height +//@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 deep link parameter for the generation of this invoice. If empty, it would be possible to pay directly from forwards of the invoice message 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 (up to 300 characters for bots) @options List of poll answer options, 2-10 strings 1-100 characters each @@ -2275,30 +2277,30 @@ httpUrl url:string = HttpUrl; //@video_url The URL of the video file (file size must not exceed 1MB) @video_mime_type MIME type of the video file. Must be one of "image/gif" and "video/mp4" //@video_duration Duration of the video, in seconds @video_width Width of the video @video_height Height of the video //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageAnimation, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageAnimation, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultAnimation id:string title:string thumbnail_url:string thumbnail_mime_type:string video_url:string video_mime_type:string video_duration:int32 video_width:int32 video_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to an article or web page @id Unique identifier of the query result @url URL of the result, if it exists @hide_url True, if the URL must be not shown @title Title of the result //@param_description A short description of the result @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultArticle id:string url:string hide_url:Bool title:string description:string thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to an MP3 audio file @id Unique identifier of the query result @title Title of the audio file @performer Performer of the audio file //@audio_url The URL of the audio file @audio_duration Audio file duration, in seconds //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageAudio, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageAudio, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultAudio id:string title:string performer:string audio_url:string audio_duration:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a user contact @id Unique identifier of the query result @contact User contact @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultContact id:string contact:contact thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to a file @id Unique identifier of the query result @title Title of the resulting file @param_description Short description of the result, if known @document_url URL of the file @mime_type MIME type of the file content; only "application/pdf" and "application/zip" are currently allowed //@thumbnail_url The URL of the file thumbnail, if it exists @thumbnail_width Width of the thumbnail @thumbnail_height Height of the thumbnail //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageDocument, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageDocument, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultDocument id:string title:string description:string document_url:string mime_type:string thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a game @id Unique identifier of the query result @game_short_name Short name of the game @reply_markup Message reply markup. Must be of type replyMarkupInlineKeyboard or null @@ -2308,37 +2310,37 @@ inputInlineQueryResultGame id:string game_short_name:string reply_markup:ReplyMa //@live_period Amount of time relative to the message sent time until the location can be updated, in seconds //@title Title of the result @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultLocation id:string location:location live_period:int32 title:string thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents link to a JPEG image @id Unique identifier of the query result @title Title of the result, if known @param_description A short description of the result, if known @thumbnail_url URL of the photo thumbnail, if it exists //@photo_url The URL of the JPEG photo (photo size must not exceed 5MB) @photo_width Width of the photo @photo_height Height of the photo //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessagePhoto, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessagePhoto, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultPhoto id:string title:string description:string thumbnail_url:string photo_url:string photo_width:int32 photo_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to a WEBP or TGS sticker @id Unique identifier of the query result @thumbnail_url URL of the sticker thumbnail, if it exists //@sticker_url The URL of the WEBP or TGS sticker (sticker file size must not exceed 5MB) @sticker_width Width of the sticker @sticker_height Height of the sticker //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, inputMessageSticker, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageSticker, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultSticker id:string thumbnail_url:string sticker_url:string sticker_width:int32 sticker_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents information about a venue @id Unique identifier of the query result @venue Venue result @thumbnail_url URL of the result thumbnail, if it exists @thumbnail_width Thumbnail width, if known @thumbnail_height Thumbnail height, if known //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultVenue id:string venue:venue thumbnail_url:string thumbnail_width:int32 thumbnail_height:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to a page containing an embedded video player or a video file @id Unique identifier of the query result @title Title of the result @param_description A short description of the result, if known //@thumbnail_url The URL of the video thumbnail (JPEG), if it exists @video_url URL of the embedded video player or video file @mime_type MIME type of the content of the video URL, only "text/html" or "video/mp4" are currently supported //@video_width Width of the video @video_height Height of the video @video_duration Video duration, in seconds //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageVideo, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageVideo, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultVideo id:string title:string description:string thumbnail_url:string video_url:string mime_type:string video_width:int32 video_height:int32 video_duration:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a link to an opus-encoded audio file within an OGG container, single channel audio @id Unique identifier of the query result @title Title of the voice note //@voice_note_url The URL of the voice note file @voice_note_duration Duration of the voice note, in seconds //@reply_markup The message reply markup. Must be of type replyMarkupInlineKeyboard or null -//@input_message_content The content of the message to be sent. Must be one of the following types: InputMessageText, InputMessageVoiceNote, InputMessageInvoice, InputMessageLocation, InputMessageVenue or InputMessageContact +//@input_message_content The content of the message to be sent. Must be one of the following types: inputMessageText, inputMessageVoiceNote, inputMessageInvoice, inputMessageLocation, inputMessageVenue or inputMessageContact inputInlineQueryResultVoiceNote id:string title:string voice_note_url:string voice_note_duration:int32 reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; @@ -4088,7 +4090,7 @@ deleteChatMessagesFromUser chat_id:int53 user_id:int32 = Ok; //@description Edits the text of a message (or a text of a game message). Returns the edited message after the edit is completed on the server side -//@chat_id The chat the message belongs to @message_id Identifier of the message @reply_markup The new message reply markup; for bots only @input_message_content New text content of the message. Should be of type InputMessageText +//@chat_id The chat the message belongs to @message_id Identifier of the message @reply_markup The new message reply markup; for bots only @input_message_content New text content of the message. Should be of type inputMessageText editMessageText chat_id:int53 message_id:int53 reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message; //@description Edits the message content of a live location. Messages can be edited for a limited period of time specified in the live location. Returns the edited message after the edit is completed on the server side @@ -4098,7 +4100,7 @@ editMessageText chat_id:int53 message_id:int53 reply_markup:ReplyMarkup input_me editMessageLiveLocation chat_id:int53 message_id:int53 reply_markup:ReplyMarkup location:location heading:int32 proximity_alert_radius:int32 = Message; //@description Edits the content of a message with an animation, an audio, a document, a photo or a video. The media in the message can't be replaced if the message was set to self-destruct. Media can't be replaced by self-destructing media. Media in an album can be edited only to contain a photo or a video. Returns the edited message after the edit is completed on the server side -//@chat_id The chat the message belongs to @message_id Identifier of the message @reply_markup The new message reply markup; for bots only @input_message_content New content of the message. Must be one of the following types: InputMessageAnimation, InputMessageAudio, InputMessageDocument, InputMessagePhoto or InputMessageVideo +//@chat_id The chat the message belongs to @message_id Identifier of the message @reply_markup The new message reply markup; for bots only @input_message_content New content of the message. Must be one of the following types: inputMessageAnimation, inputMessageAudio, inputMessageDocument, inputMessagePhoto or inputMessageVideo editMessageMedia chat_id:int53 message_id:int53 reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message; //@description Edits the message content caption. Returns the edited message after the edit is completed on the server side @@ -4109,7 +4111,7 @@ editMessageCaption chat_id:int53 message_id:int53 reply_markup:ReplyMarkup capti //@chat_id The chat the message belongs to @message_id Identifier of the message @reply_markup The new message reply markup editMessageReplyMarkup chat_id:int53 message_id:int53 reply_markup:ReplyMarkup = Message; -//@description Edits the text of an inline text or game message sent via a bot; for bots only @inline_message_id Inline message identifier @reply_markup The new message reply markup @input_message_content New text content of the message. Should be of type InputMessageText +//@description Edits the text of an inline text or game message sent via a bot; for bots only @inline_message_id Inline message identifier @reply_markup The new message reply markup @input_message_content New text content of the message. Should be of type inputMessageText editInlineMessageText inline_message_id:string reply_markup:ReplyMarkup input_message_content:InputMessageContent = Ok; //@description Edits the content of a live location in an inline message sent via a bot; for bots only @inline_message_id Inline message identifier @reply_markup The new message reply markup @@ -4119,7 +4121,7 @@ editInlineMessageText inline_message_id:string reply_markup:ReplyMarkup input_me editInlineMessageLiveLocation inline_message_id:string reply_markup:ReplyMarkup location:location heading:int32 proximity_alert_radius:int32 = Ok; //@description Edits the content of a message with an animation, an audio, a document, a photo or a video in an inline message sent via a bot; for bots only @inline_message_id Inline message identifier -//@reply_markup The new message reply markup; for bots only @input_message_content New content of the message. Must be one of the following types: InputMessageAnimation, InputMessageAudio, InputMessageDocument, InputMessagePhoto or InputMessageVideo +//@reply_markup The new message reply markup; for bots only @input_message_content New content of the message. Must be one of the following types: inputMessageAnimation, inputMessageAudio, inputMessageDocument, inputMessagePhoto or inputMessageVideo editInlineMessageMedia inline_message_id:string reply_markup:ReplyMarkup input_message_content:InputMessageContent = Ok; //@description Edits the caption of an inline message sent via a bot; for bots only @inline_message_id Inline message identifier @reply_markup The new message reply markup @caption New message content caption; 0-GetOption("message_caption_length_max") characters diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index a9ff2085a..f8382807b 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -868,7 +868,10 @@ static tl_object_ptr get_input_web_document(cons } tl_object_ptr get_input_media_invoice(const InputInvoice &input_invoice, Td *td) { - int32 flags = telegram_api::inputMediaInvoice::START_PARAM_MASK; + int32 flags = 0; + if (!input_invoice.start_parameter.empty()) { + flags |= telegram_api::inputMediaInvoice::START_PARAM_MASK; + } auto input_web_document = get_input_web_document(td->file_manager_.get(), input_invoice.photo); if (input_web_document != nullptr) { flags |= telegram_api::inputMediaInvoice::PHOTO_MASK; From a7c34c5c4971fc77b54c7c85e9254f9bcb0003d2 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 7 Apr 2021 02:11:14 +0300 Subject: [PATCH 215/281] Add td_api::startScheduledGroupCall. --- td/generate/scheme/td_api.tl | 3 ++ td/telegram/GroupCallManager.cpp | 66 ++++++++++++++++++++++++++++++++ td/telegram/GroupCallManager.h | 2 + td/telegram/Td.cpp | 6 +++ td/telegram/Td.h | 2 + td/telegram/cli.cpp | 2 + 6 files changed, 81 insertions(+) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index be015b107..7a8522841 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4612,6 +4612,9 @@ createVoiceChat chat_id:int53 title:string start_date:int32 = GroupCallId; //@description Returns information about a group call @group_call_id Group call identifier getGroupCall group_call_id:int32 = GroupCall; +//@description Starts a scheduled group call @group_call_id Group call identifier +startScheduledGroupCall group_call_id:int32 = Ok; + //@description Joins a group call //@group_call_id Group call identifier //@participant_alias Identifier of the group call participant, which will be used to join the call; voice chats only diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 94957ab84..e484aed65 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -280,6 +280,38 @@ class GetGroupCallParticipantsQuery : public Td::ResultHandler { } }; +class StartScheduledGroupCallQuery : public Td::ResultHandler { + Promise promise_; + + public: + explicit StartScheduledGroupCallQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(InputGroupCallId input_group_call_id) { + send_query(G()->net_query_creator().create( + telegram_api::phone_startScheduledGroupCall(input_group_call_id.get_input_group_call()))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for StartScheduledGroupCallQuery: " << to_string(ptr); + td->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); + } + + void on_error(uint64 id, Status status) override { + if (status.message() == "GROUPCALL_NOT_MODIFIED") { + promise_.set_value(Unit()); + return; + } + promise_.set_error(std::move(status)); + } +}; + class JoinGroupCallQuery : public Td::ResultHandler { Promise promise_; InputGroupCallId input_group_call_id_; @@ -2069,6 +2101,40 @@ void GroupCallManager::finish_get_group_call_stream_segment(InputGroupCallId inp promise.set_result(std::move(result)); } +void GroupCallManager::start_scheduled_group_call(GroupCallId group_call_id, Promise &&promise) { + if (G()->close_flag()) { + return promise.set_error(Status::Error(500, "Request aborted")); + } + + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited) { + reload_group_call(input_group_call_id, + PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, promise = std::move(promise)]( + Result> &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &GroupCallManager::start_scheduled_group_call, group_call_id, + std::move(promise)); + } + })); + return; + } + if (!group_call->can_be_managed) { + return promise.set_error(Status::Error(400, "Not enough rights to start the group call")); + } + if (!group_call->is_active) { + return promise.set_error(Status::Error(400, "Group call already ended")); + } + if (group_call->scheduled_start_date == 0) { + return promise.set_value(Unit()); + } + + td_->create_handler(std::move(promise))->send(input_group_call_id); +} + void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, td_api::object_ptr &&payload, int32 audio_source, bool is_muted, const string &invite_hash, diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index d4a751879..422dd4ecc 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -60,6 +60,8 @@ class GroupCallManager : public Actor { void get_group_call_stream_segment(GroupCallId group_call_id, int64 time_offset, int32 scale, Promise &&promise); + void start_scheduled_group_call(GroupCallId group_call_id, Promise &&promise); + void join_group_call(GroupCallId group_call_id, DialogId as_dialog_id, td_api::object_ptr &&payload, int32 audio_source, bool is_muted, const string &invite_hash, Promise> &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 0d8f846d1..f3bd6e62b 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5995,6 +5995,12 @@ void Td::on_request(uint64 id, const td_api::getGroupCall &request) { group_call_manager_->get_group_call(GroupCallId(request.group_call_id_), std::move(promise)); } +void Td::on_request(uint64 id, const td_api::startScheduledGroupCall &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + group_call_manager_->start_scheduled_group_call(GroupCallId(request.group_call_id_), std::move(promise)); +} + void Td::on_request(uint64 id, td_api::joinGroupCall &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.invite_hash_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 22aa4d61a..6ada0bdab 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -707,6 +707,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::getGroupCall &request); + void on_request(uint64 id, const td_api::startScheduledGroupCall &request); + void on_request(uint64 id, td_api::joinGroupCall &request); void on_request(uint64 id, td_api::setGroupCallTitle &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 5837c964d..683250015 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2683,6 +2683,8 @@ class CliClient final : public Actor { } else if (op == "ggcss") { send_request(td_api::make_object(as_group_call_id(args), (std::time(nullptr) - 5) * 1000, 0)); + } else if (op == "ssgc") { + send_request(td_api::make_object(as_group_call_id(args))); } else if (op == "jgc") { string group_call_id; string participant_alias; From 10bc074a1ebeb22eb6b41ee723aed0d3c76fb076 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 7 Apr 2021 03:04:56 +0300 Subject: [PATCH 216/281] Support subscription to group call start notification. --- td/generate/scheme/td_api.tl | 7 +- td/telegram/GroupCallManager.cpp | 154 ++++++++++++++++++++++++++++++- td/telegram/GroupCallManager.h | 9 ++ td/telegram/Td.cpp | 7 ++ td/telegram/Td.h | 2 + td/telegram/cli.cpp | 3 + 6 files changed, 176 insertions(+), 6 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 7a8522841..b40e8e2d0 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2147,6 +2147,7 @@ groupCallRecentSpeaker speaker:MessageSender is_speaking:Bool = GroupCallRecentS //@id Group call identifier //@title Group call title //@scheduled_start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator; 0 if it is already active or was ended +//@enabled_start_notification True, if the group call is scheduled and the current user will receive a notification when the group call will start //@is_active True, if the call is active //@is_joined True, if the call is joined //@need_rejoin True, if user was kicked from the call because of network loss and the call needs to be rejoined @@ -2159,7 +2160,7 @@ groupCallRecentSpeaker speaker:MessageSender is_speaking:Bool = GroupCallRecentS //@can_change_mute_new_participants True, if the current user can enable or disable mute_new_participants setting //@record_duration Duration of the ongoing group call recording, in seconds; 0 if none. An updateGroupCall update is not triggered when value of this field changes, but the same recording goes on //@duration Call duration; for ended calls only -groupCall id:int32 title:string scheduled_start_date:int32 is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector mute_new_participants:Bool can_change_mute_new_participants:Bool record_duration:int32 duration:int32 = GroupCall; +groupCall id:int32 title:string scheduled_start_date:int32 enabled_start_notification:Bool is_active:Bool is_joined:Bool need_rejoin:Bool can_unmute_self:Bool can_be_managed:Bool participant_count:int32 loaded_all_participants:Bool recent_speakers:vector mute_new_participants:Bool can_change_mute_new_participants:Bool record_duration:int32 duration:int32 = GroupCall; //@description Describes a payload fingerprint for interaction with tgcalls @hash Value of the field hash @setup Value of the field setup @fingerprint Value of the field fingerprint groupCallPayloadFingerprint hash:string setup:string fingerprint:string = GroupCallPayloadFingerprint; @@ -4615,6 +4616,10 @@ getGroupCall group_call_id:int32 = GroupCall; //@description Starts a scheduled group call @group_call_id Group call identifier startScheduledGroupCall group_call_id:int32 = Ok; +//@description Toggles whether the current user will receive a notification when the group call will start; scheduled group calls only +//@group_call_id Group call identifier @enabled_start_notification New value of the enabled_start_notification setting +toggleGroupCallEnabledStartNotification group_call_id:int32 enabled_start_notification:Bool = Ok; + //@description Joins a group call //@group_call_id Group call identifier //@participant_alias Identifier of the group call participant, which will be used to join the call; voice chats only diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index e484aed65..49c5fb2d6 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -400,6 +400,38 @@ class EditGroupCallTitleQuery : public Td::ResultHandler { } }; +class ToggleGroupCallStartSubscriptionQuery : public Td::ResultHandler { + Promise promise_; + + public: + explicit ToggleGroupCallStartSubscriptionQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(InputGroupCallId input_group_call_id, bool start_subscribed) { + send_query(G()->net_query_creator().create(telegram_api::phone_toggleGroupCallStartSubscription( + input_group_call_id.get_input_group_call(), start_subscribed))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for ToggleGroupCallStartSubscriptionQuery: " << to_string(ptr); + td->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); + } + + void on_error(uint64 id, Status status) override { + if (status.message() == "GROUPCALL_NOT_MODIFIED") { + promise_.set_value(Unit()); + return; + } + promise_.set_error(std::move(status)); + } +}; + class ToggleGroupCallSettingsQuery : public Td::ResultHandler { Promise promise_; @@ -679,6 +711,7 @@ struct GroupCallManager::GroupCall { bool syncing_participants = false; bool need_syncing_participants = false; bool loaded_all_participants = false; + bool start_subscribed = false; bool mute_new_participants = false; bool allowed_change_mute_new_participants = false; bool joined_date_asc = false; @@ -694,12 +727,15 @@ struct GroupCallManager::GroupCall { int32 version = -1; int32 leave_version = -1; int32 title_version = -1; + int32 start_subscribed_version = -1; int32 mute_version = -1; int32 stream_dc_id_version = -1; int32 record_start_date_version = -1; int32 scheduled_start_date_version = -1; vector> after_join; + bool have_pending_start_subscribed = false; + bool pending_start_subscribed = false; bool have_pending_mute_new_participants = false; bool pending_mute_new_participants = false; string pending_title; @@ -1258,6 +1294,12 @@ const string &GroupCallManager::get_group_call_title(const GroupCall *group_call return group_call->pending_title.empty() ? group_call->title : group_call->pending_title; } +bool GroupCallManager::get_group_call_start_subscribed(const GroupCall *group_call) { + CHECK(group_call != nullptr); + return group_call->have_pending_start_subscribed ? group_call->pending_start_subscribed + : group_call->start_subscribed; +} + bool GroupCallManager::get_group_call_mute_new_participants(const GroupCall *group_call) { CHECK(group_call != nullptr); return group_call->have_pending_mute_new_participants ? group_call->pending_mute_new_participants @@ -2588,6 +2630,93 @@ void GroupCallManager::on_edit_group_call_title(InputGroupCallId input_group_cal } } +void GroupCallManager::toggle_group_call_start_subscribed(GroupCallId group_call_id, bool start_subscribed, + Promise &&promise) { + if (G()->close_flag()) { + return promise.set_error(Status::Error(500, "Request aborted")); + } + + TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id)); + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited) { + reload_group_call(input_group_call_id, + PromiseCreator::lambda( + [actor_id = actor_id(this), group_call_id, start_subscribed, promise = std::move(promise)]( + Result> &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + send_closure(actor_id, &GroupCallManager::toggle_group_call_start_subscribed, + group_call_id, start_subscribed, std::move(promise)); + } + })); + return; + } + if (!group_call->is_active || group_call->scheduled_start_date <= 0) { + return promise.set_error(Status::Error(400, "Group call isn't scheduled")); + } + + if (start_subscribed == get_group_call_start_subscribed(group_call)) { + return promise.set_value(Unit()); + } + + // there is no reason to save promise; we will send an update with actual value anyway + + group_call->pending_start_subscribed = start_subscribed; + if (!group_call->have_pending_start_subscribed) { + group_call->have_pending_start_subscribed = true; + send_toggle_group_call_start_subscription_query(input_group_call_id, start_subscribed); + } + send_update_group_call(group_call, "toggle_group_call_start_subscription"); + promise.set_value(Unit()); +} + +void GroupCallManager::send_toggle_group_call_start_subscription_query(InputGroupCallId input_group_call_id, + bool start_subscribed) { + auto promise = + PromiseCreator::lambda([actor_id = actor_id(this), input_group_call_id, start_subscribed](Result result) { + send_closure(actor_id, &GroupCallManager::on_toggle_group_call_start_subscription, input_group_call_id, + start_subscribed, std::move(result)); + }); + td_->create_handler(std::move(promise)) + ->send(input_group_call_id, start_subscribed); +} + +void GroupCallManager::on_toggle_group_call_start_subscription(InputGroupCallId input_group_call_id, + bool start_subscribed, Result &&result) { + if (G()->close_flag()) { + return; + } + + auto *group_call = get_group_call(input_group_call_id); + if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || + !group_call->have_pending_start_subscribed) { + return; + } + + if (result.is_error()) { + group_call->have_pending_start_subscribed = false; + LOG(ERROR) << "Failed to set enabled_start_notification to " << start_subscribed << " in " << input_group_call_id + << ": " << result.error(); + if (group_call->pending_start_subscribed != group_call->start_subscribed) { + send_update_group_call(group_call, "on_toggle_group_call_start_subscription failed"); + } + } else { + if (group_call->pending_start_subscribed != start_subscribed) { + // need to send another request + send_toggle_group_call_start_subscription_query(input_group_call_id, group_call->pending_start_subscribed); + return; + } + + group_call->have_pending_start_subscribed = false; + if (group_call->start_subscribed != start_subscribed) { + LOG(ERROR) << "Failed to set enabled_start_notification to " << start_subscribed << " in " << input_group_call_id; + send_update_group_call(group_call, "on_toggle_group_call_start_subscription failed 2"); + } + } +} + void GroupCallManager::toggle_group_call_mute_new_participants(GroupCallId group_call_id, bool mute_new_participants, Promise &&promise) { if (G()->close_flag()) { @@ -2612,7 +2741,7 @@ void GroupCallManager::toggle_group_call_mute_new_participants(GroupCallId group return; } if (!group_call->is_active || !group_call->can_be_managed || !group_call->allowed_change_mute_new_participants) { - return promise.set_error(Status::Error(400, "Can't change mute_new_participant setting")); + return promise.set_error(Status::Error(400, "Can't change mute_new_participants setting")); } if (mute_new_participants == get_group_call_mute_new_participants(group_call)) { @@ -3407,6 +3536,7 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrid_, group_call->access_hash_); call.is_active = true; call.title = std::move(group_call->title_); + call.start_subscribed = group_call->schedule_start_subscribed_; call.mute_new_participants = group_call->join_muted_; call.joined_date_asc = group_call->join_date_asc_; call.allowed_change_mute_new_participants = group_call->can_change_join_muted_; @@ -3434,8 +3564,12 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrversion_; call.title_version = group_call->version_; + call.start_subscribed_version = group_call->version_; call.mute_version = group_call->version_; call.stream_dc_id_version = group_call->version_; call.record_start_date_version = group_call->version_; @@ -3507,6 +3641,15 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrstart_subscribed && + call.start_subscribed_version >= group_call->start_subscribed_version) { + auto old_start_subscribed = get_group_call_start_subscribed(group_call); + group_call->start_subscribed = call.start_subscribed; + group_call->start_subscribed_version = call.start_subscribed_version; + if (old_start_subscribed != get_group_call_start_subscribed(group_call)) { + need_update = true; + } + } auto mute_flags_changed = call.mute_new_participants != group_call->mute_new_participants || call.allowed_change_mute_new_participants != group_call->allowed_change_mute_new_participants; @@ -3899,16 +4042,17 @@ tl_object_ptr GroupCallManager::get_group_call_object( bool is_active = scheduled_start_date == 0 ? group_call->is_active : 0; bool is_joined = group_call->is_joined && !group_call->is_being_left; bool can_self_unmute = is_joined && group_call->can_self_unmute; + bool start_subscribed = get_group_call_start_subscribed(group_call); bool mute_new_participants = get_group_call_mute_new_participants(group_call); bool can_change_mute_new_participants = group_call->is_active && group_call->can_be_managed && group_call->allowed_change_mute_new_participants; int32 record_start_date = get_group_call_record_start_date(group_call); int32 record_duration = record_start_date == 0 ? 0 : max(G()->unix_time() - record_start_date + 1, 1); return td_api::make_object( - group_call->group_call_id.get(), get_group_call_title(group_call), scheduled_start_date, is_active, is_joined, - group_call->need_rejoin, can_self_unmute, group_call->can_be_managed, group_call->participant_count, - group_call->loaded_all_participants, std::move(recent_speakers), mute_new_participants, - can_change_mute_new_participants, record_duration, group_call->duration); + group_call->group_call_id.get(), get_group_call_title(group_call), scheduled_start_date, start_subscribed, + is_active, is_joined, group_call->need_rejoin, can_self_unmute, group_call->can_be_managed, + group_call->participant_count, group_call->loaded_all_participants, std::move(recent_speakers), + mute_new_participants, can_change_mute_new_participants, record_duration, group_call->duration); } tl_object_ptr GroupCallManager::get_update_group_call_object( diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 422dd4ecc..7747c4eb1 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -68,6 +68,8 @@ class GroupCallManager : public Actor { void set_group_call_title(GroupCallId group_call_id, string title, Promise &&promise); + void toggle_group_call_start_subscribed(GroupCallId group_call_id, bool start_subscribed, Promise &&promise); + void toggle_group_call_mute_new_participants(GroupCallId group_call_id, bool mute_new_participants, Promise &&promise); @@ -179,6 +181,8 @@ class GroupCallManager : public Actor { static const string &get_group_call_title(const GroupCall *group_call); + static bool get_group_call_start_subscribed(const GroupCall *group_call); + static bool get_group_call_mute_new_participants(const GroupCall *group_call); static int32 get_group_call_record_start_date(const GroupCall *group_call); @@ -239,6 +243,11 @@ class GroupCallManager : public Actor { void on_edit_group_call_title(InputGroupCallId input_group_call_id, const string &title, Result &&result); + void send_toggle_group_call_start_subscription_query(InputGroupCallId input_group_call_id, bool start_subscribed); + + void on_toggle_group_call_start_subscription(InputGroupCallId input_group_call_id, bool start_subscribed, + Result &&result); + void send_toggle_group_call_mute_new_participants_query(InputGroupCallId input_group_call_id, bool mute_new_participants); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index f3bd6e62b..c9faf9c63 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6001,6 +6001,13 @@ void Td::on_request(uint64 id, const td_api::startScheduledGroupCall &request) { group_call_manager_->start_scheduled_group_call(GroupCallId(request.group_call_id_), std::move(promise)); } +void Td::on_request(uint64 id, const td_api::toggleGroupCallEnabledStartNotification &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + group_call_manager_->toggle_group_call_start_subscribed(GroupCallId(request.group_call_id_), + request.enabled_start_notification_, std::move(promise)); +} + void Td::on_request(uint64 id, td_api::joinGroupCall &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.invite_hash_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 6ada0bdab..3c59d0f77 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -709,6 +709,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::startScheduledGroupCall &request); + void on_request(uint64 id, const td_api::toggleGroupCallEnabledStartNotification &request); + void on_request(uint64 id, td_api::joinGroupCall &request); void on_request(uint64 id, td_api::setGroupCallTitle &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 683250015..c946198f1 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2685,6 +2685,9 @@ class CliClient final : public Actor { (std::time(nullptr) - 5) * 1000, 0)); } else if (op == "ssgc") { send_request(td_api::make_object(as_group_call_id(args))); + } else if (op == "tgcesn" || op == "tgcesne") { + send_request(td_api::make_object(as_group_call_id(args), + op == "tgcesne")); } else if (op == "jgc") { string group_call_id; string participant_alias; From 4aa5df26bc8869076932e8f6976004029c5e773f Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 7 Apr 2021 03:30:26 +0300 Subject: [PATCH 217/281] Use participant_id instead of participant/participant_alias for group call participant identifiers. --- td/generate/scheme/td_api.tl | 42 ++++++++++++++++++------------------ td/telegram/Td.cpp | 15 ++++++------- td/telegram/Td.h | 2 +- td/telegram/cli.cpp | 4 ++-- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index b40e8e2d0..853c46a64 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -480,7 +480,7 @@ chatMemberStatusRestricted is_member:Bool restricted_until_date:int32 permission //@description The user or the chat is not a chat member chatMemberStatusLeft = ChatMemberStatus; -//@description The user or the chat was banned (and hence is not a member of the chat). Implies the user can't return to the chat, view messages, or be used as an alias to join a voice chat of the chat +//@description The user or the chat was banned (and hence is not a member of the chat). Implies the user can't return to the chat, view messages, or be used as a participant identifier to join a voice chat of the chat //@banned_until_date Point in time (Unix timestamp) when the user will be unbanned; 0 if never. If the user is banned for more than 366 days or for less than 30 seconds from the current time, the user is considered to be banned forever. Always 0 in basic groups chatMemberStatusBanned banned_until_date:int32 = ChatMemberStatus; @@ -895,8 +895,8 @@ chatPosition list:ChatList order:int64 is_pinned:Bool source:ChatSource = ChatPo //@description Describes a voice chat //@group_call_id Group call identifier of an active voice chat; 0 if none. Full informationa about the voice chat can be received through the method getGroupCall //@has_participants True, if the voice chat has participants -//@default_participant_alias Default group call participant identifier to join the voice chat; may be null -voiceChat group_call_id:int32 has_participants:Bool default_participant_alias:MessageSender = VoiceChat; +//@default_participant_id Default group call participant identifier to join the voice chat; may be null +voiceChat group_call_id:int32 has_participants:Bool default_participant_id:MessageSender = VoiceChat; //@description A chat. (Can be a private chat, basic group, supergroup, or secret chat) @@ -2140,8 +2140,8 @@ callStateDiscarded reason:CallDiscardReason need_rating:Bool need_debug_informat callStateError error:error = CallState; -//@description Describes a recently speaking participant in a group call @speaker Speaking participantt @is_speaking True, is the user has spoken recently -groupCallRecentSpeaker speaker:MessageSender is_speaking:Bool = GroupCallRecentSpeaker; +//@description Describes a recently speaking participant in a group call @participant_id Group call participant identifier @is_speaking True, is the user has spoken recently +groupCallRecentSpeaker participant_id:MessageSender is_speaking:Bool = GroupCallRecentSpeaker; //@description Describes a group call //@id Group call identifier @@ -2184,7 +2184,7 @@ groupCallJoinResponseStream = GroupCallJoinResponse; //@description Represents a group call participant -//@participant Identifier of the group call participant +//@participant_id Identifier of the group call participant //@source User's synchronization source //@bio The participant user's bio or the participant chat's description //@is_current_user True, if the participant is the current user @@ -2199,7 +2199,7 @@ groupCallJoinResponseStream = GroupCallJoinResponse; //@can_unmute_self True, if the participant is muted for all users, but can unmute themself //@volume_level Participant's volume level; 1-20000 in hundreds of percents //@order User's order in the group call participant list. Orders must be compared lexicographically. The bigger is order, the higher is user in the list. If order is empty, the user must be removed from the participant list -groupCallParticipant participant:MessageSender source:int32 bio:string is_current_user:Bool is_speaking:Bool is_hand_raised:Bool can_be_muted_for_all_users:Bool can_be_unmuted_for_all_users:Bool can_be_muted_for_current_user:Bool can_be_unmuted_for_current_user:Bool is_muted_for_all_users:Bool is_muted_for_current_user:Bool can_unmute_self:Bool volume_level:int32 order:string = GroupCallParticipant; +groupCallParticipant participant_id:MessageSender source:int32 bio:string is_current_user:Bool is_speaking:Bool is_hand_raised:Bool can_be_muted_for_all_users:Bool can_be_unmuted_for_all_users:Bool can_be_muted_for_current_user:Bool can_be_unmuted_for_current_user:Bool is_muted_for_all_users:Bool is_muted_for_current_user:Bool can_unmute_self:Bool volume_level:int32 order:string = GroupCallParticipant; //@class CallProblem @description Describes the exact type of a problem with a call @@ -2506,11 +2506,11 @@ chatEventVoiceChatCreated group_call_id:int32 = ChatEventAction; //@description A voice chat was discarded @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall chatEventVoiceChatDiscarded group_call_id:int32 = ChatEventAction; -//@description A voice chat participant was muted or unmuted @participant Identifier of the affected group call participant @is_muted New value of is_muted -chatEventVoiceChatParticipantIsMutedToggled participant:MessageSender is_muted:Bool = ChatEventAction; +//@description A voice chat participant was muted or unmuted @participant_id Identifier of the affected group call participant @is_muted New value of is_muted +chatEventVoiceChatParticipantIsMutedToggled participant_id:MessageSender is_muted:Bool = ChatEventAction; -//@description A voice chat participant volume level was changed @participant Identifier of the affected group call participant @volume_level New value of volume_level; 1-20000 in hundreds of percents -chatEventVoiceChatParticipantVolumeLevelChanged participant:MessageSender volume_level:int32 = ChatEventAction; +//@description A voice chat participant volume level was changed @participant_id Identifier of the affected group call participant @volume_level New value of volume_level; 1-20000 in hundreds of percents +chatEventVoiceChatParticipantVolumeLevelChanged participant_id:MessageSender volume_level:int32 = ChatEventAction; //@description The mute_new_participants setting of a voice chat was toggled @mute_new_participants New value of the mute_new_participants setting chatEventVoiceChatMuteNewParticipantsToggled mute_new_participants:Bool = ChatEventAction; @@ -4601,8 +4601,8 @@ sendCallRating call_id:int32 rating:int32 comment:string problems:vectorget_group_call_join_as(DialogId(request.chat_id_), std::move(promise)); @@ -6012,10 +6012,9 @@ void Td::on_request(uint64 id, td_api::joinGroupCall &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.invite_hash_); CREATE_REQUEST_PROMISE(); - group_call_manager_->join_group_call(GroupCallId(request.group_call_id_), - group_call_manager_->get_group_call_participant_id(request.participant_alias_), - std::move(request.payload_), request.source_, request.is_muted_, - request.invite_hash_, std::move(promise)); + group_call_manager_->join_group_call( + GroupCallId(request.group_call_id_), group_call_manager_->get_group_call_participant_id(request.participant_id_), + std::move(request.payload_), request.source_, request.is_muted_, request.invite_hash_, std::move(promise)); } void Td::on_request(uint64 id, td_api::setGroupCallTitle &request) { @@ -6086,7 +6085,7 @@ void Td::on_request(uint64 id, const td_api::toggleGroupCallParticipantIsMuted & CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); group_call_manager_->toggle_group_call_participant_is_muted( - GroupCallId(request.group_call_id_), group_call_manager_->get_group_call_participant_id(request.participant_), + GroupCallId(request.group_call_id_), group_call_manager_->get_group_call_participant_id(request.participant_id_), request.is_muted_, std::move(promise)); } @@ -6094,7 +6093,7 @@ void Td::on_request(uint64 id, const td_api::setGroupCallParticipantVolumeLevel CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); group_call_manager_->set_group_call_participant_volume_level( - GroupCallId(request.group_call_id_), group_call_manager_->get_group_call_participant_id(request.participant_), + GroupCallId(request.group_call_id_), group_call_manager_->get_group_call_participant_id(request.participant_id_), request.volume_level_, std::move(promise)); } @@ -6102,7 +6101,7 @@ void Td::on_request(uint64 id, const td_api::toggleGroupCallParticipantIsHandRai CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); group_call_manager_->toggle_group_call_participant_is_hand_raised( - GroupCallId(request.group_call_id_), group_call_manager_->get_group_call_participant_id(request.participant_), + GroupCallId(request.group_call_id_), group_call_manager_->get_group_call_participant_id(request.participant_id_), request.is_hand_raised_, std::move(promise)); } diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 3c59d0f77..6e548409b 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -701,7 +701,7 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::sendCallDebugInformation &request); - void on_request(uint64 id, const td_api::getAvailableVoiceChatAliases &request); + void on_request(uint64 id, const td_api::getVoiceChatAvailableParticipants &request); void on_request(uint64 id, td_api::createVoiceChat &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index c946198f1..597b8b397 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2670,8 +2670,8 @@ class CliClient final : public Actor { as_call_id(call_id), rating, "Wow, such good call! (TDLib test)", std::move(problems))); } else if (op == "scdi" || op == "SendCallDebugInformation") { send_request(td_api::make_object(as_call_id(args), "{}")); - } else if (op == "gavca") { - send_request(td_api::make_object(as_chat_id(args))); + } else if (op == "gvcap") { + send_request(td_api::make_object(as_chat_id(args))); } else if (op == "cvc") { string chat_id; string title; From 37cee0d823a4a04373611b1fc76f2a35c8bde1ce Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 7 Apr 2021 16:25:29 +0300 Subject: [PATCH 218/281] Add td_api::setVoiceChatDefaultParticipant. --- td/generate/scheme/td_api.tl | 3 ++ td/telegram/GroupCallManager.cpp | 77 +++++++++++++++++++++++++++++++- td/telegram/GroupCallManager.h | 2 + td/telegram/Td.cpp | 8 ++++ td/telegram/Td.h | 2 + td/telegram/cli.cpp | 12 +++-- 6 files changed, 99 insertions(+), 5 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 853c46a64..5ff0062df 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4604,6 +4604,9 @@ sendCallDebugInformation call_id:int32 debug_information:string = Ok; //@description Returns list of participant identifiers, which can be used to join voice chats in a chat @chat_id Chat identifier getVoiceChatAvailableParticipants chat_id:int53 = MessageSenders; +//@description Changes default participant identifier, which can be used to join voice chats in a chat @chat_id Chat identifier @default_participant_id Default group call participant identifier to join the voice chats +setVoiceChatDefaultParticipant chat_id:int53 default_participant_id:MessageSender = Ok; + //@description Creates a voice chat (a group call bound to a chat). Available only for basic groups, supergroups and channels; requires can_manage_voice_chats rights //@chat_id Chat identifier, in which the voice chat will be created //@title Group call title; if empty, chat title will be used diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 49c5fb2d6..245d19364 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -123,6 +123,42 @@ class GetGroupCallJoinAsQuery : public Td::ResultHandler { } }; +class SaveDefaultGroupCallJoinAsQuery : public Td::ResultHandler { + Promise promise_; + + public: + explicit SaveDefaultGroupCallJoinAsQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(DialogId dialog_id, DialogId as_dialog_id) { + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + CHECK(input_peer != nullptr); + + auto as_input_peer = td->messages_manager_->get_input_peer(as_dialog_id, AccessRights::Read); + CHECK(as_input_peer != nullptr); + + send_query(G()->net_query_creator().create( + telegram_api::phone_saveDefaultGroupCallJoinAs(std::move(input_peer), std::move(as_input_peer)))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto success = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for SaveDefaultGroupCallJoinAsQuery: " << success; + + promise_.set_value(Unit()); + } + + void on_error(uint64 id, Status status) override { + // td->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetGroupCallJoinAsQuery"); + promise_.set_error(std::move(status)); + } +}; + class CreateGroupCallQuery : public Td::ResultHandler { Promise promise_; DialogId dialog_id_; @@ -1112,6 +1148,43 @@ void GroupCallManager::get_group_call_join_as(DialogId dialog_id, td_->create_handler(std::move(promise))->send(dialog_id); } +void GroupCallManager::set_group_call_default_join_as(DialogId dialog_id, DialogId as_dialog_id, + Promise &&promise) { + if (!dialog_id.is_valid()) { + return promise.set_error(Status::Error(400, "Invalid chat identifier specified")); + } + if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + return promise.set_error(Status::Error(400, "Chat not found")); + } + if (!td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) { + return promise.set_error(Status::Error(400, "Can't access chat")); + } + + switch (as_dialog_id.get_type()) { + case DialogType::User: + if (as_dialog_id != DialogId(td_->contacts_manager_->get_my_id())) { + return promise.set_error(Status::Error(400, "Can't join voice chat as another user")); + } + break; + case DialogType::Chat: + case DialogType::Channel: + if (!td_->messages_manager_->have_dialog_force(as_dialog_id)) { + return promise.set_error(Status::Error(400, "Participant chat not found")); + } + break; + case DialogType::SecretChat: + return promise.set_error(Status::Error(400, "Can't join voice chat as a secret chat")); + default: + return promise.set_error(Status::Error(400, "Invalid default participant identifier specified")); + } + if (!td_->messages_manager_->have_input_peer(as_dialog_id, AccessRights::Read)) { + return promise.set_error(Status::Error(400, "Can't access specified default participant chat")); + } + + td_->create_handler(std::move(promise))->send(dialog_id, as_dialog_id); + td_->messages_manager_->on_update_dialog_default_join_group_call_as_dialog_id(dialog_id, as_dialog_id, true); +} + void GroupCallManager::create_voice_chat(DialogId dialog_id, string title, int32 start_date, Promise &&promise) { if (!dialog_id.is_valid()) { @@ -2213,11 +2286,11 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di } } else { if (!td_->messages_manager_->have_dialog_force(as_dialog_id, "join_group_call")) { - return promise.set_error(Status::Error(400, "Alias chat not found")); + return promise.set_error(Status::Error(400, "Join as chat not found")); } } if (!td_->messages_manager_->have_input_peer(as_dialog_id, AccessRights::Read)) { - return promise.set_error(Status::Error(400, "Can't access the alias participant")); + return promise.set_error(Status::Error(400, "Can't access the join as participant")); } if (dialog_type == DialogType::SecretChat) { return promise.set_error(Status::Error(400, "Can't join voice chat as a secret chat")); diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index 7747c4eb1..dea1ff4ca 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -48,6 +48,8 @@ class GroupCallManager : public Actor { void get_group_call_join_as(DialogId dialog_id, Promise> &&promise); + void set_group_call_default_join_as(DialogId dialog_id, DialogId as_dialog_id, Promise &&promise); + void create_voice_chat(DialogId dialog_id, string title, int32 start_date, Promise &&promise); void get_group_call(GroupCallId group_call_id, Promise> &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index d5bcc7222..5161a918a 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5974,6 +5974,14 @@ void Td::on_request(uint64 id, const td_api::getVoiceChatAvailableParticipants & group_call_manager_->get_group_call_join_as(DialogId(request.chat_id_), std::move(promise)); } +void Td::on_request(uint64 id, const td_api::setVoiceChatDefaultParticipant &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + group_call_manager_->set_group_call_default_join_as( + DialogId(request.chat_id_), group_call_manager_->get_group_call_participant_id(request.default_participant_id_), + std::move(promise)); +} + void Td::on_request(uint64 id, td_api::createVoiceChat &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.title_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 6e548409b..3f8b2d976 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -703,6 +703,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::getVoiceChatAvailableParticipants &request); + void on_request(uint64 id, const td_api::setVoiceChatDefaultParticipant &request); + void on_request(uint64 id, td_api::createVoiceChat &request); void on_request(uint64 id, const td_api::getGroupCall &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 597b8b397..1cd1c7221 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2672,6 +2672,12 @@ class CliClient final : public Actor { send_request(td_api::make_object(as_call_id(args), "{}")); } else if (op == "gvcap") { send_request(td_api::make_object(as_chat_id(args))); + } else if (op == "svcdp") { + string group_call_id; + string participant_id; + get_args(args, group_call_id, participant_id); + send_request(td_api::make_object(as_chat_id(args), + as_message_sender(participant_id))); } else if (op == "cvc") { string chat_id; string title; @@ -2690,14 +2696,14 @@ class CliClient final : public Actor { op == "tgcesne")); } else if (op == "jgc") { string group_call_id; - string participant_alias; + string participant_id; string invite_hash; - get_args(args, group_call_id, participant_alias, invite_hash); + get_args(args, group_call_id, participant_id, invite_hash); vector> fingerprints; fingerprints.push_back(td_api::make_object("hash", "setup", "fingerprint")); fingerprints.push_back(td_api::make_object("h2", "s2", "fingerprint2")); send_request(td_api::make_object( - as_group_call_id(group_call_id), as_message_sender(participant_alias), + as_group_call_id(group_call_id), as_message_sender(participant_id), td_api::make_object("ufrag", "pwd", std::move(fingerprints)), group_call_source_, true, invite_hash)); } else if (op == "sgct") { From 5d5f950d2b72d0787ca7b7d957599613b822b24b Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 7 Apr 2021 22:49:09 +0300 Subject: [PATCH 219/281] Support themes in getPaymentForm. --- td/generate/scheme/td_api.tl | 9 +++++++-- td/telegram/Payments.cpp | 29 ++++++++++++++++++++++++----- td/telegram/Payments.h | 3 ++- td/telegram/Td.cpp | 3 ++- td/telegram/cli.cpp | 4 +++- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 5ff0062df..6a7a5c661 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -1349,6 +1349,11 @@ inputCredentialsGooglePay data:string = InputCredentials; //@description Stripe payment provider @publishable_key Stripe API publishable key @need_country True, if the user country must be provided @need_postal_code True, if the user ZIP/postal code must be provided @need_cardholder_name True, if the cardholder name must be provided paymentsProviderStripe publishable_key:string need_country:Bool need_postal_code:Bool need_cardholder_name:Bool = PaymentsProviderStripe; +//@description Theme colors for a payment form @background_color A color of the payment form background in the RGB24 format @text_color A color of text in the RGB24 format +//@hint_color A color of hints in the RGB24 format @link_color A color of links in the RGB24 format @button_color A color of thebuttons in the RGB24 format +//@button_text_color A color of text on the buttons in the RGB24 format +paymentFormTheme background_color:int32 text_color:int32 hint_color:int32 link_color:int32 button_color:int32 button_text_color:int32 = PaymentFormTheme; + //@description Contains information about an invoice payment form //@id The payment form identifier //@invoice Full information of the invoice @@ -4929,8 +4934,8 @@ closeSecretChat secret_chat_id:int32 = Ok; getChatEventLog chat_id:int53 query:string from_event_id:int64 limit:int32 filters:chatEventLogFilters user_ids:vector = ChatEvents; -//@description Returns an invoice payment form. This method should be called when the user presses inlineKeyboardButtonBuy @chat_id Chat identifier of the Invoice message @message_id Message identifier -getPaymentForm chat_id:int53 message_id:int53 = PaymentForm; +//@description Returns an invoice payment form. This method should be called when the user presses inlineKeyboardButtonBuy @chat_id Chat identifier of the Invoice message @message_id Message identifier @theme Preferred payment form theme +getPaymentForm chat_id:int53 message_id:int53 theme:paymentFormTheme = PaymentForm; //@description Validates the order information provided by a user and returns the available shipping options for a flexible invoice @chat_id Chat identifier of the Invoice message @message_id Message identifier @order_info The order information, provided by the user @allow_save True, if the order information can be saved validateOrderInfo chat_id:int53 message_id:int53 order_info:orderInfo allow_save:Bool = ValidatedOrderInfo; diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index f8382807b..10eedd2d2 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -266,7 +266,8 @@ class GetPaymentFormQuery : public Td::ResultHandler { explicit GetPaymentFormQuery(Promise> &&promise) : promise_(std::move(promise)) { } - void send(DialogId dialog_id, ServerMessageId server_message_id) { + void send(DialogId dialog_id, ServerMessageId server_message_id, + tl_object_ptr &&theme_parameters) { dialog_id_ = dialog_id; auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); if (input_peer == nullptr) { @@ -274,8 +275,11 @@ class GetPaymentFormQuery : public Td::ResultHandler { } int32 flags = 0; - send_query(G()->net_query_creator().create( - telegram_api::payments_getPaymentForm(flags, std::move(input_peer), server_message_id.get(), nullptr))); + if (theme_parameters != nullptr) { + flags |= telegram_api::payments_getPaymentForm::THEME_PARAMS_MASK; + } + send_query(G()->net_query_creator().create(telegram_api::payments_getPaymentForm( + flags, std::move(input_peer), server_message_id.get(), std::move(theme_parameters)))); } void on_result(uint64 id, BufferSlice packet) override { @@ -1134,9 +1138,24 @@ void answer_pre_checkout_query(Td *td, int64 pre_checkout_query_id, const string td->create_handler(std::move(promise))->send(pre_checkout_query_id, error_message); } -void get_payment_form(Td *td, FullMessageId full_message_id, Promise> &&promise) { +void get_payment_form(Td *td, FullMessageId full_message_id, const td_api::object_ptr &theme, + Promise> &&promise) { TRY_RESULT_PROMISE(promise, server_message_id, td->messages_manager_->get_invoice_message_id(full_message_id)); - td->create_handler(std::move(promise))->send(full_message_id.get_dialog_id(), server_message_id); + + tl_object_ptr theme_parameters; + if (theme != nullptr) { + theme_parameters = make_tl_object(string()); + theme_parameters->data_ = json_encode(json_object([&theme](auto &o) { + o("bg_color", theme->background_color_); + o("text_color", theme->text_color_); + o("hint_color", theme->hint_color_); + o("link_color", theme->link_color_); + o("button_color", theme->button_color_); + o("button_text_color", theme->button_text_color_); + })); + } + td->create_handler(std::move(promise)) + ->send(full_message_id.get_dialog_id(), server_message_id, std::move(theme_parameters)); } void validate_order_info(Td *td, FullMessageId full_message_id, tl_object_ptr order_info, diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index 1947c0fc3..ecfdce141 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -179,7 +179,8 @@ void answer_shipping_query(Td *td, int64 shipping_query_id, void answer_pre_checkout_query(Td *td, int64 pre_checkout_query_id, const string &error_message, Promise &&promise); -void get_payment_form(Td *td, FullMessageId full_message_id, Promise> &&promise); +void get_payment_form(Td *td, FullMessageId full_message_id, const td_api::object_ptr &theme, + Promise> &&promise); void validate_order_info(Td *td, FullMessageId full_message_id, tl_object_ptr order_info, bool allow_save, Promise> &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 5161a918a..52de29fa7 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -7736,7 +7736,8 @@ void Td::on_request(uint64 id, td_api::getBankCardInfo &request) { void Td::on_request(uint64 id, const td_api::getPaymentForm &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - get_payment_form(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, std::move(promise)); + get_payment_form(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, request.theme_, + std::move(promise)); } void Td::on_request(uint64 id, td_api::validateOrderInfo &request) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 1cd1c7221..91996b455 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1828,7 +1828,9 @@ class CliClient final : public Actor { string chat_id; string message_id; get_args(args, chat_id, message_id); - send_request(td_api::make_object(as_chat_id(chat_id), as_message_id(message_id))); + send_request(td_api::make_object( + as_chat_id(chat_id), as_message_id(message_id), + td_api::make_object(0, -1, 256, 65536, 123456789, 65535))); } else if (op == "voi") { string chat_id; string message_id; From fbb15a992556d21bc431955c9e0effb741dd6aea Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 7 Apr 2021 22:58:40 +0300 Subject: [PATCH 220/281] Remove invoice_chat_id/invoice_message_id from messagePaymentSuccessfulBot, because they are incompatible with inline mode. --- td/generate/scheme/td_api.tl | 6 +++--- td/telegram/MessageContent.cpp | 25 +++++++++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 6a7a5c661..3f9288640 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -1767,10 +1767,10 @@ messageGameScore game_message_id:int53 game_id:int64 score:int32 = MessageConten //@description A payment has been completed @invoice_chat_id Identifier of the chat, containing the corresponding invoice message; 0 if unknown @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for the price of the product @total_amount Total price for the product, in the smallest units of the currency messagePaymentSuccessful invoice_chat_id:int53 invoice_message_id:int53 currency:string total_amount:int53 = MessageContent; -//@description A payment has been completed; for bots only @invoice_chat_id Identifier of the chat, containing the corresponding invoice message; 0 if unknown @invoice_message_id Identifier of the message with the corresponding invoice; can be an identifier of a deleted message @currency Currency for price of the product +//@description A payment has been completed; for bots only @currency Currency for price of the product //@total_amount Total price for the product, in the smallest units of the currency @invoice_payload Invoice payload @shipping_option_id Identifier of the shipping option chosen by the user; may be empty if not applicable @order_info Information about the order; may be null //@telegram_payment_charge_id Telegram payment identifier @provider_payment_charge_id Provider payment identifier -messagePaymentSuccessfulBot invoice_chat_id:int53 invoice_message_id:int53 currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo telegram_payment_charge_id:string provider_payment_charge_id:string = MessageContent; +messagePaymentSuccessfulBot currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo telegram_payment_charge_id:string provider_payment_charge_id:string = MessageContent; //@description A contact has registered with Telegram messageContactRegistered = MessageContent; @@ -3840,7 +3840,7 @@ getMessage chat_id:int53 message_id:int53 = Message; //@description Returns information about a message, if it is available locally without sending network request. This is an offline request @chat_id Identifier of the chat the message belongs to @message_id Identifier of the message to get getMessageLocally chat_id:int53 message_id:int53 = Message; -//@description Returns information about a message that is replied by a given message. Also returns the pinned message, the game message, and the invoice message for messages of the types messagePinMessage, messageGameScore, and messagePaymentSuccessful/messagePaymentSuccessfulBot respectively +//@description Returns information about a message that is replied by a given message. Also returns the pinned message, the game message, and the invoice message for messages of the types messagePinMessage, messageGameScore, and messagePaymentSuccessful respectively //@chat_id Identifier of the chat the message belongs to @message_id Identifier of the message reply to which to get getRepliedMessage chat_id:int53 message_id:int53 = Message; diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index d8aa2cada..2b863c8ce 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -2582,6 +2582,10 @@ FullMessageId get_message_content_replied_message_id(DialogId dialog_id, const M return {dialog_id, static_cast(content)->game_message_id}; case MessageContentType::PaymentSuccessful: { auto *m = static_cast(content); + if (!m->invoice_message_id.is_valid()) { + return FullMessageId(); + } + auto reply_in_dialog_id = m->invoice_dialog_id.is_valid() ? m->invoice_dialog_id : dialog_id; return {reply_in_dialog_id, m->invoice_message_id}; } @@ -4357,7 +4361,10 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptrauth_manager_->is_bot()) << "Receive MessageActionPaymentSent in " << owner_dialog_id; + if (td->auth_manager_->is_bot()) { + LOG(ERROR) << "Receive MessageActionPaymentSent in " << owner_dialog_id; + break; + } if (!reply_to_message_id.is_valid()) { LOG(ERROR) << "Receive succesful payment message with " << reply_to_message_id << " in " << owner_dialog_id; reply_to_message_id = MessageId(); @@ -4367,14 +4374,13 @@ unique_ptr get_action_message_content(Td *td, tl_object_ptrcurrency_), payment_sent->total_amount_); } case telegram_api::messageActionPaymentSentMe::ID: { - LOG_IF(ERROR, !td->auth_manager_->is_bot()) << "Receive MessageActionPaymentSentMe in " << owner_dialog_id; - if (!reply_to_message_id.is_valid()) { - LOG(ERROR) << "Receive succesful payment message with " << reply_to_message_id << " in " << owner_dialog_id; - reply_to_message_id = MessageId(); + if (!td->auth_manager_->is_bot()) { + LOG(ERROR) << "Receive MessageActionPaymentSentMe in " << owner_dialog_id; + break; } auto payment_sent = move_tl_object_as(action); auto result = td::make_unique( - reply_in_dialog_id, reply_to_message_id, std::move(payment_sent->currency_), payment_sent->total_amount_); + DialogId(), MessageId(), std::move(payment_sent->currency_), payment_sent->total_amount_); result->invoice_payload = payment_sent->payload_.as_slice().str(); result->shipping_option_id = std::move(payment_sent->shipping_option_id_); result->order_info = get_order_info(std::move(payment_sent->info_)); @@ -4621,13 +4627,12 @@ tl_object_ptr get_message_content_object(const MessageCo } case MessageContentType::PaymentSuccessful: { const MessagePaymentSuccessful *m = static_cast(content); - auto invoice_dialog_id = m->invoice_dialog_id.is_valid() ? m->invoice_dialog_id : dialog_id; if (td->auth_manager_->is_bot()) { return make_tl_object( - invoice_dialog_id.get(), m->invoice_message_id.get(), m->currency, m->total_amount, m->invoice_payload, - m->shipping_option_id, get_order_info_object(m->order_info), m->telegram_payment_charge_id, - m->provider_payment_charge_id); + m->currency, m->total_amount, m->invoice_payload, m->shipping_option_id, + get_order_info_object(m->order_info), m->telegram_payment_charge_id, m->provider_payment_charge_id); } else { + auto invoice_dialog_id = m->invoice_dialog_id.is_valid() ? m->invoice_dialog_id : dialog_id; return make_tl_object(invoice_dialog_id.get(), m->invoice_message_id.get(), m->currency, m->total_amount); } From ad17a75f284ca504235692703d3fe1d7fae707ca Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 7 Apr 2021 23:35:09 +0300 Subject: [PATCH 221/281] Add source to add_new_dialog. --- td/telegram/MessagesManager.cpp | 27 ++++++++++++++------------- td/telegram/MessagesManager.h | 4 ++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index e09b82a24..2497479ee 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -6776,7 +6776,7 @@ void MessagesManager::on_update_channel_too_long(tl_object_ptr 0) { - d = add_dialog(dialog_id); + d = add_dialog(dialog_id, "on_update_channel_too_long"); CHECK(d != nullptr); CHECK(d->pts == pts); update_dialog_pos(d, "on_update_channel_too_long"); @@ -7402,7 +7402,7 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p return; } - d = add_dialog(dialog_id); + d = add_dialog(dialog_id, "add_pending_channel_update"); CHECK(d != nullptr); CHECK(d->pts == pts); update_dialog_pos(d, "add_pending_channel_update"); @@ -14451,7 +14451,7 @@ void MessagesManager::on_get_dialogs(FolderId folder_id, vectorpts == 0) { d->pts = 1; if (is_debug_message_op_enabled()) { @@ -31943,7 +31943,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(DialogId dialog Dialog *d = get_dialog_force(dialog_id); if (d == nullptr) { - d = add_dialog(dialog_id); + d = add_dialog(dialog_id, "add_message_to_dialog"); *need_update_dialog_pos = true; } else { CHECK(d->dialog_id == dialog_id); @@ -33795,7 +33795,7 @@ void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source return; } - d = add_dialog(dialog_id); + d = add_dialog(dialog_id, "force_create_dialog"); update_dialog_pos(d, "force_create_dialog"); if (dialog_id.get_type() == DialogType::SecretChat && !d->notification_settings.is_synchronized && @@ -33855,7 +33855,7 @@ void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source } } -MessagesManager::Dialog *MessagesManager::add_dialog(DialogId dialog_id) { +MessagesManager::Dialog *MessagesManager::add_dialog(DialogId dialog_id, const char *source) { LOG(DEBUG) << "Creating " << dialog_id; CHECK(!have_dialog(dialog_id)); @@ -33864,7 +33864,7 @@ MessagesManager::Dialog *MessagesManager::add_dialog(DialogId dialog_id) { auto r_value = G()->td_db()->get_dialog_db_sync()->get_dialog(dialog_id); if (r_value.is_ok()) { LOG(INFO) << "Synchronously loaded " << dialog_id << " from database"; - return add_new_dialog(parse_dialog(dialog_id, r_value.ok()), true); + return add_new_dialog(parse_dialog(dialog_id, r_value.ok()), true, source); } } @@ -33872,10 +33872,11 @@ MessagesManager::Dialog *MessagesManager::add_dialog(DialogId dialog_id) { d->dialog_id = dialog_id; invalidate_message_indexes(d.get()); - return add_new_dialog(std::move(d), false); + return add_new_dialog(std::move(d), false, source); } -MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&d, bool is_loaded_from_database) { +MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&d, bool is_loaded_from_database, + const char *source) { auto dialog_id = d->dialog_id; LOG_CHECK(is_inited_) << dialog_id << ' ' << is_loaded_from_database; switch (dialog_id.get_type()) { @@ -35054,7 +35055,7 @@ MessagesManager::Dialog *MessagesManager::on_load_dialog_from_database(DialogId } LOG(INFO) << "Add new " << dialog_id << " from database"; - return add_new_dialog(parse_dialog(dialog_id, value), true); + return add_new_dialog(parse_dialog(dialog_id, value), true, "on_load_dialog_from_database"); } const DialogFilter *MessagesManager::get_server_dialog_filter(DialogFilterId dialog_filter_id) const { @@ -35779,7 +35780,7 @@ void MessagesManager::on_get_channel_difference( bool need_update_dialog_pos = false; if (d == nullptr) { - d = add_dialog(dialog_id); + d = add_dialog(dialog_id, "on_get_channel_difference"); need_update_dialog_pos = true; } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 24ca71aac..3503529e1 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2404,9 +2404,9 @@ class MessagesManager : public Actor { MessageId get_message_id_by_random_id(Dialog *d, int64 random_id, const char *source); - Dialog *add_dialog(DialogId dialog_id); + Dialog *add_dialog(DialogId dialog_id, const char *source); - Dialog *add_new_dialog(unique_ptr &&d, bool is_loaded_from_database); + Dialog *add_new_dialog(unique_ptr &&d, bool is_loaded_from_database, const char *source); void fix_new_dialog(Dialog *d, unique_ptr &&last_database_message, MessageId last_database_message_id, int64 order, int32 last_clear_history_date, MessageId last_clear_history_message_id, From 5a7015b9feac50d85746862b2eb4244ee392308c Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 7 Apr 2021 23:43:24 +0300 Subject: [PATCH 222/281] Improve CHECK messages. --- td/telegram/MessagesManager.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 2497479ee..8ab872837 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -34337,11 +34337,13 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab << ", max_notification_message_id = " << d->max_notification_message_id; if (d->messages != nullptr) { - CHECK(d->messages->message_id == last_message_id); - LOG_CHECK(d->messages->left == nullptr) - << (d->messages->left->debug_source != nullptr ? d->messages->left->debug_source : "null"); - LOG_CHECK(d->messages->right == nullptr) - << (d->messages->right->debug_source != nullptr ? d->messages->right->debug_source : "null"); + auto get_debug_source = [](const unique_ptr &message) { + return message->debug_source != nullptr ? message->debug_source : "null"; + }; + LOG_CHECK(d->messages->message_id == last_message_id) + << d->messages->message_id << ' ' << last_message_id << ' ' << get_debug_source(d->messages); + LOG_CHECK(d->messages->left == nullptr) << get_debug_source(d->messages->left); + LOG_CHECK(d->messages->right == nullptr) << get_debug_source(d->messages->right); } } From 0a0c9a6f968d67be60ce84ec219577a426606897 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 00:39:41 +0300 Subject: [PATCH 223/281] Add optional source to get_dialog_force. --- td/telegram/MessagesManager.cpp | 358 ++++++++++++++++---------------- td/telegram/MessagesManager.h | 4 +- 2 files changed, 183 insertions(+), 179 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 8ab872837..3365cdeae 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -6732,7 +6732,7 @@ void MessagesManager::on_update_read_channel_messages_contents( DialogId dialog_id = DialogId(channel_id); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "on_update_read_channel_messages_contents"); if (d == nullptr) { LOG(INFO) << "Receive read channel messages contents update in unknown " << dialog_id; return; @@ -6746,7 +6746,7 @@ void MessagesManager::on_update_read_channel_messages_contents( void MessagesManager::on_update_read_message_comments(DialogId dialog_id, MessageId message_id, MessageId max_message_id, MessageId last_read_inbox_message_id, MessageId last_read_outbox_message_id) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "on_update_read_message_comments"); if (d == nullptr) { LOG(INFO) << "Ignore update of read message comments in unknown " << dialog_id << " in updateReadDiscussion"; return; @@ -6772,14 +6772,14 @@ void MessagesManager::on_update_channel_too_long(tl_object_ptr 0) { - d = add_dialog(dialog_id, "on_update_channel_too_long"); + d = add_dialog(dialog_id, "on_update_channel_too_long 5"); CHECK(d != nullptr); CHECK(d->pts == pts); - update_dialog_pos(d, "on_update_channel_too_long"); + update_dialog_pos(d, "on_update_channel_too_long 6"); } } @@ -6853,7 +6853,7 @@ void MessagesManager::update_message_interaction_info(FullMessageId full_message int32 forward_count, bool has_reply_info, tl_object_ptr &&reply_info) { auto dialog_id = full_message_id.get_dialog_id(); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "update_message_interaction_info"); if (d == nullptr) { return; } @@ -7108,7 +7108,7 @@ void MessagesManager::on_read_channel_inbox(ChannelId channel_id, MessageId max_ } DialogId dialog_id(channel_id); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, source); if (d == nullptr) { LOG(INFO) << "Receive read inbox in unknown " << dialog_id << " from " << source; return; @@ -7203,7 +7203,7 @@ void MessagesManager::on_update_delete_scheduled_messages(DialogId dialog_id, return; } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "on_update_delete_scheduled_messages"); if (d == nullptr) { LOG(INFO) << "Skip updateDeleteScheduledMessages in unknown " << dialog_id; return; @@ -7245,7 +7245,7 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th LOG(ERROR) << "Receive " << action << " in thread of " << top_thread_message_id << " in " << dialog_id; return; } - const Dialog *d = get_dialog_force(dialog_id); + const Dialog *d = get_dialog_force(dialog_id, "on_user_dialog_action"); if (d != nullptr && d->active_group_call_id.is_valid()) { auto group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, dialog_id); td_->group_call_manager_->on_user_speaking_in_group_call(group_call_id, typing_dialog_id, date); @@ -7391,7 +7391,7 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p // TODO need to save all updates that can change result of running queries not associated with pts (for example // getHistory) and apply them to result of these queries - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "add_pending_channel_update"); if (d == nullptr) { auto pts = load_channel_pts(dialog_id); if (pts > 0) { @@ -7505,7 +7505,7 @@ void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_p bool MessagesManager::is_old_channel_update(DialogId dialog_id, int32 new_pts) { CHECK(dialog_id.get_type() == DialogType::Channel); - const Dialog *d = get_dialog_force(dialog_id); + const Dialog *d = get_dialog_force(dialog_id, "is_old_channel_update"); return new_pts <= (d == nullptr ? load_channel_pts(dialog_id) : d->pts); } @@ -8144,7 +8144,7 @@ void MessagesManager::repair_dialog_action_bar(Dialog *d, const char *source) { } void MessagesManager::hide_dialog_action_bar(DialogId dialog_id) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "hide_dialog_action_bar"); if (d == nullptr) { return; } @@ -8173,7 +8173,7 @@ void MessagesManager::hide_dialog_action_bar(Dialog *d) { } void MessagesManager::remove_dialog_action_bar(DialogId dialog_id, Promise &&promise) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "remove_dialog_action_bar"); if (d == nullptr) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -8184,7 +8184,7 @@ void MessagesManager::remove_dialog_action_bar(DialogId dialog_id, Promise if (dialog_id.get_type() == DialogType::SecretChat) { dialog_id = DialogId(td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id())); - d = get_dialog_force(dialog_id); + d = get_dialog_force(dialog_id, "remove_dialog_action_bar 2"); if (d == nullptr) { return promise.set_error(Status::Error(3, "Chat with the user not found")); } @@ -8308,7 +8308,7 @@ bool MessagesManager::can_report_dialog(DialogId dialog_id) const { void MessagesManager::report_dialog(DialogId dialog_id, const vector &message_ids, ReportReason &&reason, Promise &&promise) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "report_dialog"); if (d == nullptr) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -8324,7 +8324,7 @@ void MessagesManager::report_dialog(DialogId dialog_id, const vector // report from action bar if (dialog_id.get_type() == DialogType::SecretChat) { auto user_dialog_id = DialogId(td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id())); - user_d = get_dialog_force(user_dialog_id); + user_d = get_dialog_force(user_dialog_id, "report_dialog 2"); if (user_d == nullptr) { return promise.set_error(Status::Error(3, "Chat with the user not found")); } @@ -8368,7 +8368,7 @@ void MessagesManager::report_dialog(DialogId dialog_id, const vector void MessagesManager::report_dialog_photo(DialogId dialog_id, FileId file_id, ReportReason &&reason, Promise &&promise) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "report_dialog_photo"); if (d == nullptr) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -8405,7 +8405,7 @@ void MessagesManager::on_get_peer_settings(DialogId dialog_id, need_phone_number_privacy_exception); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "on_get_peer_settings"); if (d == nullptr) { return; } @@ -8568,7 +8568,7 @@ void MessagesManager::fix_dialog_action_bar(Dialog *d) { void MessagesManager::get_dialog_statistics_url(DialogId dialog_id, const string ¶meters, bool is_dark, Promise> &&promise) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_dialog_statistics_url"); if (d == nullptr) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -8584,7 +8584,7 @@ void MessagesManager::get_dialog_statistics_url(DialogId dialog_id, const string } Result MessagesManager::get_login_button_url(DialogId dialog_id, MessageId message_id, int32 button_id) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_login_button_url"); if (d == nullptr) { return Status::Error(3, "Chat not found"); } @@ -10109,7 +10109,7 @@ void MessagesManager::delete_messages_from_updates(const vector &mess void MessagesManager::delete_dialog_messages(DialogId dialog_id, const vector &message_ids, bool from_updates, bool skip_update_for_not_found_messages, const char *source) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "delete_dialog_messages"); if (d == nullptr) { LOG(INFO) << "Ignore deleteChannelMessages for unknown " << dialog_id << " from " << source; CHECK(from_updates); @@ -10148,7 +10148,7 @@ void MessagesManager::delete_dialog_messages(DialogId dialog_id, const vector &message_ids, bool is_pin) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "update_dialog_pinned_messages_from_updates"); if (d == nullptr) { LOG(INFO) << "Ignore updatePinnedMessages for unknown " << dialog_id; return; @@ -10377,7 +10377,7 @@ void MessagesManager::delete_messages(DialogId dialog_id, const vectorclose_flag()) { return promise.set_error(Status::Error(500, "Request aborted")); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "delete_messages"); if (d == nullptr) { return promise.set_error(Status::Error(6, "Chat is not found")); } @@ -10547,7 +10547,7 @@ void MessagesManager::delete_messages_from_server(DialogId dialog_id, vector random_ids; - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "delete_messages_from_server"); CHECK(d != nullptr); for (auto &message_id : message_ids) { auto *m = get_message(d, message_id); @@ -10616,7 +10616,7 @@ void MessagesManager::delete_dialog_history(DialogId dialog_id, bool remove_from LOG(INFO) << "Receive deleteChatHistory request to delete all messages in " << dialog_id << ", remove_from_chat_list is " << remove_from_dialog_list << ", revoke is " << revoke; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "delete_dialog_history"); if (d == nullptr) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -10868,7 +10868,7 @@ void MessagesManager::delete_dialog_messages_from_user(DialogId dialog_id, UserI LOG(INFO) << "Receive deleteChatMessagesFromUser request to delete all messages in " << dialog_id << " from the user " << user_id; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "delete_dialog_messages_from_user"); if (d == nullptr) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -11115,7 +11115,7 @@ void MessagesManager::delete_all_dialog_messages(Dialog *d, bool remove_from_dia void MessagesManager::on_dialog_deleted(DialogId dialog_id, Promise &&promise) { LOG(INFO) << "Delete " << dialog_id; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "on_dialog_deleted"); if (d == nullptr) { return promise.set_value(Unit()); } @@ -11151,7 +11151,7 @@ void MessagesManager::read_all_dialog_mentions(DialogId dialog_id, Promise return promise.set_error(Status::Error(3, "Method is not available for bots")); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "read_all_dialog_mentions"); if (d == nullptr) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -11428,7 +11428,7 @@ void MessagesManager::read_history_inbox(DialogId dialog_id, MessageId max_messa return; } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "read_history_inbox"); if (d != nullptr) { if (d->need_repair_channel_server_unread_count) { d->need_repair_channel_server_unread_count = false; @@ -11517,7 +11517,7 @@ void MessagesManager::read_history_outbox(DialogId dialog_id, MessageId max_mess return; } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "read_history_outbox"); if (d != nullptr) { if (!max_message_id.is_valid()) { LOG(ERROR) << "Receive read outbox update in " << dialog_id << " with " << max_message_id; @@ -11883,7 +11883,7 @@ void MessagesManager::set_dialog_max_unavailable_message_id(DialogId dialog_id, bool from_update, const char *source) { CHECK(!max_unavailable_message_id.is_scheduled()); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, source); if (d != nullptr) { if (max_unavailable_message_id > d->last_new_message_id && from_update) { if (d->last_new_message_id.is_valid()) { @@ -12443,7 +12443,7 @@ void MessagesManager::init() { } else { DialogId dialog_id(r_dialog_id.ok()); - const Dialog *d = get_dialog_force(dialog_id); + const Dialog *d = get_dialog_force(dialog_id, "init"); if (d != nullptr) { LOG(INFO) << "Loaded sponsored " << dialog_id; add_sponsored_dialog(d, r_source.move_as_ok()); @@ -12816,8 +12816,8 @@ void MessagesManager::ttl_db_on_result(Resultserver_time()); } @@ -12963,7 +12963,7 @@ void MessagesManager::read_secret_chat_outbox(SecretChatId secret_chat_id, int32 return; } auto dialog_id = DialogId(secret_chat_id); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "read_secret_chat_outbox"); if (d == nullptr) { return; } @@ -13003,7 +13003,7 @@ void MessagesManager::read_secret_chat_outbox_inner(DialogId dialog_id, int32 up void MessagesManager::open_secret_message(SecretChatId secret_chat_id, int64 random_id, Promise<> promise) { promise.set_value(Unit()); // TODO: set after event is saved DialogId dialog_id(secret_chat_id); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "open_secret_message"); if (d == nullptr) { LOG(ERROR) << "Ignore opening secret chat message in unknown " << dialog_id; return; @@ -13026,7 +13026,7 @@ void MessagesManager::open_secret_message(SecretChatId secret_chat_id, int64 ran void MessagesManager::on_update_secret_chat_state(SecretChatId secret_chat_id, SecretChatState state) { if (state == SecretChatState::Closed && !td_->auth_manager_->is_bot()) { DialogId dialog_id(secret_chat_id); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "on_update_secret_chat_state"); if (d != nullptr) { if (d->new_secret_chat_notification_id.is_valid()) { remove_new_secret_chat_notification(d, true); @@ -13063,7 +13063,7 @@ void MessagesManager::on_get_secret_message(SecretChatId secret_chat_id, UserId message_info.random_id = message->random_id_; message_info.ttl = message->ttl_; - Dialog *d = get_dialog_force(message_info.dialog_id); + Dialog *d = get_dialog_force(message_info.dialog_id, "on_get_secret_message"); if (d == nullptr) { LOG(ERROR) << "Ignore secret message in unknown " << message_info.dialog_id; pending_secret_message->success_promise.set_error(Status::Error(500, "Chat not found")); @@ -13153,7 +13153,7 @@ void MessagesManager::on_secret_chat_screenshot_taken(SecretChatId secret_chat_i message_info.flags = MESSAGE_FLAG_HAS_FROM_ID; message_info.content = create_screenshot_taken_message_content(); - Dialog *d = get_dialog_force(message_info.dialog_id); + Dialog *d = get_dialog_force(message_info.dialog_id, "on_secret_chat_screenshot_taken"); if (d == nullptr) { LOG(ERROR) << "Ignore secret message in unknown " << message_info.dialog_id; pending_secret_message->success_promise.set_error(Status::Error(500, "Chat not found")); @@ -13187,7 +13187,7 @@ void MessagesManager::on_secret_chat_ttl_changed(SecretChatId secret_chat_id, Us message_info.flags = MESSAGE_FLAG_HAS_FROM_ID; message_info.content = create_chat_set_ttl_message_content(ttl); - Dialog *d = get_dialog_force(message_info.dialog_id); + Dialog *d = get_dialog_force(message_info.dialog_id, "on_secret_chat_ttl_changed"); if (d == nullptr) { LOG(ERROR) << "Ignore secret message in unknown " << message_info.dialog_id; pending_secret_message->success_promise.set_error(Status::Error(500, "Chat not found")); @@ -14447,7 +14447,7 @@ void MessagesManager::on_get_dialogs(FolderId folder_id, vector> MessagesManager::get_dialogs(DialogListId dia for (auto &pinned_dialog : list.pinned_dialogs_) { if (offset < pinned_dialog) { auto dialog_id = pinned_dialog.get_dialog_id(); - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "get_dialogs"); if (d == nullptr) { LOG(ERROR) << "Failed to load pinned " << dialog_id << " from " << dialog_list_id; if (dialog_id.get_type() != DialogType::SecretChat) { @@ -15850,7 +15850,7 @@ void MessagesManager::on_get_dialogs_from_database(FolderId folder_id, int32 lim size_t dialogs_skipped = 0; for (auto &dialog : dialogs.dialogs) { - Dialog *d = on_load_dialog_from_database(DialogId(), std::move(dialog)); + Dialog *d = on_load_dialog_from_database(DialogId(), std::move(dialog), "on_get_dialogs_from_database"); if (d == nullptr) { dialogs_skipped++; continue; @@ -16550,7 +16550,7 @@ void MessagesManager::block_message_sender_from_replies(MessageId message_id, bo bool delete_all_messages, bool report_spam, Promise &&promise) { auto dialog_id = DialogId(ContactsManager::get_replies_bot_user_id()); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "block_message_sender_from_replies"); if (d == nullptr) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -16748,7 +16748,7 @@ const MessagesManager::Message *MessagesManager::get_message(FullMessageId full_ } MessagesManager::Message *MessagesManager::get_message_force(FullMessageId full_message_id, const char *source) { - Dialog *d = get_dialog_force(full_message_id.get_dialog_id()); + Dialog *d = get_dialog_force(full_message_id.get_dialog_id(), source); if (d == nullptr) { return nullptr; } @@ -16796,7 +16796,7 @@ void MessagesManager::get_message_force_from_server(Dialog *d, MessageId message } void MessagesManager::get_message(FullMessageId full_message_id, Promise &&promise) { - Dialog *d = get_dialog_force(full_message_id.get_dialog_id()); + Dialog *d = get_dialog_force(full_message_id.get_dialog_id(), "get_message"); if (d == nullptr) { return promise.set_error(Status::Error(6, "Chat not found")); } @@ -16807,7 +16807,7 @@ void MessagesManager::get_message(FullMessageId full_message_id, Promise & FullMessageId MessagesManager::get_replied_message(DialogId dialog_id, MessageId message_id, bool force, Promise &&promise) { LOG(INFO) << "Get replied message to " << message_id << " in " << dialog_id; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_replied_message"); if (d == nullptr) { promise.set_error(Status::Error(6, "Chat not found")); return FullMessageId(); @@ -16838,7 +16838,7 @@ FullMessageId MessagesManager::get_replied_message(DialogId dialog_id, MessageId } force_create_dialog(dialog_id, "get_replied_message"); - d = get_dialog_force(dialog_id); + d = get_dialog_force(dialog_id, "get_replied_message"); if (d == nullptr) { promise.set_error(Status::Error(500, "Chat with replied message not found")); return {}; @@ -16885,7 +16885,7 @@ Result MessagesManager::get_top_thread_full_message_id(DialogId d void MessagesManager::get_message_thread(DialogId dialog_id, MessageId message_id, Promise &&promise) { LOG(INFO) << "Get message thread from " << message_id << " in " << dialog_id; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_message_thread"); if (d == nullptr) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -17005,7 +17005,7 @@ void MessagesManager::on_get_discussion_message(DialogId dialog_id, MessageId me if (G()->close_flag()) { return promise.set_error(Status::Error(500, "Request aborted")); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "on_get_discussion_message"); CHECK(d != nullptr); auto m = get_message_force(d, message_id, "on_get_discussion_message"); @@ -17038,10 +17038,10 @@ void MessagesManager::on_get_discussion_message(DialogId dialog_id, MessageId me } if (expected_dialog_id != dialog_id && m->reply_info.is_comment && !result.message_ids.empty() && m->linked_top_thread_message_id != result.message_ids.back()) { - auto linked_d = get_dialog_force(expected_dialog_id); + auto linked_d = get_dialog_force(expected_dialog_id, "on_get_discussion_message 2"); CHECK(linked_d != nullptr); auto linked_message_id = result.message_ids.back(); - Message *linked_m = get_message_force(linked_d, linked_message_id, "on_get_discussion_message"); + Message *linked_m = get_message_force(linked_d, linked_message_id, "on_get_discussion_message 3"); CHECK(linked_m != nullptr && linked_m->message_id.is_server()); if (linked_m->top_thread_message_id == linked_m->message_id && is_active_message_reply_info(expected_dialog_id, linked_m->reply_info)) { @@ -17145,7 +17145,7 @@ void MessagesManager::reload_dialog_info_full(DialogId dialog_id) { } MessageId MessagesManager::get_dialog_pinned_message(DialogId dialog_id, Promise &&promise) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_dialog_pinned_message"); if (d == nullptr) { promise.set_error(Status::Error(6, "Chat not found")); return MessageId(); @@ -17176,7 +17176,7 @@ MessageId MessagesManager::get_dialog_pinned_message(DialogId dialog_id, Promise void MessagesManager::get_callback_query_message(DialogId dialog_id, MessageId message_id, int64 callback_query_id, Promise &&promise) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_callback_query_message"); if (d == nullptr) { return promise.set_error(Status::Error(6, "Chat not found")); } @@ -17192,7 +17192,7 @@ void MessagesManager::get_callback_query_message(DialogId dialog_id, MessageId m } bool MessagesManager::get_messages(DialogId dialog_id, const vector &message_ids, Promise &&promise) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_messages"); if (d == nullptr) { promise.set_error(Status::Error(6, "Chat not found")); return false; @@ -17330,7 +17330,7 @@ bool MessagesManager::is_message_edited_recently(FullMessageId full_message_id, Result> MessagesManager::get_message_link(FullMessageId full_message_id, bool for_group, bool for_comment) { auto dialog_id = full_message_id.get_dialog_id(); - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "get_message_link"); if (d == nullptr) { return Status::Error(400, "Chat not found"); } @@ -17423,7 +17423,7 @@ Result> MessagesManager::get_message_link(FullMessageId string MessagesManager::get_message_embedding_code(FullMessageId full_message_id, bool for_group, Promise &&promise) { auto dialog_id = full_message_id.get_dialog_id(); - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "get_message_embedding_code"); if (d == nullptr) { promise.set_error(Status::Error(400, "Chat not found")); return {}; @@ -17686,7 +17686,7 @@ void MessagesManager::on_get_message_link_dialog(MessageLinkInfo &&info, Promise force_create_dialog(dialog_id, "on_get_message_link_dialog", true); } } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "on_get_message_link_dialog"); if (d == nullptr) { return promise.set_error(Status::Error(500, "Chat not found")); } @@ -17735,7 +17735,7 @@ void MessagesManager::on_get_message_link_discussion_message(MessageLinkInfo &&i CHECK(comment_dialog_id.is_valid()); info.comment_dialog_id = comment_dialog_id; - Dialog *d = get_dialog_force(comment_dialog_id); + Dialog *d = get_dialog_force(comment_dialog_id, "on_get_message_link_discussion_message"); if (d == nullptr) { return promise.set_error(Status::Error(500, "Chat not found")); } @@ -17828,7 +17828,7 @@ Result> MessagesManager::create_dialog_filter(DialogFil if (!dialog_id.is_valid()) { return Status::Error(400, "Invalid chat identifier specified"); } - const Dialog *d = get_dialog_force(dialog_id); + const Dialog *d = get_dialog_force(dialog_id, "create_dialog_filter"); if (d == nullptr) { return Status::Error(400, "Chat not found"); } @@ -18461,7 +18461,7 @@ Status MessagesManager::delete_dialog_reply_markup(DialogId dialog_id, MessageId return Status::Error(6, "Invalid message identifier specified"); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "delete_dialog_reply_markup"); if (d == nullptr) { return Status::Error(6, "Chat not found"); } @@ -18513,7 +18513,7 @@ Status MessagesManager::set_dialog_draft_message(DialogId dialog_id, MessageId t return Status::Error(6, "Bots can't change chat draft message"); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "set_dialog_draft_message"); if (d == nullptr) { return Status::Error(6, "Chat not found"); } @@ -18648,7 +18648,7 @@ Status MessagesManager::toggle_dialog_is_pinned(DialogListId dialog_list_id, Dia return Status::Error(6, "Bots can't change chat pin state"); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "toggle_dialog_is_pinned"); if (d == nullptr) { return Status::Error(6, "Chat not found"); } @@ -18785,7 +18785,7 @@ Status MessagesManager::set_pinned_dialogs(DialogListId dialog_list_id, vectoris_blocked) { return Status::OK(); @@ -19116,7 +19116,7 @@ void MessagesManager::toggle_dialog_is_blocked_on_server(DialogId dialog_id, boo Status MessagesManager::toggle_dialog_silent_send_message(DialogId dialog_id, bool silent_send_message) { CHECK(!td_->auth_manager_->is_bot()); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "toggle_dialog_silent_send_message"); if (d == nullptr) { return Status::Error(6, "Chat not found"); } @@ -19198,7 +19198,7 @@ void MessagesManager::on_updated_dialog_notification_settings(DialogId dialog_id } Status MessagesManager::set_dialog_client_data(DialogId dialog_id, string &&client_data) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "set_dialog_client_data"); if (d == nullptr) { return Status::Error(6, "Chat not found"); } @@ -19259,7 +19259,7 @@ void MessagesManager::create_dialog(DialogId dialog_id, bool force, Promiseauth_manager_->is_bot() || dialog_id.get_type() == DialogType::SecretChat) { force_create_dialog(dialog_id, "create dialog"); } else { - const Dialog *d = get_dialog_force(dialog_id); + const Dialog *d = get_dialog_force(dialog_id, "create_dialog"); if (!is_dialog_inited(d)) { return send_get_dialog_query(dialog_id, std::move(promise), 0, "create_dialog"); } @@ -19392,7 +19392,7 @@ DialogId MessagesManager::migrate_dialog_to_megagroup(DialogId dialog_id, Promis } auto new_dialog_id = DialogId(channel_id); - Dialog *d = get_dialog_force(new_dialog_id); + Dialog *d = get_dialog_force(new_dialog_id, "migrate_dialog_to_megagroup"); if (d == nullptr) { d = add_dialog(new_dialog_id, "migrate_dialog_to_megagroup"); if (d->pts == 0) { @@ -19409,7 +19409,7 @@ DialogId MessagesManager::migrate_dialog_to_megagroup(DialogId dialog_id, Promis } Status MessagesManager::open_dialog(DialogId dialog_id) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "open_dialog"); if (d == nullptr) { return Status::Error(3, "Chat not found"); } @@ -19419,7 +19419,7 @@ Status MessagesManager::open_dialog(DialogId dialog_id) { } Status MessagesManager::close_dialog(DialogId dialog_id) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "close_dialog"); if (d == nullptr) { return Status::Error(3, "Chat not found"); } @@ -19436,7 +19436,7 @@ Status MessagesManager::view_messages(DialogId dialog_id, MessageId top_thread_m const vector &message_ids, bool force_read) { CHECK(!td_->auth_manager_->is_bot()); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "view_messages"); if (d == nullptr) { return Status::Error(3, "Chat not found"); } @@ -19582,7 +19582,7 @@ Status MessagesManager::view_messages(DialogId dialog_id, MessageId top_thread_m Status MessagesManager::open_message_content(FullMessageId full_message_id) { auto dialog_id = full_message_id.get_dialog_id(); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "open_message_content"); if (d == nullptr) { return Status::Error(3, "Chat not found"); } @@ -20182,7 +20182,7 @@ const ScopeNotificationSettings *MessagesManager::get_scope_notification_setting } DialogNotificationSettings *MessagesManager::get_dialog_notification_settings(DialogId dialog_id, bool force) { - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "get_dialog_notification_settings"); if (d == nullptr) { return nullptr; } @@ -20380,7 +20380,7 @@ tl_object_ptr MessagesManager::get_dialog_history(DialogId dia return nullptr; } - const Dialog *d = get_dialog_force(dialog_id); + const Dialog *d = get_dialog_force(dialog_id, "get_dialog_history"); if (d == nullptr) { promise.set_error(Status::Error(6, "Chat not found")); return nullptr; @@ -20808,7 +20808,7 @@ std::pair> MessagesManager::get_message_thread_histo CHECK(0 < limit && limit <= MAX_GET_HISTORY); CHECK(-limit < offset && offset <= 0); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_message_thread_history"); if (d == nullptr) { promise.set_error(Status::Error(6, "Chat not found")); return {}; @@ -20992,7 +20992,7 @@ std::pair> MessagesManager::search_dialog_messages( } from_message_id = from_message_id.get_next_server_message_id(); - const Dialog *d = get_dialog_force(dialog_id); + const Dialog *d = get_dialog_force(dialog_id, "search_dialog_messages"); if (d == nullptr) { promise.set_error(Status::Error(6, "Chat not found")); return result; @@ -21242,7 +21242,7 @@ std::pair> MessagesManager::search_dialog_recent_locati limit = MAX_SEARCH_MESSAGES; } - const Dialog *d = get_dialog_force(dialog_id); + const Dialog *d = get_dialog_force(dialog_id, "search_dialog_recent_location_messages"); if (d == nullptr) { promise.set_error(Status::Error(6, "Chat not found")); return result; @@ -21779,8 +21779,9 @@ void MessagesManager::on_messages_db_fts_result(Result resu res.reserve(fts_result.messages.size()); for (auto &message : fts_result.messages) { - auto m = on_get_message_from_database(message.dialog_id, get_dialog_force(message.dialog_id), message.data, false, - "on_messages_db_fts_result"); + auto m = on_get_message_from_database(message.dialog_id, + get_dialog_force(message.dialog_id, "on_messages_db_fts_result"), + message.data, false, "on_messages_db_fts_result"); if (m != nullptr) { res.push_back(FullMessageId(message.dialog_id, m->message_id)); } @@ -21813,8 +21814,9 @@ void MessagesManager::on_messages_db_calls_result(Result res.reserve(calls_result.messages.size()); for (auto &message : calls_result.messages) { - auto m = on_get_message_from_database(message.dialog_id, get_dialog_force(message.dialog_id), message.data, false, - "on_messages_db_calls_result"); + auto m = on_get_message_from_database(message.dialog_id, + get_dialog_force(message.dialog_id, "on_messages_db_calls_result"), + message.data, false, "on_messages_db_calls_result"); if (m != nullptr && first_db_message_id <= m->message_id) { res.push_back(FullMessageId(message.dialog_id, m->message_id)); @@ -21895,7 +21897,7 @@ std::pair> MessagesManager::search_messages( } int64 MessagesManager::get_dialog_message_by_date(DialogId dialog_id, int32 date, Promise &&promise) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_dialog_message_by_date"); if (d == nullptr) { promise.set_error(Status::Error(5, "Chat not found")); return 0; @@ -22068,7 +22070,7 @@ int32 MessagesManager::get_dialog_message_count(DialogId dialog_id, MessageSearc LOG(INFO) << "Get " << (return_local ? "local " : "") << "number of messages in " << dialog_id << " filtered by " << filter; - const Dialog *d = get_dialog_force(dialog_id); + const Dialog *d = get_dialog_force(dialog_id, "get_dialog_message_count"); if (d == nullptr) { promise.set_error(Status::Error(6, "Chat not found")); return -1; @@ -22496,7 +22498,7 @@ vector MessagesManager::get_dialog_scheduled_messages(DialogId dialog return {}; } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_dialog_scheduled_messages"); if (d == nullptr) { promise.set_error(Status::Error(6, "Chat not found")); return {}; @@ -22657,7 +22659,7 @@ MessagesManager::FoundMessages MessagesManager::get_message_public_forwards(Full } auto dialog_id = full_message_id.get_dialog_id(); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_message_public_forwards"); if (d == nullptr) { promise.set_error(Status::Error(5, "Chat not found")); return {}; @@ -23526,7 +23528,7 @@ Result MessagesManager::send_message(DialogId dialog_id, MessageId to return Status::Error(5, "Can't send message without content"); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "send_message"); if (d == nullptr) { return Status::Error(5, "Chat not found"); } @@ -23603,7 +23605,7 @@ Result MessagesManager::process_input_message_content( } DialogId from_dialog_id(input_message->from_chat_id_); - Dialog *from_dialog = get_dialog_force(from_dialog_id); + Dialog *from_dialog = get_dialog_force(from_dialog_id, "send_message copy"); if (from_dialog == nullptr) { return Status::Error(400, "Chat to copy message from not found"); } @@ -23764,7 +23766,7 @@ Result> MessagesManager::send_message_group( return Status::Error(4, "There are no messages to send"); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "send_message_group"); if (d == nullptr) { return Status::Error(5, "Chat not found"); } @@ -24404,7 +24406,7 @@ Result MessagesManager::send_bot_start_message(UserId bot_user_id, Di TRY_RESULT(bot_data, td_->contacts_manager_->get_bot_data(bot_user_id)); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "send_bot_start_message"); if (d == nullptr) { return Status::Error(5, "Chat not found"); } @@ -24560,7 +24562,7 @@ Result MessagesManager::send_inline_query_result_message(DialogId dia bool hide_via_bot) { LOG(INFO) << "Begin to send inline query result message to " << dialog_id << " in reply to " << reply_to_message_id; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "send_inline_query_result_message"); if (d == nullptr) { return Status::Error(5, "Chat not found"); } @@ -24957,7 +24959,7 @@ void MessagesManager::edit_message_text(FullMessageId full_message_id, LOG(INFO) << "Begin to edit text of " << full_message_id; auto dialog_id = full_message_id.get_dialog_id(); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "edit_message_text"); if (d == nullptr) { return promise.set_error(Status::Error(5, "Chat not found")); } @@ -25012,7 +25014,7 @@ void MessagesManager::edit_message_live_location(FullMessageId full_message_id, int32 proximity_alert_radius, Promise &&promise) { LOG(INFO) << "Begin to edit live location of " << full_message_id; auto dialog_id = full_message_id.get_dialog_id(); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "edit_message_live_location"); if (d == nullptr) { return promise.set_error(Status::Error(5, "Chat not found")); } @@ -25175,7 +25177,7 @@ void MessagesManager::edit_message_media(FullMessageId full_message_id, LOG(INFO) << "Begin to edit media of " << full_message_id; auto dialog_id = full_message_id.get_dialog_id(); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "edit_message_media"); if (d == nullptr) { return promise.set_error(Status::Error(5, "Chat not found")); } @@ -25252,7 +25254,7 @@ void MessagesManager::edit_message_caption(FullMessageId full_message_id, LOG(INFO) << "Begin to edit caption of " << full_message_id; auto dialog_id = full_message_id.get_dialog_id(); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "edit_message_caption"); if (d == nullptr) { return promise.set_error(Status::Error(5, "Chat not found")); } @@ -25304,7 +25306,7 @@ void MessagesManager::edit_message_reply_markup(FullMessageId full_message_id, LOG(INFO) << "Begin to edit reply markup of " << full_message_id; auto dialog_id = full_message_id.get_dialog_id(); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "edit_message_reply_markup"); if (d == nullptr) { return promise.set_error(Status::Error(5, "Chat not found")); } @@ -25533,7 +25535,7 @@ void MessagesManager::edit_message_scheduling_state( LOG(INFO) << "Begin to reschedule " << full_message_id << " to " << schedule_date; auto dialog_id = full_message_id.get_dialog_id(); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "edit_message_scheduling_state"); if (d == nullptr) { return promise.set_error(Status::Error(5, "Chat not found")); } @@ -25713,7 +25715,7 @@ void MessagesManager::set_game_score(FullMessageId full_message_id, bool edit_me LOG(INFO) << "Begin to set game score of " << user_id << " in " << full_message_id; auto dialog_id = full_message_id.get_dialog_id(); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "set_game_score"); if (d == nullptr) { return promise.set_error(Status::Error(5, "Chat not found")); } @@ -25769,7 +25771,7 @@ int64 MessagesManager::get_game_high_scores(FullMessageId full_message_id, UserI LOG(INFO) << "Begin to get game high scores of " << user_id << " in " << full_message_id; auto dialog_id = full_message_id.get_dialog_id(); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_game_high_scores"); if (d == nullptr) { promise.set_error(Status::Error(5, "Chat not found")); return 0; @@ -26139,7 +26141,7 @@ Result> MessagesManager::forward_messages(DialogId to_dialog_i return Status::Error(4, "There are no messages to forward"); } - Dialog *from_dialog = get_dialog_force(from_dialog_id); + Dialog *from_dialog = get_dialog_force(from_dialog_id, "forward_messages from"); if (from_dialog == nullptr) { return Status::Error(5, "Chat to forward messages from not found"); } @@ -26150,7 +26152,7 @@ Result> MessagesManager::forward_messages(DialogId to_dialog_i return Status::Error(7, "Can't forward messages from secret chats"); } - Dialog *to_dialog = get_dialog_force(to_dialog_id); + Dialog *to_dialog = get_dialog_force(to_dialog_id, "forward_messages to"); if (to_dialog == nullptr) { return Status::Error(5, "Chat to forward messages to not found"); } @@ -26444,7 +26446,7 @@ Result> MessagesManager::resend_messages(DialogId dialog_id, v return Status::Error(4, "There are no messages to resend"); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "resend_messages"); if (d == nullptr) { return Status::Error(400, "Chat not found"); } @@ -26565,7 +26567,7 @@ Status MessagesManager::send_screenshot_taken_notification_message(DialogId dial LOG(INFO) << "Begin to send notification about taken screenshot in " << dialog_id; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "send_screenshot_taken_notification_message"); if (d == nullptr) { return Status::Error(5, "Chat not found"); } @@ -26648,7 +26650,7 @@ Result MessagesManager::add_local_message( } LOG(INFO) << "Begin to add local message to " << dialog_id << " in reply to " << reply_to_message_id; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "add_local_message"); if (d == nullptr) { return Status::Error(5, "Chat not found"); } @@ -27112,7 +27114,7 @@ Result MessagesManager::get_messag return Status::Error("Ignore notification sent to bot"); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "get_message_push_notification_info"); if (d == nullptr) { return Status::Error(406, "Ignore notification in unknown chat"); } @@ -27171,10 +27173,10 @@ Result MessagesManager::get_messag if (contains_mention) { if (sender_user_id.is_valid()) { settings_dialog_id = DialogId(sender_user_id); - settings_dialog = get_dialog_force(settings_dialog_id); + settings_dialog = get_dialog_force(settings_dialog_id, "get_message_push_notification_info 2"); } else if (sender_dialog_id.is_valid()) { settings_dialog_id = sender_dialog_id; - settings_dialog = get_dialog_force(settings_dialog_id); + settings_dialog = get_dialog_force(settings_dialog_id, "get_message_push_notification_info 3"); } } @@ -27253,7 +27255,7 @@ MessagesManager::MessageNotificationGroup MessagesManager::get_message_notificat auto r_value = G()->td_db()->get_dialog_db_sync()->get_notification_group(group_id); if (r_value.is_ok()) { VLOG(notifications) << "Loaded " << r_value.ok() << " from database by " << group_id; - d = get_dialog_force(r_value.ok().dialog_id); + d = get_dialog_force(r_value.ok().dialog_id, "get_message_notification_group_force"); } else { CHECK(r_value.error().message() == "Not found"); VLOG(notifications) << "Failed to load " << group_id << " from database"; @@ -27555,7 +27557,7 @@ vector MessagesManager::get_message_notification_group_key vector result; for (auto &group_key : group_keys) { CHECK(group_key.dialog_id.is_valid()); - const Dialog *d = get_dialog_force(group_key.dialog_id); + const Dialog *d = get_dialog_force(group_key.dialog_id, "get_message_notification_group_keys_from_database"); if (d == nullptr || (d->message_notification_group.group_id != group_key.group_id && d->mention_notification_group.group_id != group_key.group_id)) { continue; @@ -27768,7 +27770,7 @@ void MessagesManager::on_get_message_notifications_from_database(DialogId dialog void MessagesManager::remove_message_notification(DialogId dialog_id, NotificationGroupId group_id, NotificationId notification_id) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "remove_message_notification"); if (d == nullptr) { LOG(ERROR) << "Can't find " << dialog_id; return; @@ -27815,7 +27817,7 @@ void MessagesManager::remove_message_notification(DialogId dialog_id, Notificati void MessagesManager::remove_message_notifications_by_message_ids(DialogId dialog_id, const vector &message_ids) { VLOG(notifications) << "Trying to remove notification about " << message_ids << " in " << dialog_id; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "remove_message_notifications_by_message_ids"); if (d == nullptr) { return; } @@ -27865,7 +27867,7 @@ void MessagesManager::do_remove_message_notification(DialogId dialog_id, bool fr void MessagesManager::remove_message_notifications(DialogId dialog_id, NotificationGroupId group_id, NotificationId max_notification_id, MessageId max_message_id) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "remove_message_notifications"); if (d == nullptr) { LOG(ERROR) << "Can't find " << dialog_id; return; @@ -28078,10 +28080,10 @@ bool MessagesManager::add_new_message_notification(Dialog *d, Message *m, bool f // have a mention, so use notification settings from the dialog with the sender if (m->sender_user_id.is_valid()) { settings_dialog_id = DialogId(m->sender_user_id); - settings_dialog = get_dialog_force(settings_dialog_id); + settings_dialog = get_dialog_force(settings_dialog_id, "add_new_message_notification 1"); } else if (m->sender_dialog_id.is_valid()) { settings_dialog_id = m->sender_dialog_id; - settings_dialog = get_dialog_force(settings_dialog_id); + settings_dialog = get_dialog_force(settings_dialog_id, "add_new_message_notification 2"); } } @@ -29344,7 +29346,7 @@ void MessagesManager::on_update_dialog_draft_message(DialogId dialog_id, LOG(ERROR) << "Receive update chat draft in invalid " << dialog_id; return; } - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "on_update_dialog_draft_message"); if (d == nullptr) { LOG(INFO) << "Ignore update chat draft in unknown " << dialog_id; if (!have_input_peer(dialog_id, AccessRights::Read)) { @@ -29409,7 +29411,7 @@ void MessagesManager::on_update_dialog_is_pinned(FolderId folder_id, DialogId di return; } - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "on_update_dialog_is_pinned"); if (d == nullptr) { LOG(INFO) << "Can't apply updateDialogPinned in " << folder_id << " with unknown " << dialog_id; on_update_pinned_dialogs(folder_id); @@ -29461,7 +29463,7 @@ void MessagesManager::on_update_dialog_is_marked_as_unread(DialogId dialog_id, b return; } - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "on_update_dialog_is_marked_as_unread"); if (d == nullptr) { // nothing to do return; @@ -29519,7 +29521,7 @@ void MessagesManager::on_update_dialog_is_blocked(DialogId dialog_id, bool is_bl td_->contacts_manager_->on_update_user_is_blocked(dialog_id.get_user_id(), is_blocked); } - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "on_update_dialog_is_blocked"); if (d == nullptr) { // nothing to do return; @@ -29590,7 +29592,7 @@ void MessagesManager::on_update_dialog_last_pinned_message_id(DialogId dialog_id return; } - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "on_update_dialog_last_pinned_message_id"); if (d == nullptr) { // nothing to do return; @@ -29675,7 +29677,7 @@ void MessagesManager::on_update_dialog_has_scheduled_server_messages(DialogId di return; } - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "on_update_dialog_has_scheduled_server_messages"); if (d == nullptr) { // nothing to do return; @@ -29729,7 +29731,7 @@ void MessagesManager::set_dialog_has_scheduled_database_messages_impl(Dialog *d, } void MessagesManager::on_update_dialog_folder_id(DialogId dialog_id, FolderId folder_id) { - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "on_update_dialog_folder_id"); if (d == nullptr) { // nothing to do return; @@ -29857,7 +29859,7 @@ void MessagesManager::on_update_dialog_group_call(DialogId dialog_id, bool has_a } void MessagesManager::on_update_dialog_group_call_id(DialogId dialog_id, InputGroupCallId input_group_call_id) { - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "on_update_dialog_group_call_id"); if (d == nullptr) { // nothing to do return; @@ -29881,7 +29883,7 @@ void MessagesManager::on_update_dialog_group_call_id(DialogId dialog_id, InputGr void MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id(DialogId dialog_id, DialogId default_join_as_dialog_id, bool force) { - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "on_update_dialog_default_join_group_call_as_dialog_id"); if (d == nullptr) { // nothing to do return; @@ -29909,7 +29911,7 @@ void MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id(Dial } void MessagesManager::on_update_dialog_message_ttl_setting(DialogId dialog_id, MessageTtlSetting message_ttl_setting) { - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "on_update_dialog_message_ttl_setting"); if (d == nullptr) { // nothing to do return; @@ -29997,7 +29999,7 @@ void MessagesManager::on_dialog_bots_updated(DialogId dialog_id, vector return; } - auto d = from_database ? get_dialog(dialog_id) : get_dialog_force(dialog_id); + auto d = from_database ? get_dialog(dialog_id) : get_dialog_force(dialog_id, "on_dialog_bots_updated"); if (d == nullptr || d->reply_markup_message_id == MessageId()) { return; } @@ -30168,9 +30170,9 @@ DialogId MessagesManager::search_public_dialog(const string &username_to_search, if (dialog_id.is_valid()) { if (have_input_peer(dialog_id, AccessRights::Read)) { if (td_->auth_manager_->is_bot()) { - force_create_dialog(dialog_id, "search public dialog", true); + force_create_dialog(dialog_id, "search_public_dialog", true); } else { - const Dialog *d = get_dialog_force(dialog_id); + const Dialog *d = get_dialog_force(dialog_id, "search_public_dialog"); if (!is_dialog_inited(d)) { send_get_dialog_query(dialog_id, std::move(promise), 0, "search_public_dialog"); return DialogId(); @@ -30182,7 +30184,7 @@ DialogId MessagesManager::search_public_dialog(const string &username_to_search, } else { // bot username maybe known despite there is no access_hash if (force || dialog_id.get_type() != DialogType::User) { - force_create_dialog(dialog_id, "search public dialog", true); + force_create_dialog(dialog_id, "search_public_dialog", true); promise.set_value(Unit()); return dialog_id; } @@ -30660,7 +30662,7 @@ void MessagesManager::clear_active_dialog_actions(DialogId dialog_id) { vector MessagesManager::get_dialog_lists_to_add_dialog(DialogId dialog_id) { vector result; - const Dialog *d = get_dialog_force(dialog_id); + const Dialog *d = get_dialog_force(dialog_id, "get_dialog_lists_to_add_dialog"); if (d == nullptr || d->order == DEFAULT_ORDER || !have_input_peer(dialog_id, AccessRights::Read)) { return result; } @@ -30700,7 +30702,7 @@ void MessagesManager::add_dialog_to_list(DialogId dialog_id, DialogListId dialog LOG(INFO) << "Receive addChatToList request to add " << dialog_id << " to " << dialog_list_id; CHECK(!td_->auth_manager_->is_bot()); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "add_dialog_to_list"); if (d == nullptr) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -30987,7 +30989,7 @@ void MessagesManager::set_dialog_message_ttl_setting(DialogId dialog_id, int32 t return promise.set_error(Status::Error(400, "Message auto-delete time can't be negative")); } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "set_dialog_message_ttl_setting"); if (d == nullptr) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -31164,7 +31166,7 @@ Status MessagesManager::can_pin_messages(DialogId dialog_id) const { void MessagesManager::pin_dialog_message(DialogId dialog_id, MessageId message_id, bool disable_notification, bool only_for_self, bool is_unpin, Promise &&promise) { - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "pin_dialog_message"); if (d == nullptr) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -31195,7 +31197,7 @@ void MessagesManager::pin_dialog_message(DialogId dialog_id, MessageId message_i } void MessagesManager::unpin_all_dialog_messages(DialogId dialog_id, Promise &&promise) { - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "unpin_all_dialog_messages"); if (d == nullptr) { return promise.set_error(Status::Error(6, "Chat not found")); } @@ -31872,7 +31874,7 @@ MessagesManager::Message *MessagesManager::on_get_message_from_database(DialogId } force_create_dialog(dialog_id, source); - d = get_dialog_force(dialog_id); + d = get_dialog_force(dialog_id, source); CHECK(d != nullptr); } @@ -31941,7 +31943,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(DialogId dialog return nullptr; } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, source); if (d == nullptr) { d = add_dialog(dialog_id, "add_message_to_dialog"); *need_update_dialog_pos = true; @@ -33726,8 +33728,8 @@ MessagesManager::Dialog *MessagesManager::get_dialog_by_message_id(MessageId mes G()->td_db()->get_messages_db_sync()->get_message_by_unique_message_id(message_id.get_server_message_id()); if (r_value.is_ok()) { DialogId dialog_id(r_value.ok().first); - Message *m = on_get_message_from_database(dialog_id, get_dialog_force(dialog_id), r_value.ok().second, false, - "get_dialog_by_message_id"); + Message *m = on_get_message_from_database(dialog_id, get_dialog_force(dialog_id, "get_dialog_by_message_id"), + r_value.ok().second, false, "get_dialog_by_message_id"); if (m != nullptr) { CHECK(m->message_id == message_id); CHECK(message_id_to_dialog_id_[message_id] == dialog_id); @@ -33787,7 +33789,7 @@ void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source bool force_update_dialog_pos) { LOG_CHECK(dialog_id.is_valid()) << source; LOG_CHECK(is_inited_) << dialog_id << ' ' << source << ' ' << expect_no_access << ' ' << force_update_dialog_pos; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, source); if (d == nullptr) { LOG(INFO) << "Force create " << dialog_id << " from " << source; if (loaded_dialogs_.count(dialog_id) > 0) { @@ -33806,7 +33808,7 @@ void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source auto secret_chat_id = dialog_id.get_secret_chat_id(); { auto user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id); - Dialog *user_d = get_dialog_force(DialogId(user_id)); + Dialog *user_d = get_dialog_force(DialogId(user_id), source); if (user_d != nullptr && user_d->notification_settings.is_synchronized) { VLOG(notifications) << "Copy notification settings from " << user_d->dialog_id << " to " << dialog_id; auto new_notification_settings = user_d->notification_settings; @@ -33878,7 +33880,7 @@ MessagesManager::Dialog *MessagesManager::add_dialog(DialogId dialog_id, const c MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&d, bool is_loaded_from_database, const char *source) { auto dialog_id = d->dialog_id; - LOG_CHECK(is_inited_) << dialog_id << ' ' << is_loaded_from_database; + LOG_CHECK(is_inited_) << dialog_id << ' ' << is_loaded_from_database << ' ' << source; switch (dialog_id.get_type()) { case DialogType::User: if (dialog_id == get_my_dialog_id() && d->last_read_inbox_message_id == MessageId::max() && @@ -34014,7 +34016,7 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab if (user_id.is_valid()) { force_create_dialog(DialogId(user_id), "add chat with user to load/store action_bar and is_blocked"); - Dialog *user_d = get_dialog_force(DialogId(user_id)); + Dialog *user_d = get_dialog_force(DialogId(user_id), "fix_new_dialog"); if (user_d != nullptr && d->is_blocked != user_d->is_blocked) { set_dialog_is_blocked(d, user_d->is_blocked); } @@ -34957,10 +34959,10 @@ const MessagesManager::Dialog *MessagesManager::get_dialog(DialogId dialog_id) c } bool MessagesManager::have_dialog_force(DialogId dialog_id) { - return loaded_dialogs_.count(dialog_id) > 0 || get_dialog_force(dialog_id) != nullptr; + return loaded_dialogs_.count(dialog_id) > 0 || get_dialog_force(dialog_id, "have_dialog_force") != nullptr; } -MessagesManager::Dialog *MessagesManager::get_dialog_force(DialogId dialog_id) { +MessagesManager::Dialog *MessagesManager::get_dialog_force(DialogId dialog_id, const char *source) { // TODO remove most usages of that function, preload dialog asynchronously if possible auto it = dialogs_.find(dialog_id); if (it != dialogs_.end()) { @@ -34973,12 +34975,13 @@ MessagesManager::Dialog *MessagesManager::get_dialog_force(DialogId dialog_id) { auto r_value = G()->td_db()->get_dialog_db_sync()->get_dialog(dialog_id); if (r_value.is_ok()) { - LOG(INFO) << "Loaded " << dialog_id << " from database"; - auto d = on_load_dialog_from_database(dialog_id, r_value.move_as_ok()); + LOG(INFO) << "Loaded " << dialog_id << " from database from " << source; + auto d = on_load_dialog_from_database(dialog_id, r_value.move_as_ok(), source); LOG_CHECK(d == nullptr || d->dialog_id == dialog_id) << d->dialog_id << " " << dialog_id; return d; } else { - LOG(INFO) << "Failed to load " << dialog_id << " from database: " << r_value.error().message(); + LOG(INFO) << "Failed to load " << dialog_id << " from database from " << source << ": " + << r_value.error().message(); return nullptr; } } @@ -35035,7 +35038,8 @@ unique_ptr MessagesManager::parse_dialog(DialogId dialo return d; } -MessagesManager::Dialog *MessagesManager::on_load_dialog_from_database(DialogId dialog_id, const BufferSlice &value) { +MessagesManager::Dialog *MessagesManager::on_load_dialog_from_database(DialogId dialog_id, const BufferSlice &value, + const char *source) { CHECK(G()->parameters().use_message_db); if (!dialog_id.is_valid()) { @@ -35056,8 +35060,8 @@ MessagesManager::Dialog *MessagesManager::on_load_dialog_from_database(DialogId return old_d; } - LOG(INFO) << "Add new " << dialog_id << " from database"; - return add_new_dialog(parse_dialog(dialog_id, value), true, "on_load_dialog_from_database"); + LOG(INFO) << "Add new " << dialog_id << " from database from " << source; + return add_new_dialog(parse_dialog(dialog_id, value), true, source); } const DialogFilter *MessagesManager::get_server_dialog_filter(DialogFilterId dialog_filter_id) const { @@ -35442,7 +35446,7 @@ bool MessagesManager::need_channel_difference_to_add_message(DialogId dialog_id, return false; } - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "need_channel_difference_to_add_message"); if (d == nullptr || d->last_new_message_id == MessageId()) { return false; } @@ -35737,7 +35741,7 @@ void MessagesManager::on_get_channel_difference( LOG(INFO) << "----- END GET CHANNEL DIFFERENCE----- for " << dialog_id; CHECK(active_get_channel_differencies_.count(dialog_id) == 1); active_get_channel_differencies_.erase(dialog_id); - auto d = get_dialog_force(dialog_id); + auto d = get_dialog_force(dialog_id, "on_get_channel_difference"); if (difference_ptr == nullptr) { bool have_access = have_input_peer(dialog_id, AccessRights::Read); @@ -36186,7 +36190,7 @@ void MessagesManager::try_hide_distance(DialogId dialog_id, const Message *m) { case DialogType::SecretChat: { auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); if (user_id.is_valid()) { - d = get_dialog_force(DialogId(user_id)); + d = get_dialog_force(DialogId(user_id), "try_hide_distance"); } break; } @@ -36211,7 +36215,7 @@ MessagesManager::Message *MessagesManager::continue_send_message(DialogId dialog CHECK(m != nullptr); CHECK(m->content != nullptr); - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "continue_send_message"); if (d == nullptr) { LOG(ERROR) << "Can't find " << dialog_id << " to continue send a message"; binlog_erase(G()->td_db()->get_binlog(), log_event_id); @@ -36418,13 +36422,13 @@ void MessagesManager::on_binlog_events(vector &&events) { } resolve_dependencies_force(td_, dependencies, "ForwardMessagesLogEvent"); - Dialog *to_dialog = get_dialog_force(to_dialog_id); + Dialog *to_dialog = get_dialog_force(to_dialog_id, "ForwardMessagesLogEvent to"); if (to_dialog == nullptr) { LOG(ERROR) << "Can't find " << to_dialog_id << " to forward messages to"; binlog_erase(G()->td_db()->get_binlog(), event.id_); continue; } - Dialog *from_dialog = get_dialog_force(from_dialog_id); + Dialog *from_dialog = get_dialog_force(from_dialog_id, "ForwardMessagesLogEvent from"); if (from_dialog == nullptr) { LOG(ERROR) << "Can't find " << from_dialog_id << " to forward messages from"; binlog_erase(G()->td_db()->get_binlog(), event.id_); @@ -36483,7 +36487,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); log_event.id_ = event.id_; - Dialog *d = get_dialog_force(log_event.full_message_id_.get_dialog_id()); + Dialog *d = get_dialog_force(log_event.full_message_id_.get_dialog_id(), "DeleteMessageLogEvent"); if (d != nullptr) { auto message_id = log_event.full_message_id_.get_message_id(); if (message_id.is_valid_scheduled() && message_id.is_scheduled_server()) { @@ -36506,7 +36510,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "DeleteMessagesFromServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36527,7 +36531,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "DeleteScheduledMessagesFromServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36551,7 +36555,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "DeleteDialogHistoryFromServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36613,7 +36617,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "ReadHistoryOnServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36664,7 +36668,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "ReadMessageThreadHistoryOnServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36690,7 +36694,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "ReadMessageContentsOnServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36709,7 +36713,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "ReadAllDialogMentionsOnServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36728,7 +36732,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "ToggleDialogIsPinnedOnServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36748,7 +36752,7 @@ void MessagesManager::on_binlog_events(vector &&events) { vector dialog_ids; for (auto &dialog_id : log_event.dialog_ids_) { - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "ReorderPinnedDialogsOnServerLogEvent"); if (d != nullptr && have_input_peer(dialog_id, AccessRights::Read)) { dialog_ids.push_back(dialog_id); } @@ -36792,7 +36796,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "ToggleDialogIsBlockedOnServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36811,7 +36815,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "SaveDialogDraftMessageOnServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Write)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36831,7 +36835,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "UpdateDialogNotificationSettingsOnServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36865,7 +36869,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "ChangeDialogReportSpamStateOnServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36884,7 +36888,7 @@ void MessagesManager::on_binlog_events(vector &&events) { log_event_parse(log_event, event.data_).ensure(); auto dialog_id = log_event.dialog_id_; - Dialog *d = get_dialog_force(dialog_id); + Dialog *d = get_dialog_force(dialog_id, "SetDialogFolderIdOnServerLogEvent"); if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -36910,7 +36914,7 @@ void MessagesManager::on_binlog_events(vector &&events) { add_dialog_dependencies(dependencies, dialog_id); resolve_dependencies_force(td_, dependencies, "GetDialogFromServerLogEvent"); - get_dialog_force(dialog_id); // load it if exists + get_dialog_force(dialog_id, "GetDialogFromServerLogEvent"); // load it if exists if (!have_input_peer(dialog_id, AccessRights::Read)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); @@ -37047,7 +37051,7 @@ bool MessagesManager::load_recently_found_dialogs(Promise &promise) { CHECK(dialog_id.is_valid()); // TODO use asynchronous load // get_dialog(dialog_id, resolve_recently_found_dialogs_multipromise_.get_promise()); - get_dialog_force(dialog_id); + get_dialog_force(dialog_id, "load_recently_found_dialogs"); } } resolve_recently_found_dialogs_multipromise_.get_promise().set_value(Unit()); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 3503529e1..262585267 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2428,9 +2428,9 @@ class MessagesManager : public Actor { Dialog *get_dialog(DialogId dialog_id); const Dialog *get_dialog(DialogId dialog_id) const; - Dialog *get_dialog_force(DialogId dialog_id); + Dialog *get_dialog_force(DialogId dialog_id, const char *source = "get_dialog_force"); - Dialog *on_load_dialog_from_database(DialogId dialog_id, const BufferSlice &value); + Dialog *on_load_dialog_from_database(DialogId dialog_id, const BufferSlice &value, const char *source); void on_get_dialogs_from_database(FolderId folder_id, int32 limit, DialogDbGetDialogsResult &&dialogs, Promise &&promise); From a0dcd2d9c282eb6180353530307c652826542659 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 00:51:32 +0300 Subject: [PATCH 224/281] Add optional source to have_dialog_force. --- td/telegram/CallbackQueriesManager.cpp | 2 +- td/telegram/ContactsManager.cpp | 30 +++++++++--------- td/telegram/Dependencies.cpp | 2 +- td/telegram/GroupCallManager.cpp | 8 ++--- td/telegram/MessagesManager.cpp | 44 +++++++++++++------------- td/telegram/MessagesManager.h | 2 +- td/telegram/PrivacyManager.cpp | 2 +- td/telegram/Td.cpp | 4 +-- td/telegram/UpdatesManager.cpp | 4 +-- 9 files changed, 49 insertions(+), 49 deletions(-) diff --git a/td/telegram/CallbackQueriesManager.cpp b/td/telegram/CallbackQueriesManager.cpp index 18d7b70a6..029dfc14e 100644 --- a/td/telegram/CallbackQueriesManager.cpp +++ b/td/telegram/CallbackQueriesManager.cpp @@ -241,7 +241,7 @@ int64 CallbackQueriesManager::send_callback_query(FullMessageId full_message_id, } auto dialog_id = full_message_id.get_dialog_id(); - td_->messages_manager_->have_dialog_force(dialog_id); + td_->messages_manager_->have_dialog_force(dialog_id, "send_callback_query"); if (!td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) { promise.set_error(Status::Error(5, "Can't access the chat")); return 0; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 151bde49e..21adb0941 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -6360,7 +6360,7 @@ void ContactsManager::set_channel_discussion_group(DialogId dialog_id, DialogId ChannelId broadcast_channel_id; telegram_api::object_ptr broadcast_input_channel; if (dialog_id.is_valid()) { - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "set_channel_discussion_group 1")) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -6390,7 +6390,7 @@ void ContactsManager::set_channel_discussion_group(DialogId dialog_id, DialogId ChannelId group_channel_id; telegram_api::object_ptr group_input_channel; if (discussion_dialog_id.is_valid()) { - if (!td_->messages_manager_->have_dialog_force(discussion_dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(discussion_dialog_id, "set_channel_discussion_group 2")) { return promise.set_error(Status::Error(400, "Discussion chat not found")); } if (discussion_dialog_id.get_type() != DialogType::Channel) { @@ -6430,7 +6430,7 @@ void ContactsManager::set_channel_location(DialogId dialog_id, const DialogLocat if (!dialog_id.is_valid()) { return promise.set_error(Status::Error(400, "Invalid chat identifier specified")); } - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "set_channel_location")) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -6462,7 +6462,7 @@ void ContactsManager::set_channel_slow_mode_delay(DialogId dialog_id, int32 slow if (!dialog_id.is_valid()) { return promise.set_error(Status::Error(400, "Invalid chat identifier specified")); } - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "set_channel_slow_mode_delay")) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -6490,7 +6490,7 @@ void ContactsManager::get_channel_statistics_dc_id(DialogId dialog_id, bool for_ if (!dialog_id.is_valid()) { return promise.set_error(Status::Error(400, "Invalid chat identifier specified")); } - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_channel_statistics_dc_id")) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -6711,7 +6711,7 @@ void ContactsManager::delete_channel(ChannelId channel_id, Promise &&promi } void ContactsManager::delete_dialog(DialogId dialog_id, Promise &&promise) { - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "delete_dialog")) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -7069,7 +7069,7 @@ td_api::object_ptr ContactsManager::get_can_ void ContactsManager::transfer_dialog_ownership(DialogId dialog_id, UserId user_id, const string &password, Promise &&promise) { - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "transfer_dialog_ownership")) { return promise.set_error(Status::Error(3, "Chat not found")); } if (!have_user_force(user_id)) { @@ -7121,7 +7121,7 @@ void ContactsManager::transfer_channel_ownership( } Status ContactsManager::can_manage_dialog_invite_links(DialogId dialog_id, bool creator_only) { - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "can_manage_dialog_invite_links")) { return Status::Error(3, "Chat not found"); } @@ -14362,7 +14362,7 @@ std::pair> ContactsManager::search_among_users(const vecto void ContactsManager::add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, Promise &&promise) { - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "add_dialog_participant")) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -14387,7 +14387,7 @@ void ContactsManager::add_dialog_participants(DialogId dialog_id, const vectormessages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "add_dialog_participants")) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -14410,7 +14410,7 @@ void ContactsManager::set_dialog_participant_status(DialogId dialog_id, UserId u const tl_object_ptr &chat_member_status, Promise &&promise) { auto status = get_dialog_participant_status(chat_member_status); - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "set_dialog_participant_status")) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -14431,7 +14431,7 @@ void ContactsManager::set_dialog_participant_status(DialogId dialog_id, UserId u void ContactsManager::ban_dialog_participant(DialogId dialog_id, UserId user_id, int32 banned_until_date, bool revoke_messages, Promise &&promise) { - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "ban_dialog_participant")) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -14455,7 +14455,7 @@ DialogParticipant ContactsManager::get_dialog_participant(DialogId dialog_id, Us bool force, Promise &&promise) { LOG(INFO) << "Receive GetChatMember request to get " << user_id << " in " << dialog_id << " with random_id " << random_id; - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_dialog_participant")) { promise.set_error(Status::Error(3, "Chat not found")); return DialogParticipant(); } @@ -14549,7 +14549,7 @@ void ContactsManager::search_dialog_participants(DialogId dialog_id, const strin Promise &&promise) { LOG(INFO) << "Receive searchChatMembers request to search for \"" << query << "\" in " << dialog_id << " with filter " << filter; - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "search_dialog_participants")) { return promise.set_error(Status::Error(3, "Chat not found")); } if (limit < 0) { @@ -14839,7 +14839,7 @@ void ContactsManager::do_get_channel_participants(ChannelId channel_id, ChannelP vector ContactsManager::get_dialog_administrators(DialogId dialog_id, int left_tries, Promise &&promise) { LOG(INFO) << "Receive GetChatAdministrators request in " << dialog_id << " with " << left_tries << " left tries"; - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_dialog_administrators")) { promise.set_error(Status::Error(3, "Chat not found")); return {}; } diff --git a/td/telegram/Dependencies.cpp b/td/telegram/Dependencies.cpp index 86be67156..e7d58f5b3 100644 --- a/td/telegram/Dependencies.cpp +++ b/td/telegram/Dependencies.cpp @@ -78,7 +78,7 @@ bool resolve_dependencies_force(Td *td, const Dependencies &dependencies, const } } for (auto dialog_id : dependencies.dialog_ids) { - if (dialog_id.is_valid() && !td->messages_manager_->have_dialog_force(dialog_id)) { + if (dialog_id.is_valid() && !td->messages_manager_->have_dialog_force(dialog_id, source)) { LOG(ERROR) << "Can't find " << dialog_id << " from " << source; td->messages_manager_->force_create_dialog(dialog_id, "resolve_dependencies_force", true); success = false; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 61502eabb..e87079c8e 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -890,7 +890,7 @@ DialogId GroupCallManager::get_group_call_participant_id( } case td_api::messageSenderChat::ID: { DialogId dialog_id(static_cast(message_sender.get())->chat_id_); - if (td_->messages_manager_->have_dialog_force(dialog_id)) { + if (td_->messages_manager_->have_dialog_force(dialog_id, "get_group_call_participant_id")) { return dialog_id; } break; @@ -1019,7 +1019,7 @@ void GroupCallManager::get_group_call_join_as(DialogId dialog_id, if (!dialog_id.is_valid()) { return promise.set_error(Status::Error(400, "Invalid chat identifier specified")); } - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_group_call_join_as")) { return promise.set_error(Status::Error(400, "Chat not found")); } if (!td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) { @@ -1033,7 +1033,7 @@ void GroupCallManager::create_voice_chat(DialogId dialog_id, Promisemessages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "create_voice_chat")) { return promise.set_error(Status::Error(400, "Chat not found")); } if (!td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) { @@ -2087,7 +2087,7 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di have_as_dialog_id = false; } } else { - if (!td_->messages_manager_->have_dialog_force(as_dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(as_dialog_id, "join_group_call")) { return promise.set_error(Status::Error(400, "Alias chat not found")); } } diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 3365cdeae..91bb16ff3 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -12883,7 +12883,7 @@ void MessagesManager::delete_secret_messages(SecretChatId secret_chat_id, std::v CHECK(secret_chat_id.is_valid()); DialogId dialog_id(secret_chat_id); - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "delete_secret_messages")) { LOG(ERROR) << "Ignore delete secret messages in unknown " << dialog_id; promise.set_value(Unit()); return; @@ -12930,7 +12930,7 @@ void MessagesManager::delete_secret_chat_history(SecretChatId secret_chat_id, bo CHECK(!last_message_id.is_scheduled()); DialogId dialog_id(secret_chat_id); - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "delete_secret_chat_history")) { LOG(ERROR) << "Ignore delete history in unknown " << dialog_id; promise.set_value(Unit()); return; @@ -15385,7 +15385,7 @@ bool MessagesManager::load_dialog(DialogId dialog_id, int left_tries, Promiseparameters().use_message_db) { // TODO load dialog from database, DialogLoader // send_closure_later(actor_id(this), &MessagesManager::load_dialog_from_database, dialog_id, @@ -15470,7 +15470,7 @@ void MessagesManager::load_dialog_filter(const DialogFilter *filter, bool force, for (auto &input_dialog_id : needed_dialog_ids) { auto dialog_id = input_dialog_id.get_dialog_id(); // TODO load dialogs asynchronously - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "load_dialog_filter")) { if (dialog_id.get_type() == DialogType::SecretChat) { if (have_dialog_info_force(dialog_id)) { force_create_dialog(dialog_id, "load_dialog_filter"); @@ -15624,7 +15624,7 @@ std::pair> MessagesManager::get_dialogs(DialogListId dia vector input_dialog_ids; for (auto &input_dialog_id : filter->pinned_dialog_ids) { auto dialog_id = input_dialog_id.get_dialog_id(); - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "get_dialogs")) { if (dialog_id.get_type() == DialogType::SecretChat) { if (have_dialog_info_force(dialog_id)) { force_create_dialog(dialog_id, "get_dialogs"); @@ -17286,7 +17286,7 @@ void MessagesManager::get_messages_from_server(vector &&message_i for (auto &it : scheduled_message_ids) { auto dialog_id = it.first; - have_dialog_force(dialog_id); + have_dialog_force(dialog_id, "get_messages_from_server"); auto input_peer = get_input_peer(dialog_id, AccessRights::Read); if (input_peer == nullptr) { LOG(ERROR) << "Can't find info about " << dialog_id << " to get a message from it"; @@ -19019,7 +19019,7 @@ Status MessagesManager::toggle_message_sender_is_blocked(const td_api::object_pt break; case td_api::messageSenderChat::ID: { auto sender_dialog_id = DialogId(static_cast(sender.get())->chat_id_); - if (!have_dialog_force(sender_dialog_id)) { + if (!have_dialog_force(sender_dialog_id, "toggle_message_sender_is_blocked")) { return Status::Error(400, "Sender chat not found"); } @@ -21721,7 +21721,7 @@ MessagesManager::FoundMessages MessagesManager::offline_search_messages(DialogId promise.set_value(Unit()); return {}; } - if (dialog_id != DialogId() && !have_dialog_force(dialog_id)) { + if (dialog_id != DialogId() && !have_dialog_force(dialog_id, "offline_search_messages")) { promise.set_error(Status::Error(400, "Chat not found")); return {}; } @@ -26685,7 +26685,7 @@ Result MessagesManager::add_local_message( if (sender_dialog_id.get_type() != DialogType::Channel) { return Status::Error(400, "Sender chat must be a supergroup or channel"); } - if (!have_dialog_force(sender_dialog_id)) { + if (!have_dialog_force(sender_dialog_id, "add_local_message")) { return Status::Error(400, "Sender chat not found"); } break; @@ -26796,7 +26796,7 @@ void MessagesManager::get_message_file_type(const string &message_file_head, } Status MessagesManager::can_import_messages(DialogId dialog_id) { - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "can_import_messages")) { return Status::Error(400, "Chat not found"); } @@ -27118,7 +27118,7 @@ Result MessagesManager::get_messag if (d == nullptr) { return Status::Error(406, "Ignore notification in unknown chat"); } - if (sender_dialog_id.is_valid() && !have_dialog_force(sender_dialog_id)) { + if (sender_dialog_id.is_valid() && !have_dialog_force(sender_dialog_id, "get_message_push_notification_info")) { return Status::Error(406, "Ignore notification sent by unknown chat"); } @@ -30518,7 +30518,7 @@ bool MessagesManager::is_dialog_action_unneeded(DialogId dialog_id) const { void MessagesManager::send_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogAction action, Promise &&promise) { - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "send_dialog_action")) { return promise.set_error(Status::Error(5, "Chat not found")); } if (top_thread_message_id != MessageId() && @@ -30825,7 +30825,7 @@ void MessagesManager::set_dialog_photo(DialogId dialog_id, const tl_object_ptr &&promise) { LOG(INFO) << "Receive setChatPhoto request to change photo of " << dialog_id; - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "set_dialog_photo")) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -30940,7 +30940,7 @@ void MessagesManager::upload_dialog_photo(DialogId dialog_id, FileId file_id, bo void MessagesManager::set_dialog_title(DialogId dialog_id, const string &title, Promise &&promise) { LOG(INFO) << "Receive setChatTitle request to change title of " << dialog_id << " to \"" << title << '"'; - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "set_dialog_title")) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -31056,7 +31056,7 @@ void MessagesManager::set_dialog_permissions(DialogId dialog_id, LOG(INFO) << "Receive setChatPermissions request to change permissions of " << dialog_id << " to " << to_string(permissions); - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "set_dialog_permissions")) { return promise.set_error(Status::Error(3, "Chat not found")); } if (!have_input_peer(dialog_id, AccessRights::Write)) { @@ -31110,7 +31110,7 @@ void MessagesManager::set_dialog_description(DialogId dialog_id, const string &d LOG(INFO) << "Receive setChatDescription request to set description of " << dialog_id << " to \"" << description << '"'; - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "set_dialog_description")) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -31319,7 +31319,7 @@ int64 MessagesManager::get_dialog_event_log(DialogId dialog_id, const string &qu return 0; } - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "get_dialog_event_log")) { promise.set_error(Status::Error(3, "Chat not found")); return 0; } @@ -34958,8 +34958,8 @@ const MessagesManager::Dialog *MessagesManager::get_dialog(DialogId dialog_id) c return it == dialogs_.end() ? nullptr : it->second.get(); } -bool MessagesManager::have_dialog_force(DialogId dialog_id) { - return loaded_dialogs_.count(dialog_id) > 0 || get_dialog_force(dialog_id, "have_dialog_force") != nullptr; +bool MessagesManager::have_dialog_force(DialogId dialog_id, const char *source) { + return loaded_dialogs_.count(dialog_id) > 0 || get_dialog_force(dialog_id, source) != nullptr; } MessagesManager::Dialog *MessagesManager::get_dialog_force(DialogId dialog_id, const char *source) { @@ -36777,7 +36777,7 @@ void MessagesManager::on_binlog_events(vector &&events) { auto dialog_id = log_event.dialog_id_; bool have_info = dialog_id.get_type() == DialogType::User ? td_->contacts_manager_->have_user_force(dialog_id.get_user_id()) - : have_dialog_force(dialog_id); + : have_dialog_force(dialog_id, "ToggleDialogIsMarkedAsUnreadOnServerLogEvent"); if (!have_info || !have_input_peer(dialog_id, AccessRights::Know)) { binlog_erase(G()->td_db()->get_binlog(), event.id_); break; @@ -37065,7 +37065,7 @@ bool MessagesManager::load_recently_found_dialogs(Promise &promise) { } Status MessagesManager::add_recently_found_dialog(DialogId dialog_id) { - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "add_recently_found_dialog")) { return Status::Error(5, "Chat not found"); } if (add_recently_found_dialog_internal(dialog_id)) { @@ -37076,7 +37076,7 @@ Status MessagesManager::add_recently_found_dialog(DialogId dialog_id) { } Status MessagesManager::remove_recently_found_dialog(DialogId dialog_id) { - if (!have_dialog_force(dialog_id)) { + if (!have_dialog_force(dialog_id, "remove_recently_found_dialog")) { return Status::Error(5, "Chat not found"); } if (remove_recently_found_dialog_internal(dialog_id)) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 262585267..e1d27ccce 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -496,7 +496,7 @@ class MessagesManager : public Actor { tl_object_ptr get_chat_events_object(int64 random_id); bool have_dialog(DialogId dialog_id) const; - bool have_dialog_force(DialogId dialog_id); + bool have_dialog_force(DialogId dialog_id, const char *source = "have_dialog_force"); bool have_dialog_info(DialogId dialog_id) const; bool have_dialog_info_force(DialogId dialog_id) const; diff --git a/td/telegram/PrivacyManager.cpp b/td/telegram/PrivacyManager.cpp index 399c292ab..7f9618b9e 100644 --- a/td/telegram/PrivacyManager.cpp +++ b/td/telegram/PrivacyManager.cpp @@ -151,7 +151,7 @@ void PrivacyManager::UserPrivacySettingRule::set_chat_ids(const vector &d auto td = G()->td().get_actor_unsafe(); for (auto dialog_id_int : dialog_ids) { DialogId dialog_id(dialog_id_int); - if (!td->messages_manager_->have_dialog_force(dialog_id)) { + if (!td->messages_manager_->have_dialog_force(dialog_id, "UserPrivacySettingRule::set_chat_ids")) { LOG(ERROR) << "Ignore not found " << dialog_id; continue; } diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 725097909..d2a98f9ff 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6303,7 +6303,7 @@ void Td::on_request(uint64 id, const td_api::leaveChat &request) { CREATE_OK_REQUEST_PROMISE(); DialogId dialog_id(request.chat_id_); td_api::object_ptr new_status = td_api::make_object(); - if (dialog_id.get_type() == DialogType::Channel && messages_manager_->have_dialog_force(dialog_id)) { + if (dialog_id.get_type() == DialogType::Channel && messages_manager_->have_dialog_force(dialog_id, "leaveChat")) { auto status = contacts_manager_->get_channel_status(dialog_id.get_channel_id()); if (status.is_creator()) { if (!status.is_member()) { @@ -7140,7 +7140,7 @@ void Td::on_request(uint64 id, const td_api::resetAllNotificationSettings &reque void Td::on_request(uint64 id, const td_api::getMapThumbnailFile &request) { DialogId dialog_id(request.chat_id_); - if (!messages_manager_->have_dialog_force(dialog_id)) { + if (!messages_manager_->have_dialog_force(dialog_id, "getMapThumbnailFile")) { dialog_id = DialogId(); } diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index 52eacfeec..3ca0835ed 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -2823,9 +2823,9 @@ void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { DialogId dialog_id(ChatId(update->chat_id_)); - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "updateGroupCall")) { dialog_id = DialogId(ChannelId(update->chat_id_)); - if (!td_->messages_manager_->have_dialog_force(dialog_id)) { + if (!td_->messages_manager_->have_dialog_force(dialog_id, "updateGroupCall")) { dialog_id = DialogId(); } } From 94368950a65fc8c33f0aeb0ad302bcab37b8d0fa Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 01:23:04 +0300 Subject: [PATCH 225/281] Remove wrong CHECK. It is wrong to compare orders with different keep_active_date. --- td/telegram/GroupCallManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index e87079c8e..e57cb8442 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1731,7 +1731,6 @@ void GroupCallManager::process_group_call_participants( for (auto participant_it = group_participants.begin(); participant_it != group_participants.end();) { auto &participant = *participant_it; if (old_participant_dialog_ids.count(participant.dialog_id) == 0) { - CHECK(!participant.order.is_valid() || participant.order >= min_order); ++participant_it; continue; } From 9ea4bc3476e23cd71be3ad7c1a654654a5a3ca33 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 01:59:44 +0300 Subject: [PATCH 226/281] Delete from database loaded messages in cleared history part. --- td/telegram/MessagesManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 91bb16ff3..1eeb632bc 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -22166,7 +22166,6 @@ void MessagesManager::preload_older_messages(const Dialog *d, MessageId min_mess unique_ptr MessagesManager::parse_message(DialogId dialog_id, const BufferSlice &value, bool is_scheduled) { - LOG(INFO) << "Loaded message of size " << value.size() << " from database"; auto m = make_unique(); auto status = log_event_parse(*m, value.as_slice()); @@ -22183,6 +22182,7 @@ unique_ptr MessagesManager::parse_message(DialogId dia return nullptr; } + LOG(INFO) << "Loaded " << m->message_id << " in " << dialog_id << " of size " << value.size() << " from database"; return m; } @@ -31987,6 +31987,9 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq if (!message_id.is_scheduled() && message_id <= d->last_clear_history_message_id) { LOG(INFO) << "Skip adding cleared " << message_id << " to " << dialog_id << " from " << source; + if (message->from_database) { + delete_message_from_database(d, message_id, message.get(), true); + } debug_add_message_to_dialog_fail_reason_ = "cleared full history"; return nullptr; } From 525f72263da4ca372fbbe35bf07ae1e4f2bb3626 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 02:19:14 +0300 Subject: [PATCH 227/281] Delete old messages using set_dialog_max_unavailable_message_id when receive MessageChatDeleteHistory. --- td/telegram/MessagesManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 1eeb632bc..15be2b4a4 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -32118,6 +32118,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } LOG(INFO) << "Process MessageChatDeleteHistory in " << message_id << " in " << dialog_id << " with date " << message->date << " from " << source; + set_dialog_max_unavailable_message_id(dialog_id, message_id, false, "message chat delete history"); CHECK(!message->from_database); debug_add_message_to_dialog_fail_reason_ = "skip adding MessageChatDeleteHistory"; return nullptr; From 5e7f0e88492203c4212cc4dfdc8dd938f2b5614d Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 02:25:24 +0300 Subject: [PATCH 228/281] Remove unneeded logging. --- td/telegram/MessagesManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 15be2b4a4..298b511c5 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -13490,14 +13490,14 @@ std::pair> MessagesManager::creat } int32 ttl_period = message_info.ttl_period; - if (ttl_period < 0 || message_id.is_scheduled()) { + if (ttl_period < 0 || (message_id.is_scheduled() && ttl_period != 0)) { LOG(ERROR) << "Wrong TTL period = " << ttl_period << " received in " << message_id << " in " << dialog_id; ttl_period = 0; } int32 ttl = message_info.ttl; bool is_content_secret = is_secret_message_content(ttl, content_type); // should be calculated before TTL is adjusted - if (ttl < 0 || message_id.is_scheduled()) { + if (ttl < 0 || (message_id.is_scheduled() && ttl != 0)) { LOG(ERROR) << "Wrong TTL = " << ttl << " received in " << message_id << " in " << dialog_id; ttl = 0; } else if (ttl > 0) { From d6015184eed2a00e77aec8d1606f4c37bc2a056c Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 02:55:17 +0300 Subject: [PATCH 229/281] Improve log message. --- td/telegram/ContactsManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 21adb0941..002830e57 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -7861,7 +7861,7 @@ void ContactsManager::on_load_contacts_from_database(string value) { } void ContactsManager::on_get_contacts_finished(size_t expected_contact_count) { - LOG(INFO) << "Finished to get " << contacts_hints_.size() << " contacts out of " << expected_contact_count; + LOG(INFO) << "Finished to get " << contacts_hints_.size() << " contacts out of expected " << expected_contact_count; are_contacts_loaded_ = true; auto promises = std::move(load_contacts_queries_); load_contacts_queries_.clear(); From 2f687edf17639c8c9430eac50d613c366e083f94 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 03:06:05 +0300 Subject: [PATCH 230/281] Don't decrease max_unavailable_message_id when processing MessageDeleteChatHistory. --- td/telegram/MessagesManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 298b511c5..b0032e6a9 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -32118,7 +32118,9 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } LOG(INFO) << "Process MessageChatDeleteHistory in " << message_id << " in " << dialog_id << " with date " << message->date << " from " << source; - set_dialog_max_unavailable_message_id(dialog_id, message_id, false, "message chat delete history"); + if (message_id > d->max_unavailable_message_id) { + set_dialog_max_unavailable_message_id(dialog_id, message_id, false, "message chat delete history"); + } CHECK(!message->from_database); debug_add_message_to_dialog_fail_reason_ = "skip adding MessageChatDeleteHistory"; return nullptr; From 9bb79b4b27aa06281388bf2d5b31e5a120169da4 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 14:43:47 +0300 Subject: [PATCH 231/281] Ignore invalid Unicode strings in C++/CX. --- tdutils/td/utils/Status.cpp | 8 ++++++-- tdutils/td/utils/port/CxCli.h | 6 +++++- tdutils/td/utils/port/path.cpp | 2 +- tdutils/td/utils/port/wstring_convert.cpp | 4 ++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/tdutils/td/utils/Status.cpp b/tdutils/td/utils/Status.cpp index bb3f6e780..2d9f7f3c8 100644 --- a/tdutils/td/utils/Status.cpp +++ b/tdutils/td/utils/Status.cpp @@ -42,12 +42,16 @@ string winerror_to_string(int code) { wchar_t wbuf[size]; auto res_size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, code, 0, wbuf, size - 1, nullptr); if (res_size == 0) { - return "Unknown windows error"; + return "Unknown Windows error"; } while (res_size != 0 && (wbuf[res_size - 1] == '\n' || wbuf[res_size - 1] == '\r')) { res_size--; } - return from_wstring(wbuf, res_size).ok(); + auto error_message = from_wstring(wbuf, res_size); + if (error_message.is_error()) { + return "Invalid Windows error"; + } + return error_message.move_as_ok(); } #endif diff --git a/tdutils/td/utils/port/CxCli.h b/tdutils/td/utils/port/CxCli.h index 9e01984e8..a22b2fe38 100644 --- a/tdutils/td/utils/port/CxCli.h +++ b/tdutils/td/utils/port/CxCli.h @@ -85,7 +85,11 @@ inline std::string string_to_unmanaged(String^ str) { if (!str) { return std::string(); } - return td::from_wstring(str->Data(), str->Length()).ok(); + auto r_unmanaged_str = td::from_wstring(str->Data(), str->Length()); + if (r_unmanaged_str.is_error()) { + return std::string(); + } + return r_unmanaged_str.move_as_ok(); } inline String^ string_from_unmanaged(const std::string &from) { diff --git a/tdutils/td/utils/port/path.cpp b/tdutils/td/utils/port/path.cpp index 83ac617ad..865467641 100644 --- a/tdutils/td/utils/port/path.cpp +++ b/tdutils/td/utils/port/path.cpp @@ -470,7 +470,7 @@ CSlice get_temporary_dir() { } auto rs = from_wstring(buf); LOG_IF(FATAL, rs.is_error()) << "GetTempPathW failed: " << rs.error(); - temporary_dir = rs.ok(); + temporary_dir = rs.move_as_ok(); } if (temporary_dir.size() > 1 && temporary_dir.back() == TD_DIR_SLASH) { temporary_dir.pop_back(); diff --git a/tdutils/td/utils/port/wstring_convert.cpp b/tdutils/td/utils/port/wstring_convert.cpp index 2f53d5192..45ad32065 100644 --- a/tdutils/td/utils/port/wstring_convert.cpp +++ b/tdutils/td/utils/port/wstring_convert.cpp @@ -18,7 +18,7 @@ namespace td { Result to_wstring(CSlice slice) { if (!check_utf8(slice)) { - return Status::Error("Wrong encoding"); + return Status::Error("Wrong string encoding"); } size_t wstring_len = utf8_utf16_length(slice); @@ -65,7 +65,7 @@ Result from_wstring(const wchar_t *begin, size_t size) { } } - return Status::Error("Wrong encoding"); + return Status::Error("Wrong wstring encoding"); } result_len += 1 + (cur >= 0x80) + (cur >= 0x800); } From 6e099908cfb4c5b6afb1bb3c1cebd4d559fc1221 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 14:55:54 +0300 Subject: [PATCH 232/281] Don't use sendmsg on Android. --- tdutils/td/utils/port/SocketFd.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tdutils/td/utils/port/SocketFd.cpp b/tdutils/td/utils/port/SocketFd.cpp index 83d418a0c..606fd4c44 100644 --- a/tdutils/td/utils/port/SocketFd.cpp +++ b/tdutils/td/utils/port/SocketFd.cpp @@ -393,7 +393,8 @@ class SocketFdImpl { int native_fd = get_native_fd().socket(); TRY_RESULT(slices_size, narrow_cast_safe(slices.size())); auto write_res = detail::skip_eintr([&] { -#ifdef MSG_NOSIGNAL + // sendmsg can erroneously return 2^32 - 1 on Android 5.1 and Android 6.0, so it must not be used there +#ifdef MSG_NOSIGNAL && !TD_ANDROID msghdr msg; std::memset(&msg, 0, sizeof(msg)); msg.msg_iov = const_cast(slices.begin()); @@ -412,7 +413,7 @@ class SocketFdImpl { } left -= slice.iov_len; } - LOG(FATAL) << "Receive " << result << " as writev response, but tried to write only " << result - left + LOG(FATAL) << "Receive " << write_res << " as writev response, but tried to write only " << result - left << " bytes"; } return write_finish(); @@ -430,7 +431,7 @@ class SocketFdImpl { }); if (write_res >= 0) { auto result = narrow_cast(write_res); - LOG_CHECK(result <= slice.size()) << "Receive " << result << " as write response, but tried to write only " + LOG_CHECK(result <= slice.size()) << "Receive " << write_res << " as write response, but tried to write only " << slice.size() << " bytes"; return result; } From af1b774ffbbb61cefa667660e09470d09555a267 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 15:21:44 +0300 Subject: [PATCH 233/281] Replace sender in messages sent by anonymous bot with the group itself. --- td/telegram/MessagesManager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index b0032e6a9..535c30e04 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -31980,6 +31980,13 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } } } + if (message->sender_user_id == ContactsManager::get_anonymous_bot_user_id() && + !message->sender_dialog_id.is_valid() && dialog_id.get_type() == DialogType::Channel && + !is_broadcast_channel(dialog_id)) { + message->sender_user_id = UserId(); + message->sender_dialog_id = dialog_id; + } + if (!message->top_thread_message_id.is_valid() && !is_broadcast_channel(dialog_id) && is_visible_message_reply_info(dialog_id, message.get()) && !message_id.is_scheduled()) { message->top_thread_message_id = message_id; @@ -33372,6 +33379,9 @@ bool MessagesManager::update_message(Dialog *d, Message *old_message, unique_ptr if (new_message->is_mention_notification_disabled) { old_message->is_mention_notification_disabled = true; } + if (!new_message->from_database) { + old_message->from_database = false; + } if (old_message->ttl_period != new_message->ttl_period) { if (old_message->ttl_period != 0 || !message_id.is_yet_unsent()) { From 4abb995b0523cbc57a887963ef6036dd741e9225 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 15:51:29 +0300 Subject: [PATCH 234/281] Don't use online mode for bots having more than one session. --- td/telegram/Td.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index d2a98f9ff..4f9f1c3bf 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -3187,6 +3187,10 @@ bool Td::is_online() const { } void Td::set_is_bot_online(bool is_bot_online) { + if (G()->shared_config().get_option_integer("session_count") > 1) { + is_bot_online = false; + } + if (is_bot_online == is_bot_online_) { return; } From 441dd127b31dbad169e4b7dcc6305dd7f65aba95 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 16:13:21 +0300 Subject: [PATCH 235/281] Set alpha channel in payment form theme. --- td/telegram/Payments.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 10eedd2d2..90b01271e 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -1146,12 +1146,15 @@ void get_payment_form(Td *td, FullMessageId full_message_id, const td_api::objec if (theme != nullptr) { theme_parameters = make_tl_object(string()); theme_parameters->data_ = json_encode(json_object([&theme](auto &o) { - o("bg_color", theme->background_color_); - o("text_color", theme->text_color_); - o("hint_color", theme->hint_color_); - o("link_color", theme->link_color_); - o("button_color", theme->button_color_); - o("button_text_color", theme->button_text_color_); + auto get_color = [](int32 color) { + return static_cast(static_cast(color) | 0x000000FF); + }; + o("bg_color", get_color(theme->background_color_)); + o("text_color", get_color(theme->text_color_)); + o("hint_color", get_color(theme->hint_color_)); + o("link_color", get_color(theme->link_color_)); + o("button_color", get_color(theme->button_color_)); + o("button_text_color", get_color(theme->button_text_color_)); })); } td->create_handler(std::move(promise)) From 564b44d3b9f175f164fe07522fb82f435c2fc010 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 22:17:55 +0300 Subject: [PATCH 236/281] Fix ifdef check. --- tdutils/td/utils/port/SocketFd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tdutils/td/utils/port/SocketFd.cpp b/tdutils/td/utils/port/SocketFd.cpp index 606fd4c44..b74a078f9 100644 --- a/tdutils/td/utils/port/SocketFd.cpp +++ b/tdutils/td/utils/port/SocketFd.cpp @@ -394,7 +394,7 @@ class SocketFdImpl { TRY_RESULT(slices_size, narrow_cast_safe(slices.size())); auto write_res = detail::skip_eintr([&] { // sendmsg can erroneously return 2^32 - 1 on Android 5.1 and Android 6.0, so it must not be used there -#ifdef MSG_NOSIGNAL && !TD_ANDROID +#if defined(MSG_NOSIGNAL) && !TD_ANDROID msghdr msg; std::memset(&msg, 0, sizeof(msg)); msg.msg_iov = const_cast(slices.begin()); From a2e6a242f12d87b8e0e0338779aa131c23851954 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 8 Apr 2021 23:01:12 +0300 Subject: [PATCH 237/281] Fix getChatEventLog filter flags. --- td/telegram/MessagesManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 535c30e04..020e940bf 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -31299,10 +31299,10 @@ tl_object_ptr MessagesManager::get_ch flags |= telegram_api::channelAdminLogEventsFilter::SETTINGS_MASK; } if (filters->invite_link_changes_) { - flags |= telegram_api::channelAdminLogEventsFilter::GROUP_CALL_MASK; + flags |= telegram_api::channelAdminLogEventsFilter::INVITES_MASK; } if (filters->voice_chat_changes_) { - flags |= telegram_api::channelAdminLogEventsFilter::INVITES_MASK; + flags |= telegram_api::channelAdminLogEventsFilter::GROUP_CALL_MASK; } return make_tl_object( From 51581b8d03c2b63e2e6c17acf1a7c5c3b0179809 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 9 Apr 2021 01:11:44 +0300 Subject: [PATCH 238/281] Minor. --- td/telegram/MessagesManager.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 020e940bf..eec76eeee 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -20126,8 +20126,8 @@ vector MessagesManager::get_dialog_notification_settings_exceptions(No vector ordered_dialogs; auto my_dialog_id = get_my_dialog_id(); for (const auto &list : dialog_folders_) { - for (const auto &it : list.second.ordered_dialogs_) { - auto dialog_id = it.get_dialog_id(); + for (const auto &dialog_date : list.second.ordered_dialogs_) { + auto dialog_id = dialog_date.get_dialog_id(); if (filter_scope && get_dialog_notification_setting_scope(dialog_id) != scope) { continue; } @@ -20152,9 +20152,9 @@ vector MessagesManager::get_dialog_notification_settings_exceptions(No std::sort(ordered_dialogs.begin(), ordered_dialogs.end()); vector result; - for (auto &it : ordered_dialogs) { - CHECK(result.empty() || result.back() != it.get_dialog_id()); - result.push_back(it.get_dialog_id()); + for (auto &dialog_date : ordered_dialogs) { + CHECK(result.empty() || result.back() != dialog_date.get_dialog_id()); + result.push_back(dialog_date.get_dialog_id()); } promise.set_value(Unit()); return result; @@ -29764,8 +29764,7 @@ void MessagesManager::set_dialog_folder_id(Dialog *d, FolderId folder_id) { } DialogDate dialog_date(d->order, d->dialog_id); - auto *folder = get_dialog_folder(d->folder_id); - if (folder->ordered_dialogs_.erase(dialog_date) == 0) { + if (get_dialog_folder(d->folder_id)->ordered_dialogs_.erase(dialog_date) == 0) { LOG_IF(ERROR, d->order != DEFAULT_ORDER) << d->dialog_id << " not found in the chat list"; } From 550ccc8d9bbbe9cff1dc618aef5764d2cbd2cd91 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 9 Apr 2021 01:49:27 +0300 Subject: [PATCH 239/281] Move left chats to a correct ordered_dialogs_ list. --- td/telegram/MessagesManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index eec76eeee..fe5f20084 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -20137,6 +20137,8 @@ vector MessagesManager::get_dialog_notification_settings_exceptions(No const Dialog *d = get_dialog(dialog_id); CHECK(d != nullptr); + LOG_CHECK(d->folder_id == list.first) + << list.first << ' ' << dialog_id << ' ' << d->folder_id << ' ' << d->order; if (d->order == DEFAULT_ORDER) { break; } @@ -34713,7 +34715,10 @@ void MessagesManager::update_dialog_lists( if (d->folder_id != FolderId::main()) { LOG(INFO) << "Change folder of " << dialog_id << " to " << FolderId::main(); + DialogDate dialog_date(d->order, dialog_id); + get_dialog_folder(d->folder_id)->ordered_dialogs_.erase(dialog_date); do_set_dialog_folder_id(d, FolderId::main()); + get_dialog_folder(d->folder_id)->ordered_dialogs_.insert(dialog_date); } } From 338e4085d5114f6d4d4fbd8f30236e4687054d82 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 9 Apr 2021 02:29:27 +0300 Subject: [PATCH 240/281] Improve scheduled voice chats documentation. --- td/generate/scheme/td_api.tl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 3f9288640..fb37ff1aa 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4615,7 +4615,7 @@ setVoiceChatDefaultParticipant chat_id:int53 default_participant_id:MessageSende //@description Creates a voice chat (a group call bound to a chat). Available only for basic groups, supergroups and channels; requires can_manage_voice_chats rights //@chat_id Chat identifier, in which the voice chat will be created //@title Group call title; if empty, chat title will be used -//@start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator. Pass 0 to start the voice chat immediately +//@start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator; 0 to start the voice chat immediately. The date must be at least 10 seconds and at most 8 days in the future createVoiceChat chat_id:int53 title:string start_date:int32 = GroupCallId; //@description Returns information about a group call @group_call_id Group call identifier @@ -4628,7 +4628,7 @@ startScheduledGroupCall group_call_id:int32 = Ok; //@group_call_id Group call identifier @enabled_start_notification New value of the enabled_start_notification setting toggleGroupCallEnabledStartNotification group_call_id:int32 enabled_start_notification:Bool = Ok; -//@description Joins a group call +//@description Joins an active group call //@group_call_id Group call identifier //@participant_id Identifier of a group call participant, which will be used to join the call; voice chats only //@payload Group join payload; received from tgcalls @@ -4647,7 +4647,7 @@ toggleGroupCallMuteNewParticipants group_call_id:int32 mute_new_participants:Boo //@description Revokes invite link for a group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier revokeGroupCallInviteLink group_call_id:int32 = Ok; -//@description Invites users to a group call. Sends a service message of type messageInviteToGroupCall for voice chats +//@description Invites users to an active group call. Sends a service message of type messageInviteToGroupCall for voice chats //@group_call_id Group call identifier @user_ids User identifiers. At most 10 users can be invited simultaneously inviteGroupCallParticipants group_call_id:int32 user_ids:vector = Ok; @@ -4656,21 +4656,21 @@ inviteGroupCallParticipants group_call_id:int32 user_ids:vector = Ok; //@can_self_unmute Pass true if the invite_link should contain an invite hash, passing which to joinGroupCall would allow the invited user to unmute themself. Requires groupCall.can_be_managed group call flag getGroupCallInviteLink group_call_id:int32 can_self_unmute:Bool = HttpUrl; -//@description Starts recording of a group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title Group call recording title; 0-64 characters +//@description Starts recording of an active group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier @title Group call recording title; 0-64 characters startGroupCallRecording group_call_id:int32 title:string = Ok; -//@description Ends recording of a group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier +//@description Ends recording of an active group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier endGroupCallRecording group_call_id:int32 = Ok; -//@description Informs TDLib that a group call participant speaking state has changed @group_call_id Group call identifier +//@description Informs TDLib that a participant of an active group call speaking state has changed @group_call_id Group call identifier //@source Group call participant's synchronization source identifier, or 0 for the current user @is_speaking True, if the user is speaking setGroupCallParticipantIsSpeaking group_call_id:int32 source:int32 is_speaking:Bool = Ok; -//@description Toggles whether a group call participant is muted, unmuted, or allowed to unmute themself +//@description Toggles whether a participant of an active group call is muted, unmuted, or allowed to unmute themself //@group_call_id Group call identifier @participant_id Participant identifier @is_muted Pass true if the user must be muted and false otherwise toggleGroupCallParticipantIsMuted group_call_id:int32 participant_id:MessageSender is_muted:Bool = Ok; -//@description Changes a group call participant's volume level. If the current user can manage the group call, then the participant's volume level will be changed for all users with default volume level +//@description Changes volume level of a participant of an active group call. If the current user can manage the group call, then the participant's volume level will be changed for all users with default volume level //@group_call_id Group call identifier @participant_id Participant identifier @volume_level New participant's volume level; 1-20000 in hundreds of percents setGroupCallParticipantVolumeLevel group_call_id:int32 participant_id:MessageSender volume_level:int32 = Ok; @@ -4679,7 +4679,7 @@ setGroupCallParticipantVolumeLevel group_call_id:int32 participant_id:MessageSen //@is_hand_raised Pass true if the user's hand should be raised. Only self hand can be raised. Requires groupCall.can_be_managed group call flag to lower other's hand toggleGroupCallParticipantIsHandRaised group_call_id:int32 participant_id:MessageSender is_hand_raised:Bool = Ok; -//@description Loads more group call participants. The loaded participants will be received through updates. Use the field groupCall.loaded_all_participants to check whether all participants has already been loaded +//@description Loads more participants of a group call. The loaded participants will be received through updates. Use the field groupCall.loaded_all_participants to check whether all participants has already been loaded //@group_call_id Group call identifier. The group call must be previously received through getGroupCall and must be joined or being joined //@limit The maximum number of participants to load loadGroupCallParticipants group_call_id:int32 limit:int32 = Ok; From 969b52cc82fe70b3a310e2c9eaed4e847f2d41d2 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 9 Apr 2021 02:35:50 +0300 Subject: [PATCH 241/281] Minor improvements. --- td/telegram/DialogFilter.cpp | 6 +++--- td/telegram/DialogParticipant.h | 1 + td/telegram/MessageContent.cpp | 1 - td/telegram/MessagesManager.cpp | 8 ++++---- td/telegram/Payments.cpp | 1 + td/telegram/Payments.h | 1 + td/telegram/SecretChatActor.h | 2 +- tdnet/td/net/Wget.cpp | 2 +- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/td/telegram/DialogFilter.cpp b/td/telegram/DialogFilter.cpp index 4717d6e63..a67f120b7 100644 --- a/td/telegram/DialogFilter.cpp +++ b/td/telegram/DialogFilter.cpp @@ -90,15 +90,15 @@ Status DialogFilter::check_limits() const { if (excluded_server_dialog_count > MAX_INCLUDED_FILTER_DIALOGS || excluded_secret_dialog_count > MAX_INCLUDED_FILTER_DIALOGS) { - return Status::Error(400, "Maximum number of excluded chats exceeded"); + return Status::Error(400, "The maximum number of excluded chats exceeded"); } if (included_server_dialog_count > MAX_INCLUDED_FILTER_DIALOGS || included_secret_dialog_count > MAX_INCLUDED_FILTER_DIALOGS) { - return Status::Error(400, "Maximum number of included chats exceeded"); + return Status::Error(400, "The maximum number of included chats exceeded"); } if (included_server_dialog_count + pinned_server_dialog_count > MAX_INCLUDED_FILTER_DIALOGS || included_secret_dialog_count + pinned_secret_dialog_count > MAX_INCLUDED_FILTER_DIALOGS) { - return Status::Error(400, "Maximum number of pinned chats exceeded"); + return Status::Error(400, "The maximum number of pinned chats exceeded"); } if (is_empty(false)) { diff --git a/td/telegram/DialogParticipant.h b/td/telegram/DialogParticipant.h index b6e5bc42a..f3665d8e1 100644 --- a/td/telegram/DialogParticipant.h +++ b/td/telegram/DialogParticipant.h @@ -11,6 +11,7 @@ #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" +#include "td/telegram/Version.h" #include "td/utils/common.h" #include "td/utils/StringBuilder.h" diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 2b863c8ce..feebce40e 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -51,7 +51,6 @@ #include "td/telegram/secret_api.hpp" #include "td/telegram/SecureValue.h" #include "td/telegram/SecureValue.hpp" -#include "td/telegram/ServerMessageId.h" #include "td/telegram/StickersManager.h" #include "td/telegram/StickersManager.hpp" #include "td/telegram/Td.h" diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 245ce5b8a..26cc52e12 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -17905,7 +17905,7 @@ void MessagesManager::create_dialog_filter(td_api::object_ptr> &&promise) { CHECK(!td_->auth_manager_->is_bot()); if (dialog_filters_.size() >= MAX_DIALOG_FILTERS) { - return promise.set_error(Status::Error(400, "Maximum number of chat folders exceeded")); + return promise.set_error(Status::Error(400, "The maximum number of chat folders exceeded")); } if (!is_update_chat_filters_sent_) { return promise.set_error(Status::Error(400, "Chat folders are not synchronized yet")); @@ -18741,7 +18741,7 @@ Status MessagesManager::toggle_dialog_is_pinned(DialogListId dialog_list_id, Dia : pinned_dialog_count - secret_pinned_dialog_count; if (dialog_count >= static_cast(get_pinned_dialogs_limit(dialog_list_id))) { - return Status::Error(400, "Maximum number of pinned chats exceeded"); + return Status::Error(400, "The maximum number of pinned chats exceeded"); } } @@ -18824,7 +18824,7 @@ Status MessagesManager::set_pinned_dialogs(DialogListId dialog_list_id, vector dialog_count_limit || secret_dialog_count > dialog_count_limit) { - return Status::Error(400, "Maximum number of pinned chats exceeded"); + return Status::Error(400, "The maximum number of pinned chats exceeded"); } } std::unordered_set new_pinned_dialog_ids(dialog_ids.begin(), dialog_ids.end()); @@ -37387,7 +37387,7 @@ Result MessagesManager::get_payment_successful_message_id(FullM return Status::Error(5, "Message has wrong type"); } if (m->message_id.is_scheduled()) { - return Status::Error(5, "Wrong sheduled message identifier"); + return Status::Error(5, "Wrong scheduled message identifier"); } if (!m->message_id.is_server()) { return Status::Error(5, "Wrong message identifier"); diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 90b01271e..efac029e2 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -6,6 +6,7 @@ // #include "td/telegram/Payments.h" +#include "td/telegram/AccessRights.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/files/FileManager.h" #include "td/telegram/files/FileType.h" diff --git a/td/telegram/Payments.h b/td/telegram/Payments.h index ecfdce141..5415c0091 100644 --- a/td/telegram/Payments.h +++ b/td/telegram/Payments.h @@ -9,6 +9,7 @@ #include "td/actor/PromiseFuture.h" #include "td/telegram/DialogId.h" +#include "td/telegram/files/FileId.h" #include "td/telegram/FullMessageId.h" #include "td/telegram/MessageId.h" #include "td/telegram/Photo.h" diff --git a/td/telegram/SecretChatActor.h b/td/telegram/SecretChatActor.h index c2a5e6747..957605708 100644 --- a/td/telegram/SecretChatActor.h +++ b/td/telegram/SecretChatActor.h @@ -11,9 +11,9 @@ #include "td/telegram/logevent/SecretChatEvent.h" #include "td/telegram/MessageId.h" #include "td/telegram/net/NetQuery.h" +#include "td/telegram/secret_api.h" #include "td/telegram/SecretChatDb.h" #include "td/telegram/SecretChatId.h" -#include "td/telegram/secret_api.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" diff --git a/tdnet/td/net/Wget.cpp b/tdnet/td/net/Wget.cpp index 7f961e3a6..a54396b74 100644 --- a/tdnet/td/net/Wget.cpp +++ b/tdnet/td/net/Wget.cpp @@ -75,7 +75,7 @@ Status Wget::try_init() { TRY_RESULT(fd, SocketFd::open(addr)); if (fd.empty()) { - return td::Status::Error("Sockets are not supported"); + return Status::Error("Sockets are not supported"); } if (url.protocol_ == HttpUrl::Protocol::Http) { connection_ = create_actor("Connect", std::move(fd), SslStream{}, From 3786033316cd57f09d60eefcd7cb9b6f2d1828dd Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 9 Apr 2021 17:01:58 +0300 Subject: [PATCH 242/281] Add minithumbnails to userProfilePhoto and chatPhotoInfo. --- td/generate/scheme/td_api.tl | 6 ++++-- td/telegram/Photo.cpp | 10 +++++++--- td/telegram/Photo.h | 1 + td/telegram/Photo.hpp | 10 ++++++++++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index fb37ff1aa..dd8bc36e9 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -318,14 +318,16 @@ poll id:int64 question:string options:vector total_voter_count:int32 //@description Describes a user profile photo @id Photo identifier; 0 for an empty photo. Can be used to find a photo in a list of user profile photos //@small A small (160x160) user profile photo. The file can be downloaded only before the photo is changed //@big A big (640x640) user profile photo. The file can be downloaded only before the photo is changed +//@minithumbnail User profile photo minithumbnail; may be null //@has_animation True, if the photo has animated variant -profilePhoto id:int64 small:file big:file has_animation:Bool = ProfilePhoto; +profilePhoto id:int64 small:file big:file minithumbnail:minithumbnail has_animation:Bool = ProfilePhoto; //@description Contains basic information about the photo of a chat //@small A small (160x160) chat photo variant in JPEG format. The file can be downloaded only before the photo is changed //@big A big (640x640) chat photo variant in JPEG format. The file can be downloaded only before the photo is changed +//@minithumbnail Chat photo minithumbnail; may be null //@has_animation True, if the photo has animated variant -chatPhotoInfo small:file big:file has_animation:Bool = ChatPhotoInfo; +chatPhotoInfo small:file big:file minithumbnail:minithumbnail has_animation:Bool = ChatPhotoInfo; //@class UserType @description Represents the type of a user. The following types are possible: regular users, deleted users and bots diff --git a/td/telegram/Photo.cpp b/td/telegram/Photo.cpp index 6e8114441..4c498bae0 100644 --- a/td/telegram/Photo.cpp +++ b/td/telegram/Photo.cpp @@ -168,6 +168,7 @@ ProfilePhoto get_profile_photo(FileManager *file_manager, UserId user_id, int64 auto dc_id = DcId::create(profile_photo->dc_id_); result.has_animation = (profile_photo->flags_ & telegram_api::userProfilePhoto::HAS_VIDEO_MASK) != 0; result.id = profile_photo->photo_id_; + result.minithumbnail = profile_photo->stripped_thumb_.as_slice().str(); result.small_file_id = register_photo(file_manager, {DialogId(user_id), user_access_hash, false}, result.id, 0, "", std::move(profile_photo->photo_small_), DialogId(), 0, dc_id, PhotoFormat::Jpeg); @@ -191,7 +192,8 @@ tl_object_ptr get_profile_photo_object(FileManager *file_m } return td_api::make_object( profile_photo.id, file_manager->get_file_object(profile_photo.small_file_id), - file_manager->get_file_object(profile_photo.big_file_id), profile_photo.has_animation); + file_manager->get_file_object(profile_photo.big_file_id), get_minithumbnail_object(profile_photo.minithumbnail), + profile_photo.has_animation); } bool operator==(const ProfilePhoto &lhs, const ProfilePhoto &rhs) { @@ -209,7 +211,7 @@ bool operator==(const ProfilePhoto &lhs, const ProfilePhoto &rhs) { << ", second profilePhoto: " << rhs; return false; } - return lhs.has_animation == rhs.has_animation && !id_differs; + return lhs.has_animation == rhs.has_animation && lhs.minithumbnail == rhs.minithumbnail && !id_differs; } bool operator!=(const ProfilePhoto &lhs, const ProfilePhoto &rhs) { @@ -235,6 +237,7 @@ DialogPhoto get_dialog_photo(FileManager *file_manager, DialogId dialog_id, int6 auto dc_id = DcId::create(chat_photo->dc_id_); result.has_animation = (chat_photo->flags_ & telegram_api::chatPhoto::HAS_VIDEO_MASK) != 0; + result.minithumbnail = chat_photo->stripped_thumb_.as_slice().str(); result.small_file_id = register_photo(file_manager, {dialog_id, dialog_access_hash, false}, 0, 0, "", std::move(chat_photo->photo_small_), DialogId(), 0, dc_id, PhotoFormat::Jpeg); @@ -258,6 +261,7 @@ tl_object_ptr get_chat_photo_info_object(FileManager *fil } return td_api::make_object(file_manager->get_file_object(dialog_photo->small_file_id), file_manager->get_file_object(dialog_photo->big_file_id), + get_minithumbnail_object(dialog_photo->minithumbnail), dialog_photo->has_animation); } @@ -318,7 +322,7 @@ ProfilePhoto as_profile_photo(FileManager *file_manager, UserId user_id, int64 u bool operator==(const DialogPhoto &lhs, const DialogPhoto &rhs) { return lhs.small_file_id == rhs.small_file_id && lhs.big_file_id == rhs.big_file_id && - lhs.has_animation == rhs.has_animation; + lhs.minithumbnail == rhs.minithumbnail && lhs.has_animation == rhs.has_animation; } bool operator!=(const DialogPhoto &lhs, const DialogPhoto &rhs) { diff --git a/td/telegram/Photo.h b/td/telegram/Photo.h index e8ddfed1e..20bd543fe 100644 --- a/td/telegram/Photo.h +++ b/td/telegram/Photo.h @@ -36,6 +36,7 @@ struct Dimensions { struct DialogPhoto { FileId small_file_id; FileId big_file_id; + string minithumbnail; bool has_animation = false; }; diff --git a/td/telegram/Photo.hpp b/td/telegram/Photo.hpp index 17a58e1fd..8289a7d5c 100644 --- a/td/telegram/Photo.hpp +++ b/td/telegram/Photo.hpp @@ -31,29 +31,39 @@ void parse(Dimensions &dimensions, ParserT &parser) { template void store(const DialogPhoto &dialog_photo, StorerT &storer) { bool has_file_ids = dialog_photo.small_file_id.is_valid() || dialog_photo.big_file_id.is_valid(); + bool has_minithumbnail = !dialog_photo.minithumbnail.empty(); BEGIN_STORE_FLAGS(); STORE_FLAG(has_file_ids); STORE_FLAG(dialog_photo.has_animation); + STORE_FLAG(has_minithumbnail); END_STORE_FLAGS(); if (has_file_ids) { store(dialog_photo.small_file_id, storer); store(dialog_photo.big_file_id, storer); } + if (has_minithumbnail) { + store(dialog_photo.minithumbnail, storer); + } } template void parse(DialogPhoto &dialog_photo, ParserT &parser) { bool has_file_ids = true; + bool has_minithumbnail = false; if (parser.version() >= static_cast(Version::AddDialogPhotoHasAnimation)) { BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_file_ids); PARSE_FLAG(dialog_photo.has_animation); + PARSE_FLAG(has_minithumbnail); END_PARSE_FLAGS(); } if (has_file_ids) { parse(dialog_photo.small_file_id, parser); parse(dialog_photo.big_file_id, parser); } + if (has_minithumbnail) { + parse(dialog_photo.minithumbnail, parser); + } } template From a54fa0909b5b35458633696fec19ca4bed5ee83c Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 9 Apr 2021 18:50:07 +0300 Subject: [PATCH 243/281] Improve updates on group call leaving. --- td/telegram/GroupCallManager.cpp | 43 ++++++++++++++++++++++---------- td/telegram/GroupCallManager.h | 2 +- td/telegram/cli.cpp | 6 ++--- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 245d19364..7081ad14c 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -1751,10 +1751,10 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup on_group_call_left_impl(group_call, need_rejoin, "process_pending_group_call_participant_updates"); need_update = true; } + need_update |= try_clear_group_call_participants(input_group_call_id); if (need_update) { send_update_group_call(group_call, "process_pending_group_call_participant_updates"); } - try_clear_group_call_participants(input_group_call_id); return need_update; } @@ -2567,7 +2567,7 @@ bool GroupCallManager::on_join_group_call_response(InputGroupCallId input_group_ need_update = true; } pending_join_requests_.erase(it); - try_clear_group_call_participants(input_group_call_id); + need_update |= try_clear_group_call_participants(input_group_call_id); process_group_call_after_join_requests(input_group_call_id, "on_join_group_call_response"); return need_update; } @@ -2579,18 +2579,23 @@ void GroupCallManager::finish_join_group_call(InputGroupCallId input_group_call_ return; } it->second->promise.set_error(std::move(error)); + auto as_dialog_id = it->second->as_dialog_id; pending_join_requests_.erase(it); if (G()->close_flag()) { return; } - try_clear_group_call_participants(input_group_call_id); + const GroupCall *group_call = get_group_call(input_group_call_id); + remove_recent_group_call_speaker(input_group_call_id, as_dialog_id); + if (try_clear_group_call_participants(input_group_call_id)) { + CHECK(group_call != nullptr); + send_update_group_call(group_call, "finish_join_group_call"); + } process_group_call_after_join_requests(input_group_call_id, "finish_join_group_call"); - GroupCall *group_call = get_group_call(input_group_call_id); - CHECK(group_call != nullptr); - if (group_call->dialog_id.is_valid()) { + if (group_call != nullptr && group_call->dialog_id.is_valid()) { + update_group_call_dialog(group_call, "finish_join_group_call", false); td_->messages_manager_->reload_dialog_info_full(group_call->dialog_id); } } @@ -3454,14 +3459,18 @@ void GroupCallManager::leave_group_call(GroupCallId group_call_id, Promise if (group_call == nullptr || !group_call->is_inited || !group_call->is_active || !group_call->is_joined || group_call->is_being_left) { if (cancel_join_group_call_request(input_group_call_id) != 0) { - try_clear_group_call_participants(input_group_call_id); + if (try_clear_group_call_participants(input_group_call_id)) { + send_update_group_call(group_call, "leave_group_call 1"); + } process_group_call_after_join_requests(input_group_call_id, "leave_group_call 1"); return promise.set_value(Unit()); } if (group_call->need_rejoin) { group_call->need_rejoin = false; send_update_group_call(group_call, "leave_group_call"); - try_clear_group_call_participants(input_group_call_id); + if (try_clear_group_call_participants(input_group_call_id)) { + send_update_group_call(group_call, "leave_group_call 2"); + } process_group_call_after_join_requests(input_group_call_id, "leave_group_call 2"); return promise.set_value(Unit()); } @@ -3551,20 +3560,20 @@ void GroupCallManager::on_update_group_call(tl_object_ptrgroup_call_id.get()); + remove_recent_group_call_speaker(input_group_call_id, group_call->as_dialog_id); } - remove_recent_group_call_speaker(input_group_call_id, group_call->as_dialog_id); auto participants_it = group_call_participants_.find(input_group_call_id); if (participants_it == group_call_participants_.end()) { - return; + return false; } auto participants = std::move(participants_it->second); @@ -3580,11 +3589,17 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ group_call->leave_version = group_call->version; group_call->version = -1; + bool need_update = false; for (auto &participant : participants->participants) { if (participant.order.is_valid()) { CHECK(participant.order >= participants->min_order); participant.order = GroupCallParticipantOrder(); send_update_group_call_participant(input_group_call_id, participant, "try_clear_group_call_participants"); + + if (participant.is_self) { + need_update |= set_group_call_participant_count(group_call, group_call->participant_count - 1, + "try_clear_group_call_participants"); + } } on_remove_group_call_participant(input_group_call_id, participant.dialog_id); } @@ -3592,6 +3607,7 @@ void GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_ if (group_call_participants_.empty()) { CHECK(participant_id_to_group_call_id_.empty()); } + return need_update; } InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptr &group_call_ptr, @@ -3799,10 +3815,10 @@ InputGroupCallId GroupCallManager::update_group_call(const tl_object_ptrdialog_id.is_valid()) { return; } diff --git a/td/telegram/GroupCallManager.h b/td/telegram/GroupCallManager.h index dea1ff4ca..7d5694b2b 100644 --- a/td/telegram/GroupCallManager.h +++ b/td/telegram/GroupCallManager.h @@ -291,7 +291,7 @@ class GroupCallManager : public Actor { static Result> get_group_call_join_response_object( string json_response); - void try_clear_group_call_participants(InputGroupCallId input_group_call_id); + bool try_clear_group_call_participants(InputGroupCallId input_group_call_id); bool set_group_call_participant_count(GroupCall *group_call, int32 count, const char *source, bool force_update = false); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 91996b455..6b84f74b6 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2675,10 +2675,10 @@ class CliClient final : public Actor { } else if (op == "gvcap") { send_request(td_api::make_object(as_chat_id(args))); } else if (op == "svcdp") { - string group_call_id; + string chat_id; string participant_id; - get_args(args, group_call_id, participant_id); - send_request(td_api::make_object(as_chat_id(args), + get_args(args, chat_id, participant_id); + send_request(td_api::make_object(as_chat_id(chat_id), as_message_sender(participant_id))); } else if (op == "cvc") { string chat_id; From c87acefd56dac9bdc2a913b6df517acb5356d478 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 11 Apr 2021 02:37:01 +0300 Subject: [PATCH 244/281] Use correct group call participant ID for self. --- td/telegram/GroupCallManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 7081ad14c..6e805470f 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -3174,6 +3174,7 @@ void GroupCallManager::toggle_group_call_participant_is_muted(GroupCallId group_ if (participant == nullptr) { return promise.set_error(Status::Error(400, "Can't find group call participant")); } + dialog_id = participant->dialog_id; bool can_manage = can_manage_group_call(input_group_call_id); bool is_admin = td::contains(participants->administrator_dialog_ids, dialog_id); @@ -3268,6 +3269,7 @@ void GroupCallManager::set_group_call_participant_volume_level(GroupCallId group if (participant == nullptr) { return promise.set_error(Status::Error(400, "Can't find group call participant")); } + dialog_id = participant->dialog_id; if (participant->is_self) { return promise.set_error(Status::Error(400, "Can't change self volume level")); @@ -3357,6 +3359,7 @@ void GroupCallManager::toggle_group_call_participant_is_hand_raised(GroupCallId if (participant == nullptr) { return promise.set_error(Status::Error(400, "Can't find group call participant")); } + dialog_id = participant->dialog_id; if (is_hand_raised == participant->get_is_hand_raised()) { return promise.set_value(Unit()); From 4b212b07284211aa0ce6f740e20ab536142037d1 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 11 Apr 2021 03:39:30 +0300 Subject: [PATCH 245/281] Restore correct can_* flags after failed mute/unmute. --- td/telegram/GroupCallManager.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 6e805470f..d9b5d206f 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -3218,14 +3218,17 @@ void GroupCallManager::on_toggle_group_call_participant_is_muted(InputGroupCallI return promise.set_value(Unit()); } - auto participant = get_group_call_participant(input_group_call_id, dialog_id); + auto participants = add_group_call_participants(input_group_call_id); + auto participant = get_group_call_participant(participants, dialog_id); if (participant == nullptr || participant->pending_is_muted_generation != generation) { return promise.set_value(Unit()); } CHECK(participant->have_pending_is_muted); participant->have_pending_is_muted = false; - if (participant->server_is_muted_by_themselves != participant->pending_is_muted_by_themselves || + bool can_manage = can_manage_group_call(input_group_call_id); + if (update_group_call_participant_can_be_muted(can_manage, participants, *participant) || + participant->server_is_muted_by_themselves != participant->pending_is_muted_by_themselves || participant->server_is_muted_by_admin != participant->pending_is_muted_by_admin || participant->server_is_muted_locally != participant->pending_is_muted_locally) { LOG(ERROR) << "Failed to mute/unmute " << dialog_id << " in " << input_group_call_id; From 47a7bc05e2464a62caf2d90c1a6cead4542ee98f Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 11 Apr 2021 05:37:53 +0300 Subject: [PATCH 246/281] Use service messages to synchronize active group call state. --- td/telegram/MessageContent.cpp | 6 ++++++ td/telegram/MessageContent.h | 3 +++ td/telegram/MessagesManager.cpp | 24 ++++++++++++++++++++++-- td/telegram/MessagesManager.h | 2 ++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index feebce40e..feb7c0c59 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -2593,6 +2593,12 @@ FullMessageId get_message_content_replied_message_id(DialogId dialog_id, const M } } +std::pair get_message_content_group_call_info(const MessageContent *content) { + CHECK(content->get_type() == MessageContentType::GroupCall); + auto message_group_call = static_cast(content); + return {message_group_call->input_group_call_id, message_group_call->duration >= 0}; +} + vector get_message_content_added_user_ids(const MessageContent *content) { CHECK(content->get_type() == MessageContentType::ChatAddUsers); return static_cast(content)->user_ids; diff --git a/td/telegram/MessageContent.h b/td/telegram/MessageContent.h index d0186e277..5d3148e0c 100644 --- a/td/telegram/MessageContent.h +++ b/td/telegram/MessageContent.h @@ -9,6 +9,7 @@ #include "td/telegram/DialogId.h" #include "td/telegram/files/FileId.h" #include "td/telegram/FullMessageId.h" +#include "td/telegram/InputGroupCallId.h" #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/MessageContentType.h" #include "td/telegram/MessageCopyOptions.h" @@ -132,6 +133,8 @@ MessageId get_message_content_pinned_message_id(const MessageContent *content); FullMessageId get_message_content_replied_message_id(DialogId dialog_id, const MessageContent *content); +std::pair get_message_content_group_call_info(const MessageContent *content); + vector get_message_content_added_user_ids(const MessageContent *content); UserId get_message_content_deleted_user_id(const MessageContent *content); diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 26cc52e12..3d7d2afcb 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -29861,11 +29861,10 @@ void MessagesManager::on_update_dialog_group_call_id(DialogId dialog_id, InputGr } if (d->active_group_call_id != input_group_call_id) { + LOG(INFO) << "Update active group call in " << dialog_id << " to " << input_group_call_id; d->active_group_call_id = input_group_call_id; bool has_active_group_call = input_group_call_id.is_valid(); if (has_active_group_call != d->has_active_group_call) { - LOG(ERROR) << "Receive invalid has_active_group_call flag " << d->has_active_group_call << ", but have " - << input_group_call_id << " in " << dialog_id; d->has_active_group_call = has_active_group_call; if (!has_active_group_call) { d->is_group_call_empty = false; @@ -32607,6 +32606,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } if (from_update) { + speculatively_update_active_group_call_id(d, m); speculatively_update_channel_participants(dialog_id, m); update_sent_message_contents(dialog_id, m); update_used_hashtags(dialog_id, m); @@ -36055,6 +36055,26 @@ void MessagesManager::reget_message_from_server_if_needed(DialogId dialog_id, co } } +void MessagesManager::speculatively_update_active_group_call_id(Dialog *d, const Message *m) { + CHECK(m != nullptr); + if (!m->message_id.is_any_server() || m->content->get_type() != MessageContentType::GroupCall) { + return; + } + + InputGroupCallId input_group_call_id; + bool is_ended; + std::tie(input_group_call_id, is_ended) = get_message_content_group_call_info(m->content.get()); + if (is_ended) { + if (d->active_group_call_id == input_group_call_id) { + on_update_dialog_group_call_id(d->dialog_id, InputGroupCallId()); + } + } else { + if (d->active_group_call_id != input_group_call_id) { + repair_dialog_active_group_call_id(d->dialog_id); + } + } +} + void MessagesManager::speculatively_update_channel_participants(DialogId dialog_id, const Message *m) { CHECK(m != nullptr); if (!m->message_id.is_any_server() || dialog_id.get_type() != DialogType::Channel || !m->sender_user_id.is_valid()) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 8cfb6a616..418f1841a 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2881,6 +2881,8 @@ class MessagesManager : public Actor { void reget_message_from_server_if_needed(DialogId dialog_id, const Message *m); + void speculatively_update_active_group_call_id(Dialog *d, const Message *m); + void speculatively_update_channel_participants(DialogId dialog_id, const Message *m); void update_sent_message_contents(DialogId dialog_id, const Message *m); From 2ddeead75f951a32912929e4ff46c2fcaa82e54f Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 12 Apr 2021 02:49:28 +0300 Subject: [PATCH 247/281] Save expected active group call ID. --- td/telegram/MessagesManager.cpp | 9 ++++++++- td/telegram/MessagesManager.h | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 3d7d2afcb..dfc2f15dc 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -8222,7 +8222,11 @@ void MessagesManager::repair_dialog_active_group_call_id(DialogId dialog_id) { void MessagesManager::do_repair_dialog_active_group_call_id(DialogId dialog_id) { Dialog *d = get_dialog(dialog_id); CHECK(d != nullptr); - if (!d->has_active_group_call || d->active_group_call_id.is_valid()) { + bool need_repair_active_group_call_id = d->has_active_group_call && !d->active_group_call_id.is_valid(); + bool need_repair_expected_group_call_id = + d->has_expected_active_group_call_id && d->active_group_call_id != d->expected_active_group_call_id; + d->has_expected_active_group_call_id = false; + if (!need_repair_active_group_call_id && !need_repair_expected_group_call_id) { return; } if (!have_input_peer(dialog_id, AccessRights::Read)) { @@ -36064,11 +36068,14 @@ void MessagesManager::speculatively_update_active_group_call_id(Dialog *d, const InputGroupCallId input_group_call_id; bool is_ended; std::tie(input_group_call_id, is_ended) = get_message_content_group_call_info(m->content.get()); + d->has_expected_active_group_call_id = true; if (is_ended) { + d->expected_active_group_call_id = InputGroupCallId(); if (d->active_group_call_id == input_group_call_id) { on_update_dialog_group_call_id(d->dialog_id, InputGroupCallId()); } } else { + d->expected_active_group_call_id = input_group_call_id; if (d->active_group_call_id != input_group_call_id) { repair_dialog_active_group_call_id(d->dialog_id); } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 418f1841a..5a0b9a552 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1168,6 +1168,7 @@ class MessagesManager : public Actor { std::unordered_set updated_read_history_message_ids; LogEventIdWithGeneration set_folder_id_log_event_id; InputGroupCallId active_group_call_id; + InputGroupCallId expected_active_group_call_id; DialogId default_join_group_call_as_dialog_id; FolderId folder_id; @@ -1244,6 +1245,7 @@ class MessagesManager : public Actor { bool has_active_group_call = false; bool is_group_call_empty = false; bool is_message_ttl_setting_inited = false; + bool has_expected_active_group_call_id = false; bool increment_view_counter = false; From 105542fc9a3b3c623e403df7fccc503ce55690c4 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 12 Apr 2021 03:51:10 +0300 Subject: [PATCH 248/281] Speculatively update participant count when joining/leaving channels. --- td/telegram/ContactsManager.cpp | 9 ++++++++- td/telegram/ContactsManager.h | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 002830e57..32fcfc27d 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -6782,6 +6782,7 @@ void ContactsManager::add_channel_participant(ChannelId channel_id, UserId user_ return promise.set_error(Status::Error(3, "Can't return to kicked from chat")); } + speculative_add_channel_user(channel_id, user_id, DialogParticipantStatus::Member(), c->status); td_->create_handler(std::move(promise))->send(channel_id); return; } @@ -7401,6 +7402,7 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, UserId } // leave the channel + speculative_add_channel_user(channel_id, user_id, status, c->status); td_->create_handler(std::move(promise))->send(channel_id); return; } @@ -12961,6 +12963,10 @@ void ContactsManager::on_channel_status_changed(Channel *c, ChannelId channel_id if (old_status.is_member() != new_status.is_member() || new_status.is_banned()) { remove_dialog_access_by_invite_link(DialogId(channel_id)); + + if (new_status.is_member()) { + reload_channel_full(channel_id, Promise(), "on_channel_status_changed"); + } } if (need_reload_group_call) { send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_group_call_rights, @@ -14372,7 +14378,8 @@ void ContactsManager::add_dialog_participant(DialogId dialog_id, UserId user_id, case DialogType::Chat: return add_chat_participant(dialog_id.get_chat_id(), user_id, forward_limit, std::move(promise)); case DialogType::Channel: - return add_channel_participant(dialog_id.get_channel_id(), user_id, std::move(promise)); + return add_channel_participant(dialog_id.get_channel_id(), user_id, std::move(promise), + DialogParticipantStatus::Left()); case DialogType::SecretChat: return promise.set_error(Status::Error(3, "Can't add members to a secret chat")); case DialogType::None: diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 5d7fbaf1f..530c8ec95 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -1407,7 +1407,7 @@ class ContactsManager : public Actor { void add_chat_participant(ChatId chat_id, UserId user_id, int32 forward_limit, Promise &&promise); void add_channel_participant(ChannelId channel_id, UserId user_id, Promise &&promise, - DialogParticipantStatus old_status = DialogParticipantStatus::Left()); + DialogParticipantStatus old_status); void add_channel_participants(ChannelId channel_id, const vector &user_ids, Promise &&promise); From e72863ff84df388baaa05b881028032dc6e478aa Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 12 Apr 2021 04:20:43 +0300 Subject: [PATCH 249/281] Drop repair_request_version after failed GetChannelFullQuery. --- td/telegram/ContactsManager.cpp | 23 +++++++++++++++++++++++ td/telegram/ContactsManager.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 32fcfc27d..9736680e9 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -2788,6 +2788,7 @@ class GetChatsQuery : public Td::ResultHandler { class GetFullChatQuery : public Td::ResultHandler { Promise promise_; + ChatId chat_id_; public: explicit GetFullChatQuery(Promise &&promise) : promise_(std::move(promise)) { @@ -2811,6 +2812,7 @@ class GetFullChatQuery : public Td::ResultHandler { } void on_error(uint64 id, Status status) override { + td->contacts_manager_->on_get_chat_full_failed(chat_id_); promise_.set_error(std::move(status)); } }; @@ -2895,6 +2897,7 @@ class GetFullChannelQuery : public Td::ResultHandler { void on_error(uint64 id, Status status) override { td->contacts_manager_->on_get_channel_error(channel_id_, status, "GetFullChannelQuery"); + td->contacts_manager_->on_get_channel_full_failed(channel_id_); promise_.set_error(std::move(status)); } }; @@ -10672,6 +10675,26 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c promise.set_value(Unit()); } +void ContactsManager::on_get_chat_full_failed(ChatId chat_id) { + if (G()->close_flag()) { + return; + } + + LOG(INFO) << "Failed to get " << chat_id; +} + +void ContactsManager::on_get_channel_full_failed(ChannelId channel_id) { + if (G()->close_flag()) { + return; + } + + LOG(INFO) << "Failed to get " << channel_id; + auto channel_full = get_channel_full(channel_id, "on_get_channel_full"); + if (channel_full != nullptr) { + channel_full->repair_request_version = 0; + } +} + bool ContactsManager::is_update_about_username_change_received(UserId user_id) const { const User *u = get_user(user_id); if (u != nullptr) { diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 530c8ec95..05ed62537 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -177,6 +177,8 @@ class ContactsManager : public Actor { void on_get_chats(vector> &&chats, const char *source); void on_get_chat_full(tl_object_ptr &&chat_full, Promise &&promise); + void on_get_chat_full_failed(ChatId chat_id); + void on_get_channel_full_failed(ChannelId channel_id); void on_update_profile_success(int32 flags, const string &first_name, const string &last_name, const string &about); void on_set_bot_commands_success(vector> &&commands); From bdb7c833fd418aba05fdc2e3575e4c5a71e442c2 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 12 Apr 2021 04:42:42 +0300 Subject: [PATCH 250/281] Improve fatal error message. --- td/telegram/MessagesManager.cpp | 19 +++++++++++-------- td/telegram/MessagesManager.h | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index fe5f20084..2f39d077d 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -16043,7 +16043,7 @@ void MessagesManager::on_get_dialog_filters(Resultcontacts_manager_.get()](vector &input_dialog_ids) { std::sort(input_dialog_ids.begin(), input_dialog_ids.end(), @@ -17814,7 +17814,10 @@ void MessagesManager::sort_dialog_filter_input_dialog_ids(DialogFilter *dialog_f for (auto input_dialog_ids : {&dialog_filter->pinned_dialog_ids, &dialog_filter->excluded_dialog_ids, &dialog_filter->included_dialog_ids}) { for (auto input_dialog_id : *input_dialog_ids) { - CHECK(all_dialog_ids.insert(input_dialog_id.get_dialog_id()).second); + LOG_CHECK(all_dialog_ids.insert(input_dialog_id.get_dialog_id()).second) + << source << ' ' << td::contains(dialog_filter->pinned_dialog_ids, input_dialog_id) << ' ' + << td::contains(dialog_filter->excluded_dialog_ids, input_dialog_id) << ' ' + << td::contains(dialog_filter->included_dialog_ids, input_dialog_id); } } } @@ -17877,7 +17880,7 @@ Result> MessagesManager::create_dialog_filter(DialogFil dialog_filter->include_channels = filter->include_channels_; TRY_STATUS(dialog_filter->check_limits()); - sort_dialog_filter_input_dialog_ids(dialog_filter.get()); + sort_dialog_filter_input_dialog_ids(dialog_filter.get(), "create_dialog_filter"); return std::move(dialog_filter); } @@ -18692,7 +18695,7 @@ Status MessagesManager::toggle_dialog_is_pinned(DialogListId dialog_list_id, Dia } TRY_STATUS(new_dialog_filter->check_limits()); - sort_dialog_filter_input_dialog_ids(new_dialog_filter.get()); + sort_dialog_filter_input_dialog_ids(new_dialog_filter.get(), "toggle_dialog_is_pinned"); edit_dialog_filter(std::move(new_dialog_filter), "toggle_dialog_is_pinned"); save_dialog_filters(); @@ -18848,7 +18851,7 @@ Status MessagesManager::set_pinned_dialogs(DialogListId dialog_list_id, vectorincluded_dialog_ids, old_pinned_dialog_ids); TRY_STATUS(new_dialog_filter->check_limits()); - sort_dialog_filter_input_dialog_ids(new_dialog_filter.get()); + sort_dialog_filter_input_dialog_ids(new_dialog_filter.get(), "set_pinned_dialogs"); edit_dialog_filter(std::move(new_dialog_filter), "set_pinned_dialogs"); save_dialog_filters(); @@ -30738,7 +30741,7 @@ void MessagesManager::add_dialog_to_list(DialogId dialog_id, DialogListId dialog if (status.is_error()) { return promise.set_error(std::move(status)); } - sort_dialog_filter_input_dialog_ids(new_dialog_filter.get()); + sort_dialog_filter_input_dialog_ids(new_dialog_filter.get(), "add_dialog_to_list"); edit_dialog_filter(std::move(new_dialog_filter), "add_dialog_to_list"); save_dialog_filters(); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index e1d27ccce..a436564a6 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2472,7 +2472,7 @@ class MessagesManager : public Actor { InputDialogId get_input_dialog_id(DialogId dialog_id) const; - void sort_dialog_filter_input_dialog_ids(DialogFilter *dialog_filter) const; + void sort_dialog_filter_input_dialog_ids(DialogFilter *dialog_filter, const char *source) const; Result> create_dialog_filter(DialogFilterId dialog_filter_id, td_api::object_ptr filter); From eb8e135ae3eaff8c83df6a7227063bb6511bc8e9 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 12 Apr 2021 04:45:35 +0300 Subject: [PATCH 251/281] Fix dropping group call's can_be_managed flag on leaving. --- td/telegram/GroupCallManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index e57cb8442..b5f3f6dc2 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -3231,7 +3231,9 @@ void GroupCallManager::on_group_call_left_impl(GroupCall *group_call, bool need_ } group_call->is_being_left = false; group_call->is_speaking = false; - group_call->can_be_managed = false; + if (!group_call->is_active) { + group_call->can_be_managed = false; + } group_call->joined_date = 0; group_call->audio_source = 0; check_group_call_is_joined_timeout_.cancel_timeout(group_call->group_call_id.get()); From a83362c4d12c5b169f0d06be47d4c8fef5a7c60c Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 12 Apr 2021 04:51:01 +0300 Subject: [PATCH 252/281] Add source to on_load_channel_full_from_database. --- td/telegram/ContactsManager.cpp | 13 +++++++------ td/telegram/ContactsManager.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 9736680e9..3bbf42129 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -9236,7 +9236,7 @@ void ContactsManager::on_load_user_full_from_database(UserId user_id, string val Dependencies dependencies; dependencies.user_ids.insert(user_id); - if (!resolve_dependencies_force(td_, dependencies, "user_full")) { + if (!resolve_dependencies_force(td_, dependencies, "on_load_user_full_from_database")) { users_full_.erase(user_id); G()->td_db()->get_sqlite_pmc()->erase(get_user_full_database_key(user_id), Auto()); return; @@ -9427,7 +9427,7 @@ void ContactsManager::on_load_chat_full_from_database(ChatId chat_id, string val dependencies.user_ids.insert(participant.inviter_user_id); } dependencies.user_ids.insert(chat_full->invite_link.get_creator_user_id()); - if (!resolve_dependencies_force(td_, dependencies, "chat_full")) { + if (!resolve_dependencies_force(td_, dependencies, "on_load_chat_full_from_database")) { chats_full_.erase(chat_id); G()->td_db()->get_sqlite_pmc()->erase(get_chat_full_database_key(chat_id), Auto()); return; @@ -9508,8 +9508,9 @@ string ContactsManager::get_channel_full_database_value(const ChannelFull *chann return log_event_store(*channel_full).as_slice().str(); } -void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, string value) { - LOG(INFO) << "Successfully loaded full " << channel_id << " of size " << value.size() << " from database"; +void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, string value, const char *source) { + LOG(INFO) << "Successfully loaded full " << channel_id << " of size " << value.size() << " from database from " + << source; // G()->td_db()->get_sqlite_pmc()->erase(get_channel_full_database_key(channel_id), Auto()); // return; @@ -9535,7 +9536,7 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s dependencies.chat_ids.insert(channel_full->migrated_from_chat_id); dependencies.user_ids.insert(channel_full->bot_user_ids.begin(), channel_full->bot_user_ids.end()); dependencies.user_ids.insert(channel_full->invite_link.get_creator_user_id()); - if (!resolve_dependencies_force(td_, dependencies, "channel_full")) { + if (!resolve_dependencies_force(td_, dependencies, source)) { channels_full_.erase(channel_id); G()->td_db()->get_sqlite_pmc()->erase(get_channel_full_database_key(channel_id), Auto()); return; @@ -9612,7 +9613,7 @@ ContactsManager::ChannelFull *ContactsManager::get_channel_full_force(ChannelId LOG(INFO) << "Trying to load full " << channel_id << " from database from " << source; on_load_channel_full_from_database( - channel_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_channel_full_database_key(channel_id))); + channel_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_channel_full_database_key(channel_id)), source); return get_channel_full(channel_id, source); } diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 05ed62537..241ea3874 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -1332,7 +1332,7 @@ class ContactsManager : public Actor { void save_channel_full(const ChannelFull *channel_full, ChannelId channel_id); static string get_channel_full_database_key(ChannelId channel_id); static string get_channel_full_database_value(const ChannelFull *channel_full); - void on_load_channel_full_from_database(ChannelId channel_id, string value); + void on_load_channel_full_from_database(ChannelId channel_id, string value, const char *source); void update_user(User *u, UserId user_id, bool from_binlog = false, bool from_database = false); void update_chat(Chat *c, ChatId chat_id, bool from_binlog = false, bool from_database = false); From 5ec3b9cfce1006e57f3f77630a2267671ba39849 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 12 Apr 2021 05:11:06 +0300 Subject: [PATCH 253/281] Init MessagesManager on first call to get_dialog_force. --- td/telegram/MessagesManager.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 2f39d077d..9c6ba917e 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -27110,8 +27110,6 @@ NotificationGroupId MessagesManager::get_dialog_notification_group_id(DialogId d Result MessagesManager::get_message_push_notification_info( DialogId dialog_id, MessageId message_id, int64 random_id, UserId sender_user_id, DialogId sender_dialog_id, int32 date, bool is_from_scheduled, bool contains_mention, bool is_pinned, bool is_from_binlog) { - init(); - if (!is_from_scheduled && dialog_id == get_my_dialog_id()) { return Status::Error("Ignore notification in chat with self"); } @@ -27548,8 +27546,6 @@ vector MessagesManager::get_message_notification_group_key return {}; } - init(); - VLOG(notifications) << "Trying to load " << limit << " message notification groups from database from " << from_group_key; @@ -34637,9 +34633,7 @@ bool MessagesManager::set_dialog_order(Dialog *d, int64 new_order, bool need_sen } auto folder_ptr = get_dialog_folder(d->folder_id); - LOG_CHECK(folder_ptr != nullptr) << is_inited_ << ' ' << G()->close_flag() << ' ' << dialog_id << ' ' << d->folder_id - << ' ' << is_loaded_from_database << ' ' << td_->auth_manager_->is_authorized() - << ' ' << td_->auth_manager_->was_authorized() << ' ' << source; + CHECK(folder_ptr != nullptr); auto &folder = *folder_ptr; if (old_date == new_date) { if (new_order == DEFAULT_ORDER) { @@ -34986,7 +34980,8 @@ bool MessagesManager::have_dialog_force(DialogId dialog_id, const char *source) } MessagesManager::Dialog *MessagesManager::get_dialog_force(DialogId dialog_id, const char *source) { - // TODO remove most usages of that function, preload dialog asynchronously if possible + init(); + auto it = dialogs_.find(dialog_id); if (it != dialogs_.end()) { return it->second.get(); From 1934bf3b0e32812983e47efc0c0e961be3bdb56a Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 12 Apr 2021 05:58:24 +0300 Subject: [PATCH 254/281] Fix repairing unread count in fix_new_dialog. --- td/telegram/MessagesManager.cpp | 67 +++++++++++++++++---------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 9c6ba917e..535f123fa 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -11831,8 +11831,7 @@ void MessagesManager::set_dialog_last_read_inbox_message_id(Dialog *d, MessageId if (d->message_notification_group.group_id.is_valid()) { auto total_count = get_dialog_pending_notification_count(d, false); if (total_count == 0) { - set_dialog_last_notification(d->dialog_id, d->message_notification_group, 0, NotificationId(), - "set_dialog_last_read_inbox_message_id"); + set_dialog_last_notification(d->dialog_id, d->message_notification_group, 0, NotificationId(), source); } if (!d->pending_new_message_notifications.empty()) { for (auto &it : d->pending_new_message_notifications) { @@ -11857,7 +11856,7 @@ void MessagesManager::set_dialog_last_read_inbox_message_id(Dialog *d, MessageId if (d->mention_notification_group.group_id.is_valid() && d->pinned_message_notification_message_id.is_valid() && d->pinned_message_notification_message_id <= d->last_read_inbox_message_id) { // remove pinned message notification when it is read - remove_dialog_pinned_message_notification(d, "set_dialog_last_read_inbox_message_id 2"); + remove_dialog_pinned_message_notification(d, source); } } @@ -34305,36 +34304,6 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab LOG(ERROR) << dialog_id << " has order " << d->order << " instead of saved to database order " << order; } - // must be after update_dialog_pos, because uses d->order - if (d->pending_read_channel_inbox_pts != 0 && !td_->auth_manager_->is_bot() && - have_input_peer(dialog_id, AccessRights::Read) && need_unread_counter(d->order)) { - if (d->pts == d->pending_read_channel_inbox_pts) { - read_history_inbox(dialog_id, d->pending_read_channel_inbox_max_message_id, - d->pending_read_channel_inbox_server_unread_count, "fix_new_dialog 12"); - d->pending_read_channel_inbox_pts = 0; - on_dialog_updated(dialog_id, "fix_new_dialog 13"); - } else if (d->pts > d->pending_read_channel_inbox_pts) { - d->need_repair_channel_server_unread_count = true; - d->pending_read_channel_inbox_pts = 0; - on_dialog_updated(dialog_id, "fix_new_dialog 14"); - } else { - channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), 0.001); - } - } else { - d->pending_read_channel_inbox_pts = 0; - } - if (need_get_history && !td_->auth_manager_->is_bot() && dialog_id != being_added_dialog_id_ && - have_input_peer(dialog_id, AccessRights::Read) && (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) { - get_history_from_the_end(dialog_id, true, false, Auto()); - } - if (d->need_repair_server_unread_count && need_unread_counter(d->order)) { - CHECK(dialog_type != DialogType::SecretChat); - repair_server_unread_count(dialog_id, d->server_unread_count); - } - if (d->need_repair_channel_server_unread_count) { - repair_channel_server_unread_count(d); - } - LOG(INFO) << "Loaded " << dialog_id << " with last new " << d->last_new_message_id << ", first database " << d->first_database_message_id << ", last database " << d->last_database_message_id << ", last " << d->last_message_id << " with order " << d->order; @@ -34363,6 +34332,38 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab LOG_CHECK(d->messages->left == nullptr) << get_debug_source(d->messages->left); LOG_CHECK(d->messages->right == nullptr) << get_debug_source(d->messages->right); } + + // must be after update_dialog_pos, because uses d->order + // must be after checks that dialog has at most one message, because read_history_inbox can load + // pinned message to remove its notification + if (d->pending_read_channel_inbox_pts != 0 && !td_->auth_manager_->is_bot() && + have_input_peer(dialog_id, AccessRights::Read) && need_unread_counter(d->order)) { + if (d->pts == d->pending_read_channel_inbox_pts) { + d->pending_read_channel_inbox_pts = 0; + read_history_inbox(dialog_id, d->pending_read_channel_inbox_max_message_id, + d->pending_read_channel_inbox_server_unread_count, "fix_new_dialog 12"); + on_dialog_updated(dialog_id, "fix_new_dialog 13"); + } else if (d->pts > d->pending_read_channel_inbox_pts) { + d->need_repair_channel_server_unread_count = true; + d->pending_read_channel_inbox_pts = 0; + on_dialog_updated(dialog_id, "fix_new_dialog 14"); + } else { + channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), 0.001); + } + } else { + d->pending_read_channel_inbox_pts = 0; + } + if (need_get_history && !td_->auth_manager_->is_bot() && dialog_id != being_added_dialog_id_ && + have_input_peer(dialog_id, AccessRights::Read) && (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) { + get_history_from_the_end(dialog_id, true, false, Auto()); + } + if (d->need_repair_server_unread_count && need_unread_counter(d->order)) { + CHECK(dialog_type != DialogType::SecretChat); + repair_server_unread_count(dialog_id, d->server_unread_count); + } + if (d->need_repair_channel_server_unread_count) { + repair_channel_server_unread_count(d); + } } void MessagesManager::add_dialog_last_database_message(Dialog *d, unique_ptr &&last_database_message) { From c7b00632604994d0c63d2ba6a534ef3760d8f19f Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 12 Apr 2021 06:04:43 +0300 Subject: [PATCH 255/281] Add source to parse_dialog. --- td/telegram/MessagesManager.cpp | 19 ++++++++++--------- td/telegram/MessagesManager.h | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 535f123fa..e167caf60 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -33881,7 +33881,7 @@ MessagesManager::Dialog *MessagesManager::add_dialog(DialogId dialog_id, const c auto r_value = G()->td_db()->get_dialog_db_sync()->get_dialog(dialog_id); if (r_value.is_ok()) { LOG(INFO) << "Synchronously loaded " << dialog_id << " from database"; - return add_new_dialog(parse_dialog(dialog_id, r_value.ok()), true, source); + return add_new_dialog(parse_dialog(dialog_id, r_value.ok(), source), true, source); } } @@ -35005,8 +35005,9 @@ MessagesManager::Dialog *MessagesManager::get_dialog_force(DialogId dialog_id, c } } -unique_ptr MessagesManager::parse_dialog(DialogId dialog_id, const BufferSlice &value) { - LOG(INFO) << "Loaded " << dialog_id << " of size " << value.size() << " from database"; +unique_ptr MessagesManager::parse_dialog(DialogId dialog_id, const BufferSlice &value, + const char *source) { + LOG(INFO) << "Loaded " << dialog_id << " of size " << value.size() << " from database from " << source; auto d = make_unique(); d->dialog_id = dialog_id; invalidate_message_indexes(d.get()); // must initialize indexes, because some of them could be not parsed @@ -35018,7 +35019,7 @@ unique_ptr MessagesManager::parse_dialog(DialogId dialo // can't happen unless database is broken, but has been seen in the wild // if dialog_id is invalid, we can't repair the dialog LOG_CHECK(dialog_id.is_valid()) << "Can't repair " << dialog_id << ' ' << d->dialog_id << ' ' << status << ' ' - << format::as_hex_dump<4>(value.as_slice()); + << source << ' ' << format::as_hex_dump<4>(value.as_slice()); LOG(ERROR) << "Repair broken " << dialog_id << ' ' << format::as_hex_dump<4>(value.as_slice()); @@ -35031,10 +35032,10 @@ unique_ptr MessagesManager::parse_dialog(DialogId dialo have_dialog_info_force(dialog_id); if (have_input_peer(dialog_id, AccessRights::Read)) { if (dialog_id.get_type() != DialogType::SecretChat) { - send_get_dialog_query(dialog_id, Auto(), 0, "parse_dialog"); + send_get_dialog_query(dialog_id, Auto(), 0, source); } } else { - LOG(ERROR) << "Have no info about " << dialog_id << " to repair it"; + LOG(ERROR) << "Have no info about " << dialog_id << " from " << source << " to repair it"; } } CHECK(dialog_id == d->dialog_id); @@ -35050,8 +35051,8 @@ unique_ptr MessagesManager::parse_dialog(DialogId dialo if (d->draft_message != nullptr) { add_formatted_text_dependencies(dependencies, &d->draft_message->input_message_text.text); } - if (!resolve_dependencies_force(td_, dependencies, "parse_dialog")) { - send_get_dialog_query(dialog_id, Auto(), 0, "parse_dialog"); + if (!resolve_dependencies_force(td_, dependencies, source)) { + send_get_dialog_query(dialog_id, Auto(), 0, source); } return d; @@ -35080,7 +35081,7 @@ MessagesManager::Dialog *MessagesManager::on_load_dialog_from_database(DialogId } LOG(INFO) << "Add new " << dialog_id << " from database from " << source; - return add_new_dialog(parse_dialog(dialog_id, value), true, source); + return add_new_dialog(parse_dialog(dialog_id, value, source), true, source); } const DialogFilter *MessagesManager::get_server_dialog_filter(DialogFilterId dialog_filter_id) const { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index a436564a6..9830896d5 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2906,7 +2906,7 @@ class MessagesManager : public Actor { unique_ptr parse_message(DialogId dialog_id, const BufferSlice &value, bool is_scheduled); - unique_ptr parse_dialog(DialogId dialog_id, const BufferSlice &value); + unique_ptr parse_dialog(DialogId dialog_id, const BufferSlice &value, const char *source); void load_calls_db_state(); void save_calls_db_state(); From 69318bf3882ac74c9670798c57efbf0b4e088f55 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Mon, 12 Apr 2021 16:22:04 +0200 Subject: [PATCH 256/281] Fix build urls --- build.html | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/build.html b/build.html index 2cb47895f..6393d16f5 100644 --- a/build.html +++ b/build.html @@ -300,14 +300,14 @@ function getTargetName(target) { case 'tdjson': case 'WebAssembly': case 'iOS': - return 'JSON'; + return 'JSON'; case 'tdclient': - return 'a simple and convenient C++11-interface'; + return 'a simple and convenient C++11-interface'; case 'JNI': case 'Android': - return 'native ' + target + ''; + return 'native ' + target + ''; default: - return 'native ' + target + ''; + return 'native ' + target + ''; } } @@ -322,16 +322,16 @@ function onOsChanged() { language = 'any other programming language'; } var text = 'TDLib can be used from ' + language + ' on ' + os + ' through the ' + getTargetName(target) + ' interface.
' + - 'See examples of such usage and already available third-party frameworks.
'; + 'See examples of such usage and already available third-party frameworks.
'; if (target === 'WebAssembly') { text = 'TDLib is available in a prebuilt form as an NPM package tdweb.
' + - 'If you want to build it manually, take a look at our example.'; + 'If you want to build it manually, take a look at our example.'; target = ''; } if (target === 'Android') { - text = 'TDLib for Android is available in a prebuilt form and can be downloaded from there.
' + - 'See build instructions if you want to build the latest TDLib version or want to build TDLib with different interface.'; + text = 'TDLib for Android is available in a prebuilt form and can be downloaded from there.
' + + 'See build instructions if you want to build the latest TDLib version or want to build TDLib with different interface.'; target = ''; } if (target === 'iOS') { @@ -712,7 +712,7 @@ function onOptionsChanged() { commands.push('exit'); } } - commands.push('git clone https://github.com/tdlib/td.git'); + commands.push('git clone https://github.com/tdlight-team/tdlight.git'); commands.push('cd td'); // commands.push('git checkout v1.7.0'); From 6fe2f1e77a0f058f873084560a9857a6eb6b740e Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Mon, 12 Apr 2021 16:26:09 +0200 Subject: [PATCH 257/281] Rerand build instructions --- build.html | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/build.html b/build.html index 6393d16f5..39292a1ca 100644 --- a/build.html +++ b/build.html @@ -2,7 +2,7 @@ -TDLib build instructions +TDLight build instructions