Add td_api::addQuickReplyShortcutMessageAlbum.
This commit is contained in:
parent
f43428d4d8
commit
420ee182fa
@ -8230,6 +8230,13 @@ addQuickReplyShortcutMessage shortcut_name:string reply_to_message_id:int53 inpu
|
|||||||
//@hide_via_bot Pass true to hide the bot, via which the message is sent. Can be used only for bots getOption("animation_search_bot_username"), getOption("photo_search_bot_username"), and getOption("venue_search_bot_username")
|
//@hide_via_bot Pass true to hide the bot, via which the message is sent. Can be used only for bots getOption("animation_search_bot_username"), getOption("photo_search_bot_username"), and getOption("venue_search_bot_username")
|
||||||
addQuickReplyShortcutInlineQueryResultMessage shortcut_name:string reply_to_message_id:int53 query_id:int64 result_id:string hide_via_bot:Bool = QuickReplyMessage;
|
addQuickReplyShortcutInlineQueryResultMessage shortcut_name:string reply_to_message_id:int53 query_id:int64 result_id:string hide_via_bot:Bool = QuickReplyMessage;
|
||||||
|
|
||||||
|
//@description Adds 2-10 messages grouped together into an album to a quick reply shortcut. Currently, only audio, document, photo and video messages can be grouped into an album.
|
||||||
|
//-Documents and audio files can be only grouped in an album with messages of the same type. Returns sent messages
|
||||||
|
//@shortcut_name Name of the target shortcut
|
||||||
|
//@reply_to_message_id Identifier of a quick reply message in the same shortcut to be replied; pass 0 if none
|
||||||
|
//@input_message_contents Contents of messages to be sent. At most 10 messages can be added to an album
|
||||||
|
addQuickReplyShortcutMessageAlbum shortcut_name:string reply_to_message_id:int53 input_message_contents:vector<InputMessageContent> = QuickReplyMessages;
|
||||||
|
|
||||||
//@description Readds quick reply messages which failed to add. Can be called only for messages for which messageSendingStateFailed.can_retry is true and after specified in messageSendingStateFailed.retry_after time passed.
|
//@description Readds quick reply messages which failed to add. Can be called only for messages for which messageSendingStateFailed.can_retry is true and after specified in messageSendingStateFailed.retry_after time passed.
|
||||||
//-If a message is readded, the corresponding failed to send message is deleted. Returns the sent messages in the same order as the message identifiers passed in message_ids. If a message can't be readded, null will be returned instead of the message
|
//-If a message is readded, the corresponding failed to send message is deleted. Returns the sent messages in the same order as the message identifiers passed in message_ids. If a message can't be readded, null will be returned instead of the message
|
||||||
//@shortcut_name Name of the target shortcut
|
//@shortcut_name Name of the target shortcut
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
@ -442,6 +443,151 @@ class QuickReplyManager::SendQuickReplyMediaQuery final : public Td::ResultHandl
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class QuickReplyManager::UploadQuickReplyMediaQuery final : public Td::ResultHandler {
|
||||||
|
int64 random_id_;
|
||||||
|
QuickReplyShortcutId shortcut_id_;
|
||||||
|
MessageId message_id_;
|
||||||
|
FileId file_id_;
|
||||||
|
FileId thumbnail_file_id_;
|
||||||
|
string file_reference_;
|
||||||
|
bool was_uploaded_ = false;
|
||||||
|
bool was_thumbnail_uploaded_ = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void send(FileId file_id, FileId thumbnail_file_id, const QuickReplyMessage *m,
|
||||||
|
telegram_api::object_ptr<telegram_api::InputMedia> &&input_media) {
|
||||||
|
random_id_ = m->random_id;
|
||||||
|
shortcut_id_ = m->shortcut_id;
|
||||||
|
message_id_ = m->message_id;
|
||||||
|
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);
|
||||||
|
|
||||||
|
int32 flags = 0;
|
||||||
|
send_query(G()->net_query_creator().create(telegram_api::messages_uploadMedia(
|
||||||
|
flags, string(), telegram_api::make_object<telegram_api::inputPeerSelf>(), std::move(input_media))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_result(BufferSlice packet) final {
|
||||||
|
auto result_ptr = fetch_result<telegram_api::messages_uploadMedia>(packet);
|
||||||
|
if (result_ptr.is_error()) {
|
||||||
|
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 UploadQuickReplyMediaQuery: " << to_string(ptr);
|
||||||
|
td_->quick_reply_manager_->on_upload_message_media_success(shortcut_id_, message_id_, file_id_, std::move(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_error(Status status) final {
|
||||||
|
if (G()->close_flag()) {
|
||||||
|
// do not send error, message will be re-sent after restart
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG(INFO) << "Receive error for UploadQuickReplyMediaQuery: " << status;
|
||||||
|
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()) {
|
||||||
|
td_->quick_reply_manager_->on_send_message_file_parts_missing(shortcut_id_, random_id_, 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)) {
|
||||||
|
LOG(ERROR) << "Receive file reference error for UploadMediaQuery";
|
||||||
|
}
|
||||||
|
|
||||||
|
td_->quick_reply_manager_->on_upload_message_media_fail(shortcut_id_, message_id_, std::move(status));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class QuickReplyManager::SendQuickReplyMultiMediaQuery final : public Td::ResultHandler {
|
||||||
|
vector<FileId> file_ids_;
|
||||||
|
vector<string> file_references_;
|
||||||
|
vector<int64> random_ids_;
|
||||||
|
QuickReplyShortcutId shortcut_id_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void send(QuickReplyShortcutId shortcut_id, MessageId reply_to_message_id, bool invert_media,
|
||||||
|
vector<int64> &&random_ids, vector<FileId> &&file_ids,
|
||||||
|
vector<tl_object_ptr<telegram_api::inputSingleMedia>> &&input_single_media) {
|
||||||
|
for (auto &single_media : input_single_media) {
|
||||||
|
CHECK(FileManager::extract_was_uploaded(single_media->media_) == false);
|
||||||
|
file_references_.push_back(FileManager::extract_file_reference(single_media->media_));
|
||||||
|
}
|
||||||
|
shortcut_id_ = shortcut_id;
|
||||||
|
file_ids_ = std::move(file_ids);
|
||||||
|
random_ids_ = std::move(random_ids);
|
||||||
|
CHECK(file_ids_.size() == random_ids_.size());
|
||||||
|
|
||||||
|
int32 flags = telegram_api::messages_sendMultiMedia::QUICK_REPLY_SHORTCUT_MASK;
|
||||||
|
auto reply_to =
|
||||||
|
MessageInputReplyTo(reply_to_message_id, DialogId(), MessageQuote()).get_input_reply_to(td_, MessageId());
|
||||||
|
if (reply_to != nullptr) {
|
||||||
|
flags |= telegram_api::messages_sendMultiMedia::REPLY_TO_MASK;
|
||||||
|
}
|
||||||
|
if (invert_media) {
|
||||||
|
flags |= telegram_api::messages_sendMultiMedia::INVERT_MEDIA_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_query(G()->net_query_creator().create(
|
||||||
|
telegram_api::messages_sendMultiMedia(flags, false /*ignored*/, false /*ignored*/, false /*ignored*/,
|
||||||
|
false /*ignored*/, false /*ignored*/, false /*ignored*/,
|
||||||
|
telegram_api::make_object<telegram_api::inputPeerSelf>(),
|
||||||
|
std::move(reply_to), std::move(input_single_media), 0, nullptr,
|
||||||
|
td_->quick_reply_manager_->get_input_quick_reply_shortcut(shortcut_id_)),
|
||||||
|
{{"me"}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_result(BufferSlice packet) final {
|
||||||
|
auto result_ptr = fetch_result<telegram_api::messages_sendMultiMedia>(packet);
|
||||||
|
if (result_ptr.is_error()) {
|
||||||
|
return on_error(result_ptr.move_as_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptr = result_ptr.move_as_ok();
|
||||||
|
LOG(INFO) << "Receive result for SendMultiMedia for " << format::as_array(random_ids_) << ": " << to_string(ptr);
|
||||||
|
td_->quick_reply_manager_->process_send_quick_reply_updates(shortcut_id_, std::move(ptr), std::move(random_ids_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_error(Status status) final {
|
||||||
|
LOG(INFO) << "Receive error for SendMultiMedia: " << status;
|
||||||
|
if (G()->close_flag()) {
|
||||||
|
// do not send error, message will be re-sent after restart
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (FileReferenceManager::is_file_reference_error(status)) {
|
||||||
|
auto pos = FileReferenceManager::get_file_reference_error_pos(status);
|
||||||
|
if (1 <= pos && pos <= file_ids_.size() && file_ids_[pos - 1].is_valid()) {
|
||||||
|
VLOG(file_references) << "Receive " << status << " for " << file_ids_[pos - 1];
|
||||||
|
td_->file_manager_->delete_file_reference(file_ids_[pos - 1], file_references_[pos - 1]);
|
||||||
|
td_->quick_reply_manager_->on_send_media_group_file_reference_error(shortcut_id_, std::move(random_ids_));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "Receive file reference error " << status << ", but file_ids = " << file_ids_
|
||||||
|
<< ", message_count = " << file_ids_.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
td_->quick_reply_manager_->on_failed_send_quick_reply_messages(shortcut_id_, std::move(random_ids_),
|
||||||
|
std::move(status));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class QuickReplyManager::EditQuickReplyMessageQuery final : public Td::ResultHandler {
|
class QuickReplyManager::EditQuickReplyMessageQuery final : public Td::ResultHandler {
|
||||||
QuickReplyShortcutId shortcut_id_;
|
QuickReplyShortcutId shortcut_id_;
|
||||||
MessageId message_id_;
|
MessageId message_id_;
|
||||||
@ -520,7 +666,7 @@ class QuickReplyManager::EditQuickReplyMessageQuery final : public Td::ResultHan
|
|||||||
// do not send error, message will be re-edited after restart
|
// do not send error, message will be re-edited after restart
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!td_->auth_manager_->is_bot() && status.message() == "MESSAGE_NOT_MODIFIED") {
|
if (status.message() == "MESSAGE_NOT_MODIFIED") {
|
||||||
if (was_thumbnail_uploaded_) {
|
if (was_thumbnail_uploaded_) {
|
||||||
CHECK(thumbnail_file_id_.is_valid());
|
CHECK(thumbnail_file_id_.is_valid());
|
||||||
// always delete partial remote location for the thumbnail, because it can't be reused anyway
|
// always delete partial remote location for the thumbnail, because it can't be reused anyway
|
||||||
@ -1520,10 +1666,15 @@ void QuickReplyManager::delete_quick_reply_messages(Shortcut *s, const vector<Me
|
|||||||
for (auto &message_id : message_ids) {
|
for (auto &message_id : message_ids) {
|
||||||
auto it = get_message_it(s, message_id);
|
auto it = get_message_it(s, message_id);
|
||||||
if (it != s->messages_.end()) {
|
if (it != s->messages_.end()) {
|
||||||
delete_message_files(s->shortcut_id_, it->get());
|
const auto *m = it->get();
|
||||||
|
delete_message_files(s->shortcut_id_, m);
|
||||||
if (message_id.is_server()) {
|
if (message_id.is_server()) {
|
||||||
s->server_total_count_--;
|
s->server_total_count_--;
|
||||||
} else {
|
} else {
|
||||||
|
if (m->media_album_id != 0 && m->message_id.is_yet_unsent()) {
|
||||||
|
send_closure_later(actor_id(this), &QuickReplyManager::on_upload_message_media_finished, m->media_album_id,
|
||||||
|
m->shortcut_id, m->message_id, Status::OK());
|
||||||
|
}
|
||||||
s->local_total_count_--;
|
s->local_total_count_--;
|
||||||
}
|
}
|
||||||
is_changed = true;
|
is_changed = true;
|
||||||
@ -1770,17 +1921,21 @@ void QuickReplyManager::process_send_quick_reply_updates(QuickReplyShortcutId sh
|
|||||||
save_quick_reply_shortcuts();
|
save_quick_reply_shortcuts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuickReplyManager::update_message_content(QuickReplyMessage *old_message, QuickReplyMessage *new_message,
|
void QuickReplyManager::update_message_content(const QuickReplyMessage *old_message, QuickReplyMessage *new_message,
|
||||||
bool is_edit) {
|
bool is_edit) {
|
||||||
CHECK(is_edit ? old_message->message_id.is_server() : old_message->message_id.is_yet_unsent());
|
CHECK(is_edit ? old_message->message_id.is_server() : old_message->message_id.is_yet_unsent());
|
||||||
CHECK(new_message->edited_content == nullptr);
|
CHECK(new_message->edited_content == nullptr);
|
||||||
unique_ptr<MessageContent> &old_content = is_edit ? old_message->edited_content : old_message->content;
|
update_message_content(is_edit ? old_message->edited_content : old_message->content, new_message->content,
|
||||||
unique_ptr<MessageContent> &new_content = new_message->content;
|
is_edit || new_message->edit_date == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuickReplyManager::update_message_content(const unique_ptr<MessageContent> &old_content,
|
||||||
|
unique_ptr<MessageContent> &new_content, bool need_merge_files) {
|
||||||
MessageContentType old_content_type = old_content->get_type();
|
MessageContentType old_content_type = old_content->get_type();
|
||||||
MessageContentType new_content_type = new_content->get_type();
|
MessageContentType new_content_type = new_content->get_type();
|
||||||
|
|
||||||
auto old_file_id = get_message_content_any_file_id(old_content.get());
|
auto old_file_id = get_message_content_any_file_id(old_content.get());
|
||||||
auto need_merge_files = (is_edit || new_message->edit_date == 0) && old_file_id.is_valid();
|
need_merge_files = need_merge_files && old_file_id.is_valid();
|
||||||
if (old_content_type != new_content_type) {
|
if (old_content_type != new_content_type) {
|
||||||
if (need_merge_files) {
|
if (need_merge_files) {
|
||||||
td_->file_manager_->try_merge_documents(old_file_id, get_message_content_any_file_id(new_content.get()));
|
td_->file_manager_->try_merge_documents(old_file_id, get_message_content_any_file_id(new_content.get()));
|
||||||
@ -1906,11 +2061,82 @@ Result<td_api::object_ptr<td_api::quickReplyMessage>> QuickReplyManager::send_in
|
|||||||
return get_quick_reply_message_object(m, "send_inline_query_result_message");
|
return get_quick_reply_message_object(m, "send_inline_query_result_message");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<td_api::object_ptr<td_api::quickReplyMessages>> QuickReplyManager::send_message_group(
|
||||||
|
const string &shortcut_name, MessageId reply_to_message_id,
|
||||||
|
vector<td_api::object_ptr<td_api::InputMessageContent>> &&input_message_contents) {
|
||||||
|
if (input_message_contents.size() > MAX_GROUPED_MESSAGES) {
|
||||||
|
return Status::Error(400, "Too many messages to send as an album");
|
||||||
|
}
|
||||||
|
if (input_message_contents.empty()) {
|
||||||
|
return Status::Error(400, "There are no messages to send");
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<InputMessageContent> message_contents;
|
||||||
|
std::unordered_set<MessageContentType, MessageContentTypeHash> message_content_types;
|
||||||
|
for (auto &input_message_content : input_message_contents) {
|
||||||
|
TRY_RESULT(message_content, process_input_message_content(std::move(input_message_content)));
|
||||||
|
auto message_content_type = message_content.content->get_type();
|
||||||
|
if (!is_allowed_media_group_content(message_content_type)) {
|
||||||
|
return Status::Error(400, "Invalid message content type");
|
||||||
|
}
|
||||||
|
message_content_types.insert(message_content_type);
|
||||||
|
|
||||||
|
message_contents.push_back(std::move(message_content));
|
||||||
|
}
|
||||||
|
if (message_content_types.size() > 1) {
|
||||||
|
for (auto message_content_type : message_content_types) {
|
||||||
|
if (is_homogenous_media_group_content(message_content_type)) {
|
||||||
|
return Status::Error(400, PSLICE() << message_content_type << " can't be mixed with other media types");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY_RESULT(s, create_new_local_shortcut(shortcut_name, static_cast<int32>(message_contents.size())));
|
||||||
|
bool is_new = s->messages_.empty();
|
||||||
|
reply_to_message_id = get_input_reply_to_message_id(s, reply_to_message_id);
|
||||||
|
|
||||||
|
int64 media_album_id = 0;
|
||||||
|
if (message_contents.size() > 1) {
|
||||||
|
media_album_id = generate_new_media_album_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<td_api::object_ptr<td_api::quickReplyMessage>> messages;
|
||||||
|
for (auto &message_content : message_contents) {
|
||||||
|
auto content = dup_message_content(td_, td_->dialog_manager_->get_my_dialog_id(), message_content.content.get(),
|
||||||
|
MessageContentDupType::Send, MessageCopyOptions());
|
||||||
|
auto *m = add_local_message(s, reply_to_message_id, std::move(content), message_content.invert_media,
|
||||||
|
message_content.via_bot_user_id, false, message_content.disable_web_page_preview,
|
||||||
|
std::move(message_content.emoji));
|
||||||
|
m->media_album_id = media_album_id;
|
||||||
|
|
||||||
|
do_send_message(m);
|
||||||
|
|
||||||
|
messages.push_back(get_quick_reply_message_object(m, "send_message_group"));
|
||||||
|
}
|
||||||
|
|
||||||
|
send_update_quick_reply_shortcut(s, "send_message_group");
|
||||||
|
send_update_quick_reply_shortcut_messages(s, "send_message_group");
|
||||||
|
if (is_new) {
|
||||||
|
send_update_quick_reply_shortcuts();
|
||||||
|
}
|
||||||
|
save_quick_reply_shortcuts();
|
||||||
|
|
||||||
|
return td_api::make_object<td_api::quickReplyMessages>(std::move(messages));
|
||||||
|
}
|
||||||
|
|
||||||
void QuickReplyManager::do_send_message(const QuickReplyMessage *m, vector<int> bad_parts) {
|
void QuickReplyManager::do_send_message(const QuickReplyMessage *m, vector<int> bad_parts) {
|
||||||
|
CHECK(m != nullptr);
|
||||||
bool is_edit = m->message_id.is_server();
|
bool is_edit = m->message_id.is_server();
|
||||||
auto message_full_id = QuickReplyMessageFullId(m->shortcut_id, m->message_id);
|
auto message_full_id = QuickReplyMessageFullId(m->shortcut_id, m->message_id);
|
||||||
LOG(INFO) << "Do " << (is_edit ? "edit" : "send") << ' ' << message_full_id;
|
LOG(INFO) << "Do " << (is_edit ? "edit" : "send") << ' ' << message_full_id;
|
||||||
|
|
||||||
|
if (m->media_album_id != 0 && bad_parts.empty() && !is_edit) {
|
||||||
|
auto &request = pending_message_group_sends_[m->media_album_id];
|
||||||
|
request.message_ids.push_back(m->message_id);
|
||||||
|
request.is_finished.push_back(false);
|
||||||
|
request.results.push_back(Status::OK());
|
||||||
|
}
|
||||||
|
|
||||||
auto content = is_edit ? m->edited_content.get() : m->content.get();
|
auto content = is_edit ? m->edited_content.get() : m->content.get();
|
||||||
CHECK(content != nullptr);
|
CHECK(content != nullptr);
|
||||||
auto content_type = content->get_type();
|
auto content_type = content->get_type();
|
||||||
@ -2118,15 +2344,232 @@ void QuickReplyManager::on_message_media_uploaded(const QuickReplyMessage *m,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(m->media_album_id == 0);
|
if (m->media_album_id != 0) {
|
||||||
|
// must use UploadMedia and wait for other messages
|
||||||
|
switch (input_media->get_id()) {
|
||||||
|
case telegram_api::inputMediaUploadedDocument::ID:
|
||||||
|
static_cast<telegram_api::inputMediaUploadedDocument *>(input_media.get())->flags_ |=
|
||||||
|
telegram_api::inputMediaUploadedDocument::NOSOUND_VIDEO_MASK;
|
||||||
|
// fallthrough
|
||||||
|
case telegram_api::inputMediaUploadedPhoto::ID:
|
||||||
|
case telegram_api::inputMediaDocumentExternal::ID:
|
||||||
|
case telegram_api::inputMediaPhotoExternal::ID:
|
||||||
|
td_->create_handler<UploadQuickReplyMediaQuery>()->send(file_id, thumbnail_file_id, m, std::move(input_media));
|
||||||
|
break;
|
||||||
|
case telegram_api::inputMediaDocument::ID:
|
||||||
|
case telegram_api::inputMediaPhoto::ID:
|
||||||
|
send_closure_later(actor_id(this), &QuickReplyManager::on_upload_message_media_finished, m->media_album_id,
|
||||||
|
m->shortcut_id, m->message_id, Status::OK());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG(ERROR) << "Have wrong input media " << to_string(input_media);
|
||||||
|
send_closure_later(actor_id(this), &QuickReplyManager::on_upload_message_media_finished, m->media_album_id,
|
||||||
|
m->shortcut_id, m->message_id, Status::Error(400, "Invalid input media"));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
td_->create_handler<SendQuickReplyMediaQuery>()->send(file_id, thumbnail_file_id, m, std::move(input_media));
|
td_->create_handler<SendQuickReplyMediaQuery>()->send(file_id, thumbnail_file_id, m, std::move(input_media));
|
||||||
}
|
}
|
||||||
|
|
||||||
int64 QuickReplyManager::generate_new_media_album_id() {
|
void QuickReplyManager::on_upload_message_media_success(QuickReplyShortcutId shortcut_id, MessageId message_id,
|
||||||
|
FileId file_id,
|
||||||
|
telegram_api::object_ptr<telegram_api::MessageMedia> &&media) {
|
||||||
|
auto *s = get_shortcut(shortcut_id);
|
||||||
|
auto *m = get_message(s, message_id);
|
||||||
|
if (m == nullptr) {
|
||||||
|
send_closure_later(G()->file_manager(), &FileManager::cancel_upload, file_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(message_id.is_yet_unsent());
|
||||||
|
|
||||||
|
auto caption = get_message_content_caption(m->content.get());
|
||||||
|
auto has_spoiler = get_message_content_has_spoiler(m->content.get());
|
||||||
|
auto content = get_message_content(td_, caption == nullptr ? FormattedText() : *caption, std::move(media),
|
||||||
|
td_->dialog_manager_->get_my_dialog_id(), 0, false, UserId(), nullptr, nullptr,
|
||||||
|
"on_upload_message_media_success");
|
||||||
|
set_message_content_has_spoiler(content.get(), has_spoiler);
|
||||||
|
|
||||||
|
update_message_content(m->content, content, true);
|
||||||
|
|
||||||
|
if (s->messages_[0]->message_id == message_id) {
|
||||||
|
// send_update_quick_reply_shortcut(s, "on_upload_message_media_success");
|
||||||
|
}
|
||||||
|
// send_update_quick_reply_shortcut_messages(s, "on_upload_message_media_success");
|
||||||
|
save_quick_reply_shortcuts();
|
||||||
|
|
||||||
|
auto input_media = get_input_media(m->content.get(), td_, {}, m->send_emoji, true);
|
||||||
|
Status result;
|
||||||
|
if (input_media == nullptr) {
|
||||||
|
result = Status::Error(400, "Failed to upload file");
|
||||||
|
}
|
||||||
|
|
||||||
|
send_closure_later(actor_id(this), &QuickReplyManager::on_upload_message_media_finished, m->media_album_id,
|
||||||
|
shortcut_id, message_id, std::move(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuickReplyManager::on_upload_message_media_fail(QuickReplyShortcutId shortcut_id, MessageId message_id,
|
||||||
|
Status error) {
|
||||||
|
auto *m = get_message({shortcut_id, message_id});
|
||||||
|
if (m == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_closure_later(actor_id(this), &QuickReplyManager::on_upload_message_media_finished, m->media_album_id,
|
||||||
|
shortcut_id, m->message_id, std::move(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuickReplyManager::on_upload_message_media_finished(int64 media_album_id, QuickReplyShortcutId shortcut_id,
|
||||||
|
MessageId message_id, Status result) {
|
||||||
|
CHECK(media_album_id < 0);
|
||||||
|
auto it = pending_message_group_sends_.find(media_album_id);
|
||||||
|
if (it == pending_message_group_sends_.end()) {
|
||||||
|
CHECK(result.is_ok());
|
||||||
|
// the message is being sent but was deleted
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &request = it->second;
|
||||||
|
auto message_it = std::find(request.message_ids.begin(), request.message_ids.end(), message_id);
|
||||||
|
CHECK(message_it != request.message_ids.end());
|
||||||
|
auto pos = static_cast<size_t>(message_it - request.message_ids.begin());
|
||||||
|
|
||||||
|
if (request.is_finished[pos]) {
|
||||||
|
LOG(INFO) << "Upload media of " << message_id << " in " << shortcut_id << " from group " << media_album_id
|
||||||
|
<< " at pos " << pos << " has already been finished";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG(INFO) << "Finish to upload media of " << message_id << " in " << shortcut_id << " from group " << media_album_id
|
||||||
|
<< " at pos " << pos << " with result " << result
|
||||||
|
<< " and previous finished_count = " << request.finished_count;
|
||||||
|
|
||||||
|
request.results[pos] = std::move(result);
|
||||||
|
request.is_finished[pos] = true;
|
||||||
|
request.finished_count++;
|
||||||
|
|
||||||
|
if (request.finished_count == request.message_ids.size()) {
|
||||||
|
do_send_message_group(shortcut_id, media_album_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuickReplyManager::do_send_message_group(QuickReplyShortcutId shortcut_id, int64 media_album_id) {
|
||||||
|
if (G()->close_flag()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(media_album_id < 0);
|
||||||
|
auto it = pending_message_group_sends_.find(media_album_id);
|
||||||
|
CHECK(it != pending_message_group_sends_.end());
|
||||||
|
|
||||||
|
auto &request = it->second;
|
||||||
|
auto *s = get_shortcut(shortcut_id);
|
||||||
|
if (s == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<FileId> file_ids;
|
||||||
|
vector<int64> random_ids;
|
||||||
|
MessageId reply_to_message_id;
|
||||||
|
bool invert_media = false;
|
||||||
|
vector<telegram_api::object_ptr<telegram_api::inputSingleMedia>> input_single_media;
|
||||||
|
Status error = Status::OK();
|
||||||
|
for (size_t i = 0; i < request.message_ids.size(); i++) {
|
||||||
|
CHECK(request.is_finished[i]);
|
||||||
|
auto *m = get_message(s, request.message_ids[i]);
|
||||||
|
if (m == nullptr) {
|
||||||
|
// skip deleted messages
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (request.results[i].is_error()) {
|
||||||
|
if (error.is_ok()) {
|
||||||
|
error = std::move(request.results[i]);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply_to_message_id = m->reply_to_message_id;
|
||||||
|
invert_media = m->invert_media;
|
||||||
|
file_ids.push_back(get_message_content_any_file_id(m->content.get()));
|
||||||
|
random_ids.push_back(m->random_id);
|
||||||
|
|
||||||
|
LOG(INFO) << "Have file " << file_ids.back() << " in " << m->message_id << " with result " << request.results[i]
|
||||||
|
<< " and is_finished = " << static_cast<bool>(request.is_finished[i]);
|
||||||
|
|
||||||
|
const FormattedText *caption = get_message_content_caption(m->content.get());
|
||||||
|
auto input_media = get_input_media(m->content.get(), td_, {}, m->send_emoji, true);
|
||||||
|
CHECK(input_media != nullptr);
|
||||||
|
auto entities = get_input_message_entities(td_->user_manager_.get(), caption, "do_send_message_group");
|
||||||
|
int32 input_single_media_flags = 0;
|
||||||
|
if (!entities.empty()) {
|
||||||
|
input_single_media_flags |= telegram_api::inputSingleMedia::ENTITIES_MASK;
|
||||||
|
}
|
||||||
|
input_single_media.push_back(telegram_api::make_object<telegram_api::inputSingleMedia>(
|
||||||
|
input_single_media_flags, std::move(input_media), random_ids.back(), caption == nullptr ? "" : caption->text,
|
||||||
|
std::move(entities)));
|
||||||
|
}
|
||||||
|
pending_message_group_sends_.erase(it);
|
||||||
|
if (error.is_error()) {
|
||||||
|
on_failed_send_quick_reply_messages(shortcut_id, std::move(random_ids), std::move(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(INFO) << "Begin to send media group " << media_album_id << " to " << shortcut_id;
|
||||||
|
|
||||||
|
if (input_single_media.empty()) {
|
||||||
|
LOG(INFO) << "Media group " << media_album_id << " from " << shortcut_id << " is empty";
|
||||||
|
}
|
||||||
|
td_->create_handler<SendQuickReplyMultiMediaQuery>()->send(shortcut_id, reply_to_message_id, invert_media,
|
||||||
|
std::move(random_ids), std::move(file_ids),
|
||||||
|
std::move(input_single_media));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuickReplyManager::on_send_media_group_file_reference_error(QuickReplyShortcutId shortcut_id,
|
||||||
|
vector<int64> random_ids) {
|
||||||
|
auto *s = get_shortcut(shortcut_id);
|
||||||
|
if (s == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 media_album_id = 0;
|
||||||
|
vector<MessageId> message_ids;
|
||||||
|
for (auto &random_id : random_ids) {
|
||||||
|
for (auto it = s->messages_.begin(); it != s->messages_.end(); ++it) {
|
||||||
|
const auto *m = it->get();
|
||||||
|
if (m->random_id == random_id && m->message_id.is_yet_unsent()) {
|
||||||
|
CHECK(m->media_album_id != 0);
|
||||||
|
CHECK(media_album_id == 0 || media_album_id == m->media_album_id);
|
||||||
|
media_album_id = m->media_album_id;
|
||||||
|
|
||||||
|
message_ids.push_back(m->message_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (message_ids.empty()) {
|
||||||
|
// all messages were deleted, nothing to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &request = pending_message_group_sends_[media_album_id];
|
||||||
|
CHECK(request.finished_count == 0);
|
||||||
|
CHECK(request.is_finished.empty());
|
||||||
|
CHECK(request.results.empty());
|
||||||
|
request.message_ids = std::move(message_ids);
|
||||||
|
request.is_finished.resize(request.message_ids.size());
|
||||||
|
for (size_t i = 0; i < request.message_ids.size(); i++) {
|
||||||
|
request.results.push_back(Status::OK());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto message_id : request.message_ids) {
|
||||||
|
do_send_message(get_message(s, message_id), {-1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 QuickReplyManager::generate_new_media_album_id() const {
|
||||||
int64 media_album_id = 0;
|
int64 media_album_id = 0;
|
||||||
do {
|
do {
|
||||||
media_album_id = Random::secure_int64();
|
media_album_id = Random::secure_int64();
|
||||||
} while (media_album_id >= 0);
|
} while (media_album_id >= 0 || pending_message_group_sends_.count(media_album_id) > 0);
|
||||||
return media_album_id;
|
return media_album_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3022,6 +3465,7 @@ string QuickReplyManager::get_quick_reply_shortcuts_database_key() {
|
|||||||
|
|
||||||
void QuickReplyManager::save_quick_reply_shortcuts() {
|
void QuickReplyManager::save_quick_reply_shortcuts() {
|
||||||
CHECK(shortcuts_.are_inited_);
|
CHECK(shortcuts_.are_inited_);
|
||||||
|
LOG(INFO) << "Save quick reply shortcuts";
|
||||||
G()->td_db()->get_binlog_pmc()->set(get_quick_reply_shortcuts_database_key(),
|
G()->td_db()->get_binlog_pmc()->set(get_quick_reply_shortcuts_database_key(),
|
||||||
log_event_store(shortcuts_).as_slice().str());
|
log_event_store(shortcuts_).as_slice().str());
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,10 @@ class QuickReplyManager final : public Actor {
|
|||||||
const string &result_id,
|
const string &result_id,
|
||||||
bool hide_via_bot);
|
bool hide_via_bot);
|
||||||
|
|
||||||
|
Result<td_api::object_ptr<td_api::quickReplyMessages>> send_message_group(
|
||||||
|
const string &shortcut_name, MessageId reply_to_message_id,
|
||||||
|
vector<td_api::object_ptr<td_api::InputMessageContent>> &&input_message_contents);
|
||||||
|
|
||||||
Result<td_api::object_ptr<td_api::quickReplyMessages>> resend_messages(const string &shortcut_name,
|
Result<td_api::object_ptr<td_api::quickReplyMessages>> resend_messages(const string &shortcut_name,
|
||||||
vector<MessageId> message_ids);
|
vector<MessageId> message_ids);
|
||||||
|
|
||||||
@ -194,10 +198,12 @@ class QuickReplyManager final : public Actor {
|
|||||||
void parse(ParserT &parser);
|
void parse(ParserT &parser);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SendQuickReplyMessageQuery;
|
|
||||||
class SendQuickReplyMediaQuery;
|
|
||||||
class SendQuickReplyInlineMessageQuery;
|
|
||||||
class EditQuickReplyMessageQuery;
|
class EditQuickReplyMessageQuery;
|
||||||
|
class SendQuickReplyInlineMessageQuery;
|
||||||
|
class SendQuickReplyMediaQuery;
|
||||||
|
class SendQuickReplyMessageQuery;
|
||||||
|
class SendQuickReplyMultiMediaQuery;
|
||||||
|
class UploadQuickReplyMediaQuery;
|
||||||
|
|
||||||
class UploadMediaCallback;
|
class UploadMediaCallback;
|
||||||
class UploadThumbnailCallback;
|
class UploadThumbnailCallback;
|
||||||
@ -354,7 +360,10 @@ class QuickReplyManager final : public Actor {
|
|||||||
|
|
||||||
void on_failed_send_quick_reply_messages(QuickReplyShortcutId shortcut_id, vector<int64> random_ids, Status error);
|
void on_failed_send_quick_reply_messages(QuickReplyShortcutId shortcut_id, vector<int64> random_ids, Status error);
|
||||||
|
|
||||||
void update_message_content(QuickReplyMessage *old_message, QuickReplyMessage *new_message, bool is_edit);
|
void update_message_content(const QuickReplyMessage *old_message, QuickReplyMessage *new_message, bool is_edit);
|
||||||
|
|
||||||
|
void update_message_content(const unique_ptr<MessageContent> &old_content, unique_ptr<MessageContent> &new_content,
|
||||||
|
bool need_merge_files);
|
||||||
|
|
||||||
void do_send_message(const QuickReplyMessage *m, vector<int> bad_parts = {});
|
void do_send_message(const QuickReplyMessage *m, vector<int> bad_parts = {});
|
||||||
|
|
||||||
@ -373,11 +382,23 @@ class QuickReplyManager final : public Actor {
|
|||||||
void on_upload_thumbnail(FileId thumbnail_file_id,
|
void on_upload_thumbnail(FileId thumbnail_file_id,
|
||||||
telegram_api::object_ptr<telegram_api::InputFile> thumbnail_input_file);
|
telegram_api::object_ptr<telegram_api::InputFile> thumbnail_input_file);
|
||||||
|
|
||||||
|
void on_upload_message_media_success(QuickReplyShortcutId shortcut_id, MessageId message_id, FileId file_id,
|
||||||
|
telegram_api::object_ptr<telegram_api::MessageMedia> &&media);
|
||||||
|
|
||||||
|
void on_upload_message_media_fail(QuickReplyShortcutId shortcut_id, MessageId message_id, Status error);
|
||||||
|
|
||||||
|
void on_upload_message_media_finished(int64 media_album_id, QuickReplyShortcutId shortcut_id, MessageId message_id,
|
||||||
|
Status result);
|
||||||
|
|
||||||
|
void do_send_message_group(QuickReplyShortcutId shortcut_id, int64 media_album_id);
|
||||||
|
|
||||||
void on_message_media_uploaded(const QuickReplyMessage *m,
|
void on_message_media_uploaded(const QuickReplyMessage *m,
|
||||||
telegram_api::object_ptr<telegram_api::InputMedia> &&input_media, FileId file_id,
|
telegram_api::object_ptr<telegram_api::InputMedia> &&input_media, FileId file_id,
|
||||||
FileId thumbnail_file_id);
|
FileId thumbnail_file_id);
|
||||||
|
|
||||||
static int64 generate_new_media_album_id();
|
void on_send_media_group_file_reference_error(QuickReplyShortcutId shortcut_id, vector<int64> random_ids);
|
||||||
|
|
||||||
|
int64 generate_new_media_album_id() const;
|
||||||
|
|
||||||
void on_edit_quick_reply_message(QuickReplyShortcutId shortcut_id, MessageId message_id, int64 edit_generation,
|
void on_edit_quick_reply_message(QuickReplyShortcutId shortcut_id, MessageId message_id, int64 edit_generation,
|
||||||
FileId file_id, bool was_uploaded,
|
FileId file_id, bool was_uploaded,
|
||||||
@ -423,6 +444,14 @@ class QuickReplyManager final : public Actor {
|
|||||||
};
|
};
|
||||||
FlatHashMap<FileId, UploadedThumbnailInfo, FileIdHash> being_uploaded_thumbnails_; // thumbnail_file_id -> ...
|
FlatHashMap<FileId, UploadedThumbnailInfo, FileIdHash> being_uploaded_thumbnails_; // thumbnail_file_id -> ...
|
||||||
|
|
||||||
|
struct PendingMessageGroupSend {
|
||||||
|
size_t finished_count = 0;
|
||||||
|
vector<MessageId> message_ids;
|
||||||
|
vector<bool> is_finished;
|
||||||
|
vector<Status> results;
|
||||||
|
};
|
||||||
|
FlatHashMap<int64, PendingMessageGroupSend> pending_message_group_sends_; // media_album_id -> ...
|
||||||
|
|
||||||
int64 current_message_edit_generation_ = 0;
|
int64 current_message_edit_generation_ = 0;
|
||||||
|
|
||||||
Td *td_;
|
Td *td_;
|
||||||
|
@ -5928,6 +5928,18 @@ void Td::on_request(uint64 id, td_api::addQuickReplyShortcutInlineQueryResultMes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Td::on_request(uint64 id, td_api::addQuickReplyShortcutMessageAlbum &request) {
|
||||||
|
CHECK_IS_USER();
|
||||||
|
CLEAN_INPUT_STRING(request.shortcut_name_);
|
||||||
|
auto r_messages = quick_reply_manager_->send_message_group(
|
||||||
|
request.shortcut_name_, MessageId(request.reply_to_message_id_), std::move(request.input_message_contents_));
|
||||||
|
if (r_messages.is_error()) {
|
||||||
|
send_closure(actor_id(this), &Td::send_error, id, r_messages.move_as_error());
|
||||||
|
} else {
|
||||||
|
send_closure(actor_id(this), &Td::send_result, id, r_messages.move_as_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Td::on_request(uint64 id, td_api::readdQuickReplyShortcutMessages &request) {
|
void Td::on_request(uint64 id, td_api::readdQuickReplyShortcutMessages &request) {
|
||||||
CHECK_IS_USER();
|
CHECK_IS_USER();
|
||||||
CLEAN_INPUT_STRING(request.shortcut_name_);
|
CLEAN_INPUT_STRING(request.shortcut_name_);
|
||||||
|
@ -909,6 +909,8 @@ class Td final : public Actor {
|
|||||||
|
|
||||||
void on_request(uint64 id, td_api::addQuickReplyShortcutInlineQueryResultMessage &request);
|
void on_request(uint64 id, td_api::addQuickReplyShortcutInlineQueryResultMessage &request);
|
||||||
|
|
||||||
|
void on_request(uint64 id, td_api::addQuickReplyShortcutMessageAlbum &request);
|
||||||
|
|
||||||
void on_request(uint64 id, td_api::readdQuickReplyShortcutMessages &request);
|
void on_request(uint64 id, td_api::readdQuickReplyShortcutMessages &request);
|
||||||
|
|
||||||
void on_request(uint64 id, td_api::editQuickReplyMessage &request);
|
void on_request(uint64 id, td_api::editQuickReplyMessage &request);
|
||||||
|
@ -4878,6 +4878,9 @@ class CliClient final : public Actor {
|
|||||||
send_request(td_api::make_object<td_api::sendBusinessMessageAlbum>(
|
send_request(td_api::make_object<td_api::sendBusinessMessageAlbum>(
|
||||||
business_connection_id_, chat_id, get_input_message_reply_to(), rand_bool(), rand_bool(),
|
business_connection_id_, chat_id, get_input_message_reply_to(), rand_bool(), rand_bool(),
|
||||||
std::move(input_message_contents)));
|
std::move(input_message_contents)));
|
||||||
|
} else if (!quick_reply_shortcut_name_.empty()) {
|
||||||
|
send_request(td_api::make_object<td_api::addQuickReplyShortcutMessageAlbum>(
|
||||||
|
quick_reply_shortcut_name_, reply_message_id_, std::move(input_message_contents)));
|
||||||
} else {
|
} else {
|
||||||
send_request(td_api::make_object<td_api::sendMessageAlbum>(
|
send_request(td_api::make_object<td_api::sendMessageAlbum>(
|
||||||
chat_id, message_thread_id_, get_input_message_reply_to(), default_message_send_options(),
|
chat_id, message_thread_id_, get_input_message_reply_to(), default_message_send_options(),
|
||||||
@ -4895,6 +4898,9 @@ class CliClient final : public Actor {
|
|||||||
send_request(td_api::make_object<td_api::sendBusinessMessageAlbum>(
|
send_request(td_api::make_object<td_api::sendBusinessMessageAlbum>(
|
||||||
business_connection_id_, chat_id, get_input_message_reply_to(), rand_bool(), rand_bool(),
|
business_connection_id_, chat_id, get_input_message_reply_to(), rand_bool(), rand_bool(),
|
||||||
std::move(input_message_contents)));
|
std::move(input_message_contents)));
|
||||||
|
} else if (!quick_reply_shortcut_name_.empty()) {
|
||||||
|
send_request(td_api::make_object<td_api::addQuickReplyShortcutMessageAlbum>(
|
||||||
|
quick_reply_shortcut_name_, reply_message_id_, std::move(input_message_contents)));
|
||||||
} else {
|
} else {
|
||||||
send_request(td_api::make_object<td_api::sendMessageAlbum>(
|
send_request(td_api::make_object<td_api::sendMessageAlbum>(
|
||||||
chat_id, message_thread_id_, get_input_message_reply_to(), default_message_send_options(),
|
chat_id, message_thread_id_, get_input_message_reply_to(), default_message_send_options(),
|
||||||
|
Loading…
Reference in New Issue
Block a user