Support quick reply media editing.

This commit is contained in:
levlam 2024-04-20 18:57:32 +03:00
parent 93e7755187
commit 1221cccbdf
3 changed files with 119 additions and 39 deletions

View File

@ -25138,6 +25138,12 @@ void MessagesManager::on_message_media_edited(DialogId dialog_id, MessageId mess
Result<int32> &&result) {
// must not run getDifference
if (was_thumbnail_uploaded) {
CHECK(thumbnail_file_id.is_valid());
// always delete partial remote location for the thumbnail, because it can't be reused anyway
td_->file_manager_->delete_partial_remote_location(thumbnail_file_id);
}
CHECK(message_id.is_any_server());
Dialog *d = get_dialog(dialog_id);
CHECK(d != nullptr);

View File

@ -439,15 +439,26 @@ class QuickReplyManager::EditQuickReplyMessageQuery final : public Td::ResultHan
QuickReplyShortcutId shortcut_id_;
MessageId message_id_;
int64 edit_generation_ = 0;
FileId file_id_;
FileId thumbnail_file_id_;
string file_reference_;
bool was_uploaded_ = false;
bool was_thumbnail_uploaded_ = false;
public:
void send(const QuickReplyMessage *m) {
void send(FileId file_id, FileId thumbnail_file_id, const QuickReplyMessage *m,
telegram_api::object_ptr<telegram_api::InputMedia> &&input_media) {
CHECK(m != nullptr);
CHECK(m->edited_content != nullptr);
CHECK(m->edit_generation > 0);
shortcut_id_ = m->shortcut_id;
message_id_ = m->message_id;
edit_generation_ = m->edit_generation;
file_id_ = file_id;
thumbnail_file_id_ = thumbnail_file_id;
file_reference_ = FileManager::extract_file_reference(input_media);
was_uploaded_ = FileManager::extract_was_uploaded(input_media);
was_thumbnail_uploaded_ = FileManager::extract_was_thumbnail_uploaded(input_media);
auto *content = m->edited_content.get();
const auto *text = get_message_content_text(content);
@ -466,12 +477,15 @@ class QuickReplyManager::EditQuickReplyMessageQuery final : public Td::ResultHan
if (m->edited_disable_web_page_preview) {
flags |= telegram_api::messages_editMessage::NO_WEBPAGE_MASK;
}
if (input_media != nullptr) {
flags |= telegram_api::messages_editMessage::MEDIA_MASK;
}
send_query(G()->net_query_creator().create(
telegram_api::messages_editMessage(
flags, false /*ignored*/, false /*ignored*/, telegram_api::make_object<telegram_api::inputPeerSelf>(),
m->message_id.get_server_message_id().get(), text != nullptr ? text->text : string(), nullptr, nullptr,
std::move(entities), 0, m->shortcut_id.get()),
m->message_id.get_server_message_id().get(), text != nullptr ? text->text : string(),
std::move(input_media), nullptr, std::move(entities), 0, m->shortcut_id.get()),
{{"me"}}));
}
@ -481,17 +495,36 @@ class QuickReplyManager::EditQuickReplyMessageQuery final : public Td::ResultHan
return on_error(result_ptr.move_as_error());
}
if (was_thumbnail_uploaded_) {
CHECK(thumbnail_file_id_.is_valid());
// always delete partial remote location for the thumbnail, because it can't be reused anyway
td_->file_manager_->delete_partial_remote_location(thumbnail_file_id_);
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for EditMessageQuery: " << to_string(ptr);
td_->quick_reply_manager_->on_edit_quick_reply_message(shortcut_id_, message_id_, edit_generation_, std::move(ptr));
td_->quick_reply_manager_->on_edit_quick_reply_message(shortcut_id_, message_id_, edit_generation_, file_id_,
was_uploaded_, std::move(ptr));
}
void on_error(Status status) final {
if (!td_->auth_manager_->is_bot() && status.message() == "MESSAGE_NOT_MODIFIED") {
return td_->quick_reply_manager_->on_edit_quick_reply_message(shortcut_id_, message_id_, edit_generation_,
nullptr);
if (G()->close_flag()) {
// do not send error, message will be re-edited after restart
return;
}
td_->quick_reply_manager_->fail_edit_quick_reply_message(shortcut_id_, message_id_, edit_generation_);
if (!td_->auth_manager_->is_bot() && status.message() == "MESSAGE_NOT_MODIFIED") {
if (was_thumbnail_uploaded_) {
CHECK(thumbnail_file_id_.is_valid());
// always delete partial remote location for the thumbnail, because it can't be reused anyway
td_->file_manager_->delete_partial_remote_location(thumbnail_file_id_);
}
return td_->quick_reply_manager_->on_edit_quick_reply_message(shortcut_id_, message_id_, edit_generation_,
file_id_, was_uploaded_, nullptr);
}
td_->quick_reply_manager_->fail_edit_quick_reply_message(shortcut_id_, message_id_, edit_generation_, file_id_,
thumbnail_file_id_, file_reference_, was_uploaded_,
was_thumbnail_uploaded_, std::move(status));
}
};
@ -1877,7 +1910,7 @@ void QuickReplyManager::do_send_message(const QuickReplyMessage *m, vector<int>
auto content_type = content->get_type();
if (content_type == MessageContentType::Text) {
if (is_edit) {
td_->create_handler<EditQuickReplyMessageQuery>()->send(m);
td_->create_handler<EditQuickReplyMessageQuery>()->send(FileId(), FileId(), m, nullptr);
return;
}
auto input_media = get_message_content_input_media_web_page(td_, content);
@ -1888,9 +1921,6 @@ void QuickReplyManager::do_send_message(const QuickReplyMessage *m, vector<int>
}
return;
}
if (is_edit) {
return fail_edit_quick_reply_message(m->shortcut_id, m->message_id, m->edit_generation);
}
FileId file_id = get_message_content_any_file_id(content); // any_file_id, because it could be a photo sent by ID
FileView file_view = td_->file_manager_->get_file_view(file_id);
@ -1909,7 +1939,8 @@ void QuickReplyManager::do_send_message(const QuickReplyMessage *m, vector<int>
CHECK(file_id.is_valid());
bool is_inserted =
being_uploaded_files_.emplace(file_id, std::make_pair(message_full_id, thumbnail_file_id)).second;
being_uploaded_files_.emplace(file_id, std::make_tuple(message_full_id, thumbnail_file_id, m->edit_generation))
.second;
CHECK(is_inserted);
td_->file_manager_->resume_upload(file_id, std::move(bad_parts), upload_media_callback_, 1, m->message_id.get());
} else {
@ -1946,13 +1977,14 @@ void QuickReplyManager::on_upload_media(FileId file_id, telegram_api::object_ptr
auto it = being_uploaded_files_.find(file_id);
CHECK(it != being_uploaded_files_.end());
auto message_full_id = it->second.first;
auto thumbnail_file_id = it->second.second;
auto message_full_id = std::get<0>(it->second);
auto thumbnail_file_id = std::get<1>(it->second);
auto edit_generation = std::get<2>(it->second);
being_uploaded_files_.erase(it);
auto *m = get_message(message_full_id);
if (m == nullptr) {
if (m == nullptr || (m->message_id.is_server() && m->edit_generation != edit_generation)) {
send_closure_later(G()->file_manager(), &FileManager::cancel_upload, file_id);
return;
}
@ -1960,10 +1992,10 @@ void QuickReplyManager::on_upload_media(FileId file_id, telegram_api::object_ptr
if (input_file && thumbnail_file_id.is_valid()) {
// TODO: download thumbnail if needed (like in secret chats)
LOG(INFO) << "Ask to upload thumbnail " << thumbnail_file_id;
bool is_inserted =
being_uploaded_thumbnails_
.emplace(thumbnail_file_id, UploadedThumbnailInfo{message_full_id, file_id, std::move(input_file)})
.second;
bool is_inserted = being_uploaded_thumbnails_
.emplace(thumbnail_file_id, UploadedThumbnailInfo{message_full_id, file_id,
std::move(input_file), edit_generation})
.second;
CHECK(is_inserted);
td_->file_manager_->upload(thumbnail_file_id, upload_thumbnail_callback_, 32, m->message_id.get());
} else {
@ -2002,7 +2034,7 @@ void QuickReplyManager::on_upload_media_error(FileId file_id, Status status) {
auto it = being_uploaded_files_.find(file_id);
CHECK(it != being_uploaded_files_.end());
auto message_full_id = it->second.first;
auto message_full_id = std::get<0>(it->second);
being_uploaded_files_.erase(it);
@ -2029,11 +2061,12 @@ void QuickReplyManager::on_upload_thumbnail(FileId thumbnail_file_id,
auto message_full_id = it->second.quick_reply_message_full_id;
auto file_id = it->second.file_id;
auto input_file = std::move(it->second.input_file);
auto edit_generation = it->second.edit_generation;
being_uploaded_thumbnails_.erase(it);
auto *m = get_message(message_full_id);
if (m == nullptr) {
if (m == nullptr || (m->message_id.is_server() && m->edit_generation != edit_generation)) {
send_closure_later(G()->file_manager(), &FileManager::cancel_upload, file_id);
send_closure_later(G()->file_manager(), &FileManager::cancel_upload, thumbnail_file_id);
return;
@ -2058,7 +2091,9 @@ void QuickReplyManager::on_message_media_uploaded(const QuickReplyMessage *m,
CHECK(input_media != nullptr);
auto message_id = m->message_id;
if (message_id.is_any_server()) {
UNREACHABLE();
CHECK(m->edited_content != nullptr);
CHECK(m->edited_content->get_type() != MessageContentType::Text);
td_->create_handler<EditQuickReplyMessageQuery>()->send(file_id, thumbnail_file_id, m, std::move(input_media));
return;
}
@ -2256,15 +2291,21 @@ void QuickReplyManager::edit_quick_reply_message(
}
void QuickReplyManager::on_edit_quick_reply_message(QuickReplyShortcutId shortcut_id, MessageId message_id,
int64 edit_generation,
int64 edit_generation, FileId file_id, bool was_uploaded,
telegram_api::object_ptr<telegram_api::Updates> updates_ptr) {
auto *m = get_message({shortcut_id, message_id});
if (m == nullptr) {
if (was_uploaded) {
send_closure_later(G()->file_manager(), &FileManager::cancel_upload, file_id);
}
return;
}
if (m->edit_generation != edit_generation) {
LOG(INFO) << "Ignore succesful edit of " << QuickReplyMessageFullId(m->shortcut_id, m->message_id)
<< " with generation " << edit_generation << " instead of " << m->edit_generation;
if (was_uploaded) {
send_closure_later(G()->file_manager(), &FileManager::cancel_upload, file_id);
}
return;
}
LOG(INFO) << "Receive result for editing of " << QuickReplyMessageFullId(m->shortcut_id, m->message_id) << ": "
@ -2284,27 +2325,56 @@ void QuickReplyManager::on_edit_quick_reply_message(QuickReplyShortcutId shortcu
auto *s = get_shortcut(shortcut_id);
CHECK(s != nullptr);
if (s->messages_[0]->message_id == m->message_id) {
send_update_quick_reply_shortcut(s, "fail_edit_quick_reply_message 1");
send_update_quick_reply_shortcut(s, "on_edit_quick_reply_message 1");
}
send_update_quick_reply_shortcut_messages(s, "fail_edit_quick_reply_message 2");
send_update_quick_reply_shortcut_messages(s, "on_edit_quick_reply_message 2");
save_quick_reply_shortcuts();
}
void QuickReplyManager::fail_edit_quick_reply_message(QuickReplyShortcutId shortcut_id, MessageId message_id,
int64 edit_generation) {
int64 edit_generation, FileId file_id, FileId thumbnail_file_id,
string file_reference, bool was_uploaded,
bool was_thumbnail_uploaded, Status status) {
auto *m = get_message({shortcut_id, message_id});
if (m != nullptr) {
fail_edit_quick_reply_message(m, edit_generation);
if (m == nullptr) {
if (was_uploaded) {
send_closure_later(G()->file_manager(), &FileManager::cancel_upload, file_id);
}
return;
}
}
void QuickReplyManager::fail_edit_quick_reply_message(QuickReplyMessage *m, int64 edit_generation) {
CHECK(m != nullptr);
if (m->edit_generation != edit_generation) {
LOG(INFO) << "Ignore failed edit of " << QuickReplyMessageFullId(m->shortcut_id, m->message_id)
<< " with generation " << edit_generation << " instead of " << m->edit_generation;
if (was_uploaded) {
send_closure_later(G()->file_manager(), &FileManager::cancel_upload, file_id);
}
return;
}
if (was_uploaded) {
if (was_thumbnail_uploaded) {
CHECK(thumbnail_file_id.is_valid());
// always delete partial remote location for the thumbnail, because it can't be reused anyway
td_->file_manager_->delete_partial_remote_location(thumbnail_file_id);
}
CHECK(file_id.is_valid());
auto bad_parts = FileManager::get_missing_file_parts(status);
if (!bad_parts.empty()) {
do_send_message(m, std::move(bad_parts));
return;
} else {
td_->file_manager_->delete_partial_remote_location_if_needed(file_id, status);
}
} else if (FileReferenceManager::is_file_reference_error(status)) {
if (file_id.is_valid() && !was_uploaded) {
VLOG(file_references) << "Receive " << status << " for " << file_id;
td_->file_manager_->delete_file_reference(file_id, file_reference);
do_send_message(m, {-1});
return;
} else {
LOG(ERROR) << "Receive file reference error, but file_id = " << file_id << ", was_uploaded = " << was_uploaded;
}
}
auto old_file_ids = get_message_file_ids(m);
m->edit_generation = 0;
@ -2320,6 +2390,7 @@ void QuickReplyManager::fail_edit_quick_reply_message(QuickReplyMessage *m, int6
}
send_update_quick_reply_shortcut_messages(s, "fail_edit_quick_reply_message 2");
save_quick_reply_shortcuts();
reload_quick_reply_messages(m->shortcut_id, Auto());
}
void QuickReplyManager::get_quick_reply_shortcut_messages(QuickReplyShortcutId shortcut_id, Promise<Unit> &&promise) {

View File

@ -26,6 +26,7 @@
#include "td/utils/Status.h"
#include <memory>
#include <tuple>
#include <utility>
namespace td {
@ -379,11 +380,12 @@ class QuickReplyManager final : public Actor {
static int64 generate_new_media_album_id();
void on_edit_quick_reply_message(QuickReplyShortcutId shortcut_id, MessageId message_id, int64 edit_generation,
FileId file_id, bool was_uploaded,
telegram_api::object_ptr<telegram_api::Updates> updates_ptr);
void fail_edit_quick_reply_message(QuickReplyShortcutId shortcut_id, MessageId message_id, int64 edit_generation);
void fail_edit_quick_reply_message(QuickReplyMessage *m, int64 edit_generation);
void fail_edit_quick_reply_message(QuickReplyShortcutId shortcut_id, MessageId message_id, int64 edit_generation,
FileId file_id, FileId thumbnail_file_id, string file_reference, bool was_uploaded,
bool was_thumbnail_uploaded, Status status);
string get_quick_reply_shortcuts_database_key();
@ -410,13 +412,14 @@ class QuickReplyManager final : public Actor {
FlatHashMap<QuickReplyMessageFullId, FileSourceId, QuickReplyMessageFullIdHash> message_full_id_to_file_source_id_;
FlatHashMap<FileId, std::pair<QuickReplyMessageFullId, FileId>, FileIdHash>
FlatHashMap<FileId, std::tuple<QuickReplyMessageFullId, FileId, int64>, FileIdHash>
being_uploaded_files_; // file_id -> message, thumbnail_file_id
struct UploadedThumbnailInfo {
QuickReplyMessageFullId quick_reply_message_full_id;
FileId file_id; // original file file_id
tl_object_ptr<telegram_api::InputFile> input_file; // original file InputFile
FileId file_id; // original file file_id
telegram_api::object_ptr<telegram_api::InputFile> input_file; // original file InputFile
int64 edit_generation;
};
FlatHashMap<FileId, UploadedThumbnailInfo, FileIdHash> being_uploaded_thumbnails_; // thumbnail_file_id -> ...