diff --git a/td/telegram/SecretChatActor.cpp b/td/telegram/SecretChatActor.cpp index 13ffbf93f..3e1b32ab1 100644 --- a/td/telegram/SecretChatActor.cpp +++ b/td/telegram/SecretChatActor.cpp @@ -115,7 +115,7 @@ void SecretChatActor::on_result_resendable(NetQueryPtr net_query, Promiseid()); if (close_flag_) { if (key == static_cast(QueryType::DiscardEncryption)) { - on_discard_encryption_result(std::move(net_query)); + discard_encryption_promise_.set_value(Unit()); } return; } @@ -140,7 +140,7 @@ void SecretChatActor::on_result_resendable(NetQueryPtr net_query, Promise event) { - do_close_chat_impl(event->delete_history, event->log_event_id()); + do_close_chat_impl(event->delete_history, event->is_already_discarded, event->log_event_id(), Promise()); } void SecretChatActor::replay_create_chat(unique_ptr event) { @@ -709,10 +709,10 @@ void SecretChatActor::check_status(Status status) { void SecretChatActor::on_fatal_error(Status status) { LOG(ERROR) << "Fatal error: " << status; - cancel_chat(false, Promise<>()); + cancel_chat(false, false, Promise<>()); } -void SecretChatActor::cancel_chat(bool delete_history, Promise<> promise) { +void SecretChatActor::cancel_chat(bool delete_history, bool is_already_discarded, Promise<> promise) { if (close_flag_) { promise.set_value(Unit()); return; @@ -737,11 +737,11 @@ void SecretChatActor::cancel_chat(bool delete_history, Promise<> promise) { event->chat_id = auth_state_.id; auto log_event_id = binlog_add(context_->binlog(), LogEvent::HandlerType::SecretChats, create_storer(*event)); - auto on_sync = PromiseCreator::lambda([actor_id = actor_id(this), delete_history, log_event_id, + auto on_sync = PromiseCreator::lambda([actor_id = actor_id(this), delete_history, is_already_discarded, log_event_id, promise = std::move(promise)](Result result) mutable { if (result.is_ok()) { - send_closure(actor_id, &SecretChatActor::do_close_chat_impl, delete_history, log_event_id); - promise.set_value(Unit()); + send_closure(actor_id, &SecretChatActor::do_close_chat_impl, delete_history, is_already_discarded, log_event_id, + std::move(promise)); } else { promise.set_error(result.error().clone()); send_closure(actor_id, &SecretChatActor::on_promise_error, result.move_as_error(), "cancel_chat"); @@ -752,25 +752,56 @@ void SecretChatActor::cancel_chat(bool delete_history, Promise<> promise) { yield(); } -void SecretChatActor::do_close_chat_impl(bool delete_history, uint64 log_event_id) { +void SecretChatActor::do_close_chat_impl(bool delete_history, bool is_already_discarded, uint64 log_event_id, + Promise &&promise) { close_flag_ = true; - close_log_event_id_ = log_event_id; - LOG(INFO) << "Send messages.discardEncryption"; auth_state_.state = State::Closed; context_->secret_chat_db()->set_value(auth_state_); context_->secret_chat_db()->erase_value(config_state_); context_->secret_chat_db()->erase_value(pfs_state_); context_->secret_chat_db()->erase_value(seq_no_state_); - int32 flags = 0; + + MultiPromiseActorSafe mpas{"DeleteMessagesFromServerMultiPromiseActor"}; + mpas.add_promise( + PromiseCreator::lambda([actor_id = actor_id(this), log_event_id, promise = std::move(promise)](Unit) mutable { + send_closure(actor_id, &SecretChatActor::on_closed, log_event_id, std::move(promise)); + })); + + auto lock = mpas.get_promise(); + if (delete_history) { - flags |= telegram_api::messages_discardEncryption::DELETE_HISTORY_MASK; + context_->on_flush_history(MessageId::max(), mpas.get_promise()); } - auto query = create_net_query(QueryType::DiscardEncryption, - telegram_api::messages_discardEncryption(flags, false /*ignored*/, auth_state_.id)); send_update_secret_chat(); - context_->send_net_query(std::move(query), actor_shared(this), true); + if (!is_already_discarded) { + int32 flags = 0; + if (delete_history) { + flags |= telegram_api::messages_discardEncryption::DELETE_HISTORY_MASK; + } + auto query = create_net_query(QueryType::DiscardEncryption, + telegram_api::messages_discardEncryption(flags, false /*ignored*/, auth_state_.id)); + query->total_timeout_limit_ = 60 * 60 * 24 * 365; + context_->send_net_query(std::move(query), actor_shared(this), true); + discard_encryption_promise_ = mpas.get_promise(); + } + + lock.set_value(Unit()); +} + +void SecretChatActor::on_closed(uint64 log_event_id, Promise &&promise) { + CHECK(close_flag_); + if (context_->close_flag()) { + return; + } + + LOG(INFO) << "Finish closing"; + context_->secret_chat_db()->erase_value(auth_state_); + binlog_erase(context_->binlog(), log_event_id); + promise.set_value(Unit()); + // skip flush + stop(); } void SecretChatActor::do_create_chat_impl(unique_ptr event) { @@ -793,18 +824,6 @@ void SecretChatActor::do_create_chat_impl(unique_ptrclose_flag()) { - return; - } - LOG(INFO) << "Got result for messages.discardEncryption"; - context_->secret_chat_db()->erase_value(auth_state_); - binlog_erase(context_->binlog(), close_log_event_id_); - // skip flush - stop(); -} telegram_api::object_ptr SecretChatActor::get_input_user() { return telegram_api::make_object(auth_state_.user_id, auth_state_.user_access_hash); @@ -1904,7 +1923,8 @@ Status SecretChatActor::on_update_chat(telegram_api::encryptedChat &update) { return Status::OK(); } Status SecretChatActor::on_update_chat(telegram_api::encryptedChatDiscarded &update) { - return Status::Error("Chat discarded"); + cancel_chat(update.history_deleted_, true, Promise()); + return Status::OK(); } Status SecretChatActor::on_update_chat(NetQueryPtr query) { diff --git a/td/telegram/SecretChatActor.h b/td/telegram/SecretChatActor.h index 01dd491ff..f2ff16a62 100644 --- a/td/telegram/SecretChatActor.h +++ b/td/telegram/SecretChatActor.h @@ -116,7 +116,7 @@ class SecretChatActor : public NetQueryCallback { void update_chat(telegram_api::object_ptr chat); void create_chat(int32 user_id, int64 user_access_hash, int32 random_id, Promise promise); - void cancel_chat(bool delete_history, Promise<> promise); + void cancel_chat(bool delete_history, bool is_already_discarded, Promise<> promise); // Inbound messages // Logevent is created by SecretChatsManager, because it must contain qts @@ -462,7 +462,7 @@ class SecretChatActor : public NetQueryCallback { bool binlog_replay_finish_flag_ = false; bool close_flag_ = false; - LogEvent::Id close_log_event_id_ = 0; + Promise discard_encryption_promise_; LogEvent::Id create_log_event_id_ = 0; @@ -638,8 +638,8 @@ class SecretChatActor : public NetQueryCallback { // DiscardEncryption void on_fatal_error(Status status); - void do_close_chat_impl(bool delete_history, uint64 log_event_id); - void on_discard_encryption_result(NetQueryPtr result); + void do_close_chat_impl(bool delete_history, bool is_already_discarded, uint64 log_event_id, Promise &&promise); + void on_closed(uint64 log_event_id, Promise &&promise); // Other template diff --git a/td/telegram/SecretChatsManager.cpp b/td/telegram/SecretChatsManager.cpp index a4dd084e9..6176b3586 100644 --- a/td/telegram/SecretChatsManager.cpp +++ b/td/telegram/SecretChatsManager.cpp @@ -109,7 +109,7 @@ void SecretChatsManager::create_chat(int32 user_id, int64 user_access_hash, Prom void SecretChatsManager::cancel_chat(SecretChatId secret_chat_id, bool delete_history, Promise<> promise) { auto actor = get_chat_actor(secret_chat_id.get()); auto safe_promise = SafePromise<>(std::move(promise), Unit()); - send_closure(actor, &SecretChatActor::cancel_chat, delete_history, std::move(safe_promise)); + send_closure(actor, &SecretChatActor::cancel_chat, delete_history, false, std::move(safe_promise)); } void SecretChatsManager::send_message(SecretChatId secret_chat_id, tl_object_ptr message, diff --git a/td/telegram/logevent/SecretChatEvent.h b/td/telegram/logevent/SecretChatEvent.h index c69bdf46e..2c8f241f2 100644 --- a/td/telegram/logevent/SecretChatEvent.h +++ b/td/telegram/logevent/SecretChatEvent.h @@ -411,12 +411,14 @@ class CloseSecretChat : public SecretChatLogEventBase { static constexpr Type type = SecretChatEvent::Type::CloseSecretChat; int32 chat_id = 0; bool delete_history = false; + bool is_already_discarded = false; template void store(StorerT &storer) const { using td::store; BEGIN_STORE_FLAGS(); STORE_FLAG(delete_history); + STORE_FLAG(is_already_discarded); END_STORE_FLAGS(); store(chat_id, storer); } @@ -427,6 +429,7 @@ class CloseSecretChat : public SecretChatLogEventBase { if (parser.version() >= 3) { BEGIN_PARSE_FLAGS(); PARSE_FLAG(delete_history); + PARSE_FLAG(is_already_discarded); END_PARSE_FLAGS(); } parse(chat_id, parser); @@ -434,7 +437,7 @@ class CloseSecretChat : public SecretChatLogEventBase { StringBuilder &print(StringBuilder &sb) const override { return sb << "[Logevent CloseSecretChat " << tag("id", log_event_id()) << tag("chat_id", chat_id) - << tag("delete_history", delete_history) << "]"; + << tag("delete_history", delete_history) << tag("is_already_discarded", is_already_discarded) << "]"; } };