Support sending of multiple paid media.

This commit is contained in:
levlam 2024-06-27 18:38:53 +03:00
parent b94cab9432
commit c77d6957c5
6 changed files with 252 additions and 82 deletions

View File

@ -1006,9 +1006,9 @@ void BusinessConnectionManager::do_upload_media(BeingUploadedMedia &&being_uploa
<< ", have_input_file = " << have_input_file << ", have_input_thumbnail = " << have_input_thumbnail; << ", have_input_file = " << have_input_file << ", have_input_thumbnail = " << have_input_thumbnail;
const auto *message = being_uploaded_media.message_.get(); const auto *message = being_uploaded_media.message_.get();
auto input_media = auto input_media = get_message_content_input_media(message->content_.get(), -1, td_, std::move(input_file),
get_message_content_input_media(message->content_.get(), td_, std::move(input_file), std::move(input_thumbnail), std::move(input_thumbnail), file_id, thumbnail_file_id,
file_id, thumbnail_file_id, message->ttl_, message->send_emoji_, true); message->ttl_, message->send_emoji_, true);
CHECK(input_media != nullptr); CHECK(input_media != nullptr);
if (is_uploaded_input_media(input_media)) { if (is_uploaded_input_media(input_media)) {
UploadMediaResult result; UploadMediaResult result;
@ -1025,7 +1025,7 @@ void BusinessConnectionManager::complete_upload_media(unique_ptr<PendingMessage>
telegram_api::object_ptr<telegram_api::MessageMedia> &&media, telegram_api::object_ptr<telegram_api::MessageMedia> &&media,
Promise<UploadMediaResult> &&promise) { Promise<UploadMediaResult> &&promise) {
auto new_content = auto new_content =
get_uploaded_message_content(td_, message->content_.get(), std::move(media), get_uploaded_message_content(td_, message->content_.get(), -1, std::move(media),
td_->dialog_manager_->get_my_dialog_id(), G()->unix_time(), "complete_upload_media"); td_->dialog_manager_->get_my_dialog_id(), G()->unix_time(), "complete_upload_media");
bool is_content_changed = false; bool is_content_changed = false;
bool need_update = false; bool need_update = false;

View File

@ -3389,12 +3389,16 @@ SecretInputMedia get_message_content_secret_input_media(
} }
static telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_media_impl( static telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_media_impl(
const MessageContent *content, Td *td, telegram_api::object_ptr<telegram_api::InputFile> input_file, const MessageContent *content, int32 media_pos, Td *td,
telegram_api::object_ptr<telegram_api::InputFile> input_file,
telegram_api::object_ptr<telegram_api::InputFile> input_thumbnail, MessageSelfDestructType ttl, telegram_api::object_ptr<telegram_api::InputFile> input_thumbnail, MessageSelfDestructType ttl,
const string &emoji) { const string &emoji) {
if (!can_message_content_have_input_media(td, content, false)) { if (!can_message_content_have_input_media(td, content, false)) {
return nullptr; return nullptr;
} }
if (media_pos >= 0) {
CHECK(content->get_type() == MessageContentType::PaidMedia);
}
switch (content->get_type()) { switch (content->get_type()) {
case MessageContentType::Animation: { case MessageContentType::Animation: {
const auto *m = static_cast<const MessageAnimation *>(content); const auto *m = static_cast<const MessageAnimation *>(content);
@ -3442,6 +3446,10 @@ static telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_in
} }
case MessageContentType::PaidMedia: { case MessageContentType::PaidMedia: {
const auto *m = static_cast<const MessagePaidMedia *>(content); const auto *m = static_cast<const MessagePaidMedia *>(content);
if (media_pos >= 0) {
CHECK(static_cast<size_t>(media_pos) < m->media.size());
return m->media[media_pos].get_input_media(td, std::move(input_file), std::move(input_thumbnail));
}
CHECK(m->media.size() == 1u || (input_file == nullptr && input_thumbnail == nullptr)); CHECK(m->media.size() == 1u || (input_file == nullptr && input_thumbnail == nullptr));
vector<telegram_api::object_ptr<telegram_api::InputMedia>> input_media; vector<telegram_api::object_ptr<telegram_api::InputMedia>> input_media;
for (auto &extended_media : m->media) { for (auto &extended_media : m->media) {
@ -3547,13 +3555,14 @@ static telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_in
} }
telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_media( telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_media(
const MessageContent *content, Td *td, telegram_api::object_ptr<telegram_api::InputFile> input_file, const MessageContent *content, int32 media_pos, Td *td,
telegram_api::object_ptr<telegram_api::InputFile> input_file,
telegram_api::object_ptr<telegram_api::InputFile> input_thumbnail, FileId file_id, FileId thumbnail_file_id, telegram_api::object_ptr<telegram_api::InputFile> input_thumbnail, FileId file_id, FileId thumbnail_file_id,
MessageSelfDestructType ttl, const string &emoji, bool force) { MessageSelfDestructType ttl, const string &emoji, bool force) {
bool had_input_file = input_file != nullptr; bool had_input_file = input_file != nullptr;
bool had_input_thumbnail = input_thumbnail != nullptr; bool had_input_thumbnail = input_thumbnail != nullptr;
auto input_media = auto input_media = get_message_content_input_media_impl(content, media_pos, td, std::move(input_file),
get_message_content_input_media_impl(content, td, std::move(input_file), std::move(input_thumbnail), ttl, emoji); std::move(input_thumbnail), ttl, emoji);
auto was_uploaded = FileManager::extract_was_uploaded(input_media); auto was_uploaded = FileManager::extract_was_uploaded(input_media);
if (had_input_file) { if (had_input_file) {
if (!was_uploaded) { if (!was_uploaded) {
@ -3586,8 +3595,9 @@ telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_med
telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_media(const MessageContent *content, telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_media(const MessageContent *content,
Td *td, MessageSelfDestructType ttl, Td *td, MessageSelfDestructType ttl,
const string &emoji, bool force) { const string &emoji, bool force,
auto input_media = get_message_content_input_media_impl(content, td, nullptr, nullptr, ttl, emoji); int32 media_pos) {
auto input_media = get_message_content_input_media_impl(content, media_pos, td, nullptr, nullptr, ttl, emoji);
auto file_references = FileManager::extract_file_references(input_media); auto file_references = FileManager::extract_file_references(input_media);
for (size_t i = 0; i < file_references.size(); i++) { for (size_t i = 0; i < file_references.size(); i++) {
if (file_references[i] == FileReferenceView::invalid_file_reference()) { if (file_references[i] == FileReferenceView::invalid_file_reference()) {
@ -3662,6 +3672,7 @@ telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_med
bool is_uploaded_input_media(telegram_api::object_ptr<telegram_api::InputMedia> &input_media) { bool is_uploaded_input_media(telegram_api::object_ptr<telegram_api::InputMedia> &input_media) {
CHECK(input_media != nullptr); CHECK(input_media != nullptr);
LOG(DEBUG) << "Have " << to_string(input_media);
switch (input_media->get_id()) { switch (input_media->get_id()) {
case telegram_api::inputMediaUploadedDocument::ID: case telegram_api::inputMediaUploadedDocument::ID:
static_cast<telegram_api::inputMediaUploadedDocument *>(input_media.get())->flags_ |= static_cast<telegram_api::inputMediaUploadedDocument *>(input_media.get())->flags_ |=
@ -7766,8 +7777,24 @@ static void set_message_content_has_spoiler(MessageContent *content, bool has_sp
} }
unique_ptr<MessageContent> get_uploaded_message_content( unique_ptr<MessageContent> get_uploaded_message_content(
Td *td, const MessageContent *old_content, telegram_api::object_ptr<telegram_api::MessageMedia> &&media_ptr, Td *td, const MessageContent *old_content, int32 media_pos,
DialogId owner_dialog_id, int32 message_date, const char *source) { telegram_api::object_ptr<telegram_api::MessageMedia> &&media_ptr, DialogId owner_dialog_id, int32 message_date,
const char *source) {
if (media_pos >= 0) {
CHECK(old_content->get_type() == MessageContentType::PaidMedia);
auto paid_media = static_cast<const MessagePaidMedia *>(old_content);
CHECK(static_cast<size_t>(media_pos) < paid_media->media.size());
auto content = make_unique<MessagePaidMedia>(*paid_media);
auto media = MessageExtendedMedia(td, std::move(media_ptr), owner_dialog_id);
if (!media.has_input_media()) {
LOG(ERROR) << "Receive invalid uploaded paid media";
} else {
bool is_content_changed = false;
bool need_update = false;
content->media[media_pos].merge_files(td, media, owner_dialog_id, true, is_content_changed, need_update);
}
return content;
}
auto caption = get_message_content_caption(old_content); auto caption = get_message_content_caption(old_content);
auto has_spoiler = get_message_content_has_spoiler(old_content); auto has_spoiler = get_message_content_has_spoiler(old_content);
auto content = get_message_content(td, caption == nullptr ? FormattedText() : *caption, std::move(media_ptr), auto content = get_message_content(td, caption == nullptr ? FormattedText() : *caption, std::move(media_ptr),

View File

@ -128,13 +128,15 @@ SecretInputMedia get_message_content_secret_input_media(
BufferSlice thumbnail, int32 layer); BufferSlice thumbnail, int32 layer);
telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_media( telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_media(
const MessageContent *content, Td *td, telegram_api::object_ptr<telegram_api::InputFile> input_file, const MessageContent *content, int32 media_pos, Td *td,
telegram_api::object_ptr<telegram_api::InputFile> input_file,
telegram_api::object_ptr<telegram_api::InputFile> input_thumbnail, FileId file_id, FileId thumbnail_file_id, telegram_api::object_ptr<telegram_api::InputFile> input_thumbnail, FileId file_id, FileId thumbnail_file_id,
MessageSelfDestructType ttl, const string &emoji, bool force); MessageSelfDestructType ttl, const string &emoji, bool force);
telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_media(const MessageContent *content, telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_input_media(const MessageContent *content,
Td *td, MessageSelfDestructType ttl, Td *td, MessageSelfDestructType ttl,
const string &emoji, bool force); const string &emoji, bool force,
int32 media_pos = -1);
telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_fake_input_media( telegram_api::object_ptr<telegram_api::InputMedia> get_message_content_fake_input_media(
Td *td, telegram_api::object_ptr<telegram_api::InputFile> input_file, FileId file_id); Td *td, telegram_api::object_ptr<telegram_api::InputFile> input_file, FileId file_id);
@ -239,8 +241,9 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message_tex
bool *disable_web_page_preview, const char *source); bool *disable_web_page_preview, const char *source);
unique_ptr<MessageContent> get_uploaded_message_content( unique_ptr<MessageContent> get_uploaded_message_content(
Td *td, const MessageContent *old_content, telegram_api::object_ptr<telegram_api::MessageMedia> &&media_ptr, Td *td, const MessageContent *old_content, int32 media_pos,
DialogId owner_dialog_id, int32 message_date, const char *source); telegram_api::object_ptr<telegram_api::MessageMedia> &&media_ptr, DialogId owner_dialog_id, int32 message_date,
const char *source);
enum class MessageContentDupType : int32 { enum class MessageContentDupType : int32 {
Send, // normal message sending Send, // normal message sending

View File

@ -3318,6 +3318,7 @@ class SendMediaQuery final : public Td::ResultHandler {
class UploadMediaQuery final : public Td::ResultHandler { class UploadMediaQuery final : public Td::ResultHandler {
DialogId dialog_id_; DialogId dialog_id_;
MessageId message_id_; MessageId message_id_;
int32 media_pos_ = -1;
FileId file_id_; FileId file_id_;
FileId thumbnail_file_id_; FileId thumbnail_file_id_;
string file_reference_; string file_reference_;
@ -3325,11 +3326,12 @@ class UploadMediaQuery final : public Td::ResultHandler {
bool was_thumbnail_uploaded_ = false; bool was_thumbnail_uploaded_ = false;
public: public:
void send(DialogId dialog_id, MessageId message_id, FileId file_id, FileId thumbnail_file_id, void send(DialogId dialog_id, MessageId message_id, int32 media_pos, FileId file_id, FileId thumbnail_file_id,
tl_object_ptr<telegram_api::InputMedia> &&input_media) { tl_object_ptr<telegram_api::InputMedia> &&input_media) {
CHECK(input_media != nullptr); CHECK(input_media != nullptr);
dialog_id_ = dialog_id; dialog_id_ = dialog_id;
message_id_ = message_id; message_id_ = message_id;
media_pos_ = media_pos;
file_id_ = file_id; file_id_ = file_id;
thumbnail_file_id_ = thumbnail_file_id; thumbnail_file_id_ = thumbnail_file_id;
file_reference_ = FileManager::extract_file_reference(input_media); file_reference_ = FileManager::extract_file_reference(input_media);
@ -3361,7 +3363,7 @@ class UploadMediaQuery final : public Td::ResultHandler {
auto ptr = result_ptr.move_as_ok(); auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for UploadMediaQuery for " << message_id_ << " in " << dialog_id_ << ": " LOG(INFO) << "Receive result for UploadMediaQuery for " << message_id_ << " in " << dialog_id_ << ": "
<< to_string(ptr); << to_string(ptr);
td_->messages_manager_->on_upload_message_media_success(dialog_id_, message_id_, std::move(ptr)); td_->messages_manager_->on_upload_message_media_success(dialog_id_, message_id_, media_pos_, std::move(ptr));
} }
void on_error(Status status) final { void on_error(Status status) final {
@ -3381,7 +3383,7 @@ class UploadMediaQuery final : public Td::ResultHandler {
CHECK(file_id_.is_valid()); CHECK(file_id_.is_valid());
auto bad_parts = FileManager::get_missing_file_parts(status); auto bad_parts = FileManager::get_missing_file_parts(status);
if (!bad_parts.empty()) { if (!bad_parts.empty()) {
td_->messages_manager_->on_upload_message_media_file_parts_missing(dialog_id_, message_id_, td_->messages_manager_->on_upload_message_media_file_parts_missing(dialog_id_, message_id_, media_pos_,
std::move(bad_parts)); std::move(bad_parts));
return; return;
} else { } else {
@ -3390,7 +3392,7 @@ class UploadMediaQuery final : public Td::ResultHandler {
} else if (FileReferenceManager::is_file_reference_error(status)) { } else if (FileReferenceManager::is_file_reference_error(status)) {
LOG(ERROR) << "Receive file reference error for UploadMediaQuery"; LOG(ERROR) << "Receive file reference error for UploadMediaQuery";
} }
td_->messages_manager_->on_upload_message_media_fail(dialog_id_, message_id_, std::move(status)); td_->messages_manager_->on_upload_message_media_fail(dialog_id_, message_id_, media_pos_, std::move(status));
} }
}; };
@ -8345,7 +8347,7 @@ void MessagesManager::do_send_media(DialogId dialog_id, const Message *m, int32
bool have_input_thumbnail = input_thumbnail != nullptr; bool have_input_thumbnail = input_thumbnail != nullptr;
LOG(INFO) << "Do send media file " << file_id << " with thumbnail " << thumbnail_file_id LOG(INFO) << "Do send media file " << file_id << " with thumbnail " << thumbnail_file_id
<< ", have_input_file = " << have_input_file << ", have_input_thumbnail = " << have_input_thumbnail << ", have_input_file = " << have_input_file << ", have_input_thumbnail = " << have_input_thumbnail
<< ", self-destruct time = " << m->ttl; << ", self-destruct time = " << m->ttl << ", media_pos = " << media_pos;
const MessageContent *content = nullptr; const MessageContent *content = nullptr;
if (m->message_id.is_any_server()) { if (m->message_id.is_any_server()) {
@ -8357,21 +8359,16 @@ void MessagesManager::do_send_media(DialogId dialog_id, const Message *m, int32
} }
} else { } else {
content = m->content.get(); content = m->content.get();
if (media_pos >= 0) {
// TODO PaidMedia
LOG(ERROR) << "PaidMedia upload isn't supported";
return;
}
} }
auto input_media = get_message_content_input_media(content, td_, std::move(input_file), std::move(input_thumbnail), auto input_media =
file_id, thumbnail_file_id, m->ttl, m->send_emoji, true); get_message_content_input_media(content, media_pos, td_, std::move(input_file), std::move(input_thumbnail),
LOG_CHECK(input_media != nullptr) << to_string(get_message_object(dialog_id, m, "do_send_media")) << ' ' file_id, thumbnail_file_id, m->ttl, m->send_emoji, true);
<< have_input_file << ' ' << have_input_thumbnail << ' ' << file_id << ' ' LOG_CHECK(input_media != nullptr) << to_string(get_message_object(dialog_id, m, "do_send_media")) << ' ' << media_pos
<< ' ' << have_input_file << ' ' << have_input_thumbnail << ' ' << file_id << ' '
<< thumbnail_file_id << ' ' << m->ttl; << thumbnail_file_id << ' ' << m->ttl;
on_message_media_uploaded(dialog_id, m, std::move(input_media), {file_id}, {thumbnail_file_id}); on_message_media_uploaded(dialog_id, m, media_pos, std::move(input_media), {file_id}, {thumbnail_file_id});
} }
void MessagesManager::do_send_secret_media(DialogId dialog_id, const Message *m, FileId file_id, void MessagesManager::do_send_secret_media(DialogId dialog_id, const Message *m, FileId file_id,
@ -23382,7 +23379,10 @@ void MessagesManager::cancel_send_message_query(DialogId dialog_id, Message *m)
if (m->media_album_id != 0) { if (m->media_album_id != 0) {
send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, dialog_id, send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, dialog_id,
m->message_id, Status::OK()); m->message_id, -1, Status::OK());
} else if (m->content->get_type() == MessageContentType::PaidMedia) {
LOG(INFO) << "Remove paid media group send from " << MessageFullId{dialog_id, m->message_id};
pending_paid_media_group_sends_.erase({dialog_id, m->message_id});
} }
if (!m->message_id.is_scheduled() && G()->keep_media_order() && !m->is_copy) { if (!m->message_id.is_scheduled() && G()->keep_media_order() && !m->is_copy) {
@ -23962,7 +23962,7 @@ void MessagesManager::save_send_message_log_event(DialogId dialog_id, const Mess
binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::SendMessage, get_log_event_storer(log_event)); binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::SendMessage, get_log_event_storer(log_event));
} }
void MessagesManager::do_send_message(DialogId dialog_id, const Message *m, vector<int> bad_parts) { void MessagesManager::do_send_message(DialogId dialog_id, const Message *m, int32 media_pos, vector<int> bad_parts) {
bool is_edit = m->message_id.is_any_server(); bool is_edit = m->message_id.is_any_server();
LOG(INFO) << "Do " << (is_edit ? "edit" : "send") << ' ' << MessageFullId(dialog_id, m->message_id); LOG(INFO) << "Do " << (is_edit ? "edit" : "send") << ' ' << MessageFullId(dialog_id, m->message_id);
bool is_secret = dialog_id.get_type() == DialogType::SecretChat; bool is_secret = dialog_id.get_type() == DialogType::SecretChat;
@ -23989,7 +23989,7 @@ void MessagesManager::do_send_message(DialogId dialog_id, const Message *m, vect
auto thumbnail_file_ids = get_message_content_thumbnail_file_ids(content, td_); auto thumbnail_file_ids = get_message_content_thumbnail_file_ids(content, td_);
LOG(DEBUG) << "Need to send files " << file_ids << " with thumbnails " << thumbnail_file_ids; LOG(DEBUG) << "Need to send files " << file_ids << " with thumbnails " << thumbnail_file_ids;
if (!bad_parts.empty()) { if (!bad_parts.empty()) {
CHECK(file_ids.size() <= 1u); CHECK(file_ids.size() <= 1u || media_pos >= 0);
} }
if (file_ids.size() != thumbnail_file_ids.size()) { if (file_ids.size() != thumbnail_file_ids.size()) {
CHECK(file_ids.size() == 1u); CHECK(file_ids.size() == 1u);
@ -24019,15 +24019,32 @@ void MessagesManager::do_send_message(DialogId dialog_id, const Message *m, vect
on_secret_message_media_uploaded(dialog_id, m, std::move(secret_input_media), file_id, thumbnail_file_id); on_secret_message_media_uploaded(dialog_id, m, std::move(secret_input_media), file_id, thumbnail_file_id);
} }
} else { } else {
if (media_pos >= 0) {
CHECK(!bad_parts.empty());
CHECK(static_cast<size_t>(media_pos) < file_ids.size());
CHECK(static_cast<size_t>(media_pos) < thumbnail_file_ids.size());
}
auto input_media = get_message_content_input_media(content, td_, m->ttl, m->send_emoji, auto input_media = get_message_content_input_media(content, td_, m->ttl, m->send_emoji,
td_->auth_manager_->is_bot() && bad_parts.empty()); td_->auth_manager_->is_bot() && bad_parts.empty());
if (input_media == nullptr) { if (input_media == nullptr || media_pos >= 0 || !bad_parts.empty()) {
if (content_type == MessageContentType::Game || content_type == MessageContentType::Poll || if (content_type == MessageContentType::Game || content_type == MessageContentType::Poll ||
content_type == MessageContentType::Story) { content_type == MessageContentType::Story) {
return; return;
} }
CHECK(!file_ids.empty()); CHECK(!file_ids.empty());
if (file_ids.size() > 1u && bad_parts.empty()) {
CHECK(!is_secret && !is_edit);
CHECK(media_pos == -1);
LOG(INFO) << "Add paid media group send for " << MessageFullId{dialog_id, m->message_id};
auto &request = pending_paid_media_group_sends_[{dialog_id, m->message_id}];
CHECK(request.is_finished.empty());
request.is_finished.resize(file_ids.size());
request.results.resize(file_ids.size());
}
for (size_t i = 0; i < file_ids.size(); i++) { for (size_t i = 0; i < file_ids.size(); i++) {
if (media_pos >= 0 && static_cast<size_t>(media_pos) != i) {
continue;
}
auto file_id = file_ids[i]; auto file_id = file_ids[i];
CHECK(file_id.is_valid()); CHECK(file_id.is_valid());
@ -24050,14 +24067,14 @@ void MessagesManager::do_send_message(DialogId dialog_id, const Message *m, vect
m->message_id.get()); m->message_id.get());
} }
} else { } else {
on_message_media_uploaded(dialog_id, m, std::move(input_media), std::move(file_ids), on_message_media_uploaded(dialog_id, m, -1, std::move(input_media), std::move(file_ids),
std::move(thumbnail_file_ids)); std::move(thumbnail_file_ids));
} }
} }
} }
void MessagesManager::on_message_media_uploaded(DialogId dialog_id, const Message *m, void MessagesManager::on_message_media_uploaded(DialogId dialog_id, const Message *m, int32 media_pos,
tl_object_ptr<telegram_api::InputMedia> &&input_media, telegram_api::object_ptr<telegram_api::InputMedia> &&input_media,
vector<FileId> file_ids, vector<FileId> thumbnail_file_ids) { vector<FileId> file_ids, vector<FileId> thumbnail_file_ids) {
if (G()->close_flag()) { if (G()->close_flag()) {
return; return;
@ -24067,6 +24084,7 @@ void MessagesManager::on_message_media_uploaded(DialogId dialog_id, const Messag
CHECK(input_media != nullptr); CHECK(input_media != nullptr);
auto message_id = m->message_id; auto message_id = m->message_id;
if (message_id.is_any_server()) { if (message_id.is_any_server()) {
CHECK(media_pos == -1);
CHECK(file_ids.size() == 1u); CHECK(file_ids.size() == 1u);
auto file_id = file_ids[0]; auto file_id = file_ids[0];
auto thumbnail_file_id = thumbnail_file_ids.empty() ? FileId() : thumbnail_file_ids[0]; auto thumbnail_file_id = thumbnail_file_ids.empty() ? FileId() : thumbnail_file_ids[0];
@ -24092,7 +24110,7 @@ void MessagesManager::on_message_media_uploaded(DialogId dialog_id, const Messag
return; return;
} }
if (m->media_album_id == 0) { if (m->media_album_id == 0 && media_pos == -1) {
send_closure_later( send_closure_later(
actor_id(this), &MessagesManager::on_media_message_ready_to_send, dialog_id, message_id, actor_id(this), &MessagesManager::on_media_message_ready_to_send, dialog_id, message_id,
PromiseCreator::lambda([this, dialog_id, input_media = std::move(input_media), file_ids = std::move(file_ids), PromiseCreator::lambda([this, dialog_id, input_media = std::move(input_media), file_ids = std::move(file_ids),
@ -24122,11 +24140,11 @@ void MessagesManager::on_message_media_uploaded(DialogId dialog_id, const Messag
CHECK(file_ids.size() == 1u); CHECK(file_ids.size() == 1u);
auto file_id = file_ids[0]; auto file_id = file_ids[0];
auto thumbnail_file_id = thumbnail_file_ids.empty() ? FileId() : thumbnail_file_ids[0]; auto thumbnail_file_id = thumbnail_file_ids.empty() ? FileId() : thumbnail_file_ids[0];
td_->create_handler<UploadMediaQuery>()->send(dialog_id, message_id, file_id, thumbnail_file_id, td_->create_handler<UploadMediaQuery>()->send(dialog_id, message_id, media_pos, file_id, thumbnail_file_id,
std::move(input_media)); std::move(input_media));
} else { } else {
send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id,
dialog_id, message_id, Status::OK()); dialog_id, message_id, media_pos, Status::OK());
} }
} }
} }
@ -24157,11 +24175,11 @@ void MessagesManager::on_secret_message_media_uploaded(DialogId dialog_id, const
return td_->create_handler<UploadEncryptedMediaQuery>()->send(dialog_id, m->message_id, std::move(secret_input_media)); return td_->create_handler<UploadEncryptedMediaQuery>()->send(dialog_id, m->message_id, std::move(secret_input_media));
case telegram_api::inputEncryptedFile::ID: case telegram_api::inputEncryptedFile::ID:
return send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, return send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id,
dialog_id, m->message_id, Status::OK()); dialog_id, m->message_id, -1, Status::OK());
default: default:
LOG(ERROR) << "Have wrong secret input media " << to_string(secret_input_media->input_file_); LOG(ERROR) << "Have wrong secret input media " << to_string(secret_input_media->input_file_);
return send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, return send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id,
dialog_id, m->message_id, Status::Error(400, "Invalid input media")); dialog_id, m->message_id, -1, Status::Error(400, "Invalid input media"));
} }
*/ */
// TODO use file_id, thumbnail_file_id, was_uploaded, was_thumbnail_uploaded, // TODO use file_id, thumbnail_file_id, was_uploaded, was_thumbnail_uploaded,
@ -24222,8 +24240,8 @@ void MessagesManager::send_secret_message(DialogId dialog_id, const Message *m,
std::move(media.input_file_), Promise<Unit>()); std::move(media.input_file_), Promise<Unit>());
} }
void MessagesManager::on_upload_message_media_success(DialogId dialog_id, MessageId message_id, void MessagesManager::on_upload_message_media_success(DialogId dialog_id, MessageId message_id, int32 media_pos,
tl_object_ptr<telegram_api::MessageMedia> &&media) { telegram_api::object_ptr<telegram_api::MessageMedia> &&media) {
Dialog *d = get_dialog(dialog_id); Dialog *d = get_dialog(dialog_id);
CHECK(d != nullptr); CHECK(d != nullptr);
@ -24243,29 +24261,30 @@ void MessagesManager::on_upload_message_media_success(DialogId dialog_id, Messag
return; // the message should be deleted soon return; // the message should be deleted soon
} }
auto content = get_uploaded_message_content(td_, m->content.get(), std::move(media), dialog_id, m->date, auto content = get_uploaded_message_content(td_, m->content.get(), media_pos, std::move(media), dialog_id, m->date,
"on_upload_message_media_success"); "on_upload_message_media_success");
bool is_content_changed = false; bool is_content_changed = false;
bool need_update = update_message_content(dialog_id, m, std::move(content), true, true, is_content_changed); bool need_update =
if (need_update) { update_message_content(dialog_id, m, std::move(content), media_pos == -1, true, is_content_changed);
if (need_update || media_pos >= 0) {
send_update_message_content(d, m, true, "on_upload_message_media_success"); send_update_message_content(d, m, true, "on_upload_message_media_success");
} }
if (is_content_changed || need_update) { if (is_content_changed || need_update || media_pos >= 0) {
on_message_changed(d, m, need_update, "on_upload_message_media_success"); on_message_changed(d, m, need_update, "on_upload_message_media_success");
} }
auto input_media = get_message_content_input_media(m->content.get(), td_, m->ttl, m->send_emoji, true); auto input_media = get_message_content_input_media(m->content.get(), td_, m->ttl, m->send_emoji, true, media_pos);
Status result; Status result;
if (input_media == nullptr) { if (input_media == nullptr) {
result = Status::Error(400, "Failed to upload file"); result = Status::Error(400, "Failed to upload file");
} }
send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, dialog_id, send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, dialog_id,
m->message_id, std::move(result)); m->message_id, media_pos, std::move(result));
} }
void MessagesManager::on_upload_message_media_file_parts_missing(DialogId dialog_id, MessageId message_id, void MessagesManager::on_upload_message_media_file_parts_missing(DialogId dialog_id, MessageId message_id,
vector<int> &&bad_parts) { int32 media_pos, vector<int> &&bad_parts) {
Dialog *d = get_dialog(dialog_id); Dialog *d = get_dialog(dialog_id);
CHECK(d != nullptr); CHECK(d != nullptr);
@ -24285,10 +24304,11 @@ void MessagesManager::on_upload_message_media_file_parts_missing(DialogId dialog
CHECK(dialog_id.get_type() != DialogType::SecretChat); CHECK(dialog_id.get_type() != DialogType::SecretChat);
do_send_message(dialog_id, m, std::move(bad_parts)); do_send_message(dialog_id, m, media_pos, std::move(bad_parts));
} }
void MessagesManager::on_upload_message_media_fail(DialogId dialog_id, MessageId message_id, Status error) { void MessagesManager::on_upload_message_media_fail(DialogId dialog_id, MessageId message_id, int32 media_pos,
Status error) {
Dialog *d = get_dialog(dialog_id); Dialog *d = get_dialog(dialog_id);
CHECK(d != nullptr); CHECK(d != nullptr);
@ -24309,11 +24329,48 @@ void MessagesManager::on_upload_message_media_fail(DialogId dialog_id, MessageId
CHECK(dialog_id.get_type() != DialogType::SecretChat); CHECK(dialog_id.get_type() != DialogType::SecretChat);
send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, dialog_id, send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, dialog_id,
m->message_id, std::move(error)); m->message_id, media_pos, std::move(error));
} }
void MessagesManager::on_upload_message_media_finished(int64 media_album_id, DialogId dialog_id, MessageId message_id, void MessagesManager::on_upload_message_media_finished(int64 media_album_id, DialogId dialog_id, MessageId message_id,
Status result) { int32 media_pos, Status result) {
if (media_pos >= 0) {
CHECK(media_album_id == 0);
LOG(INFO) << "Finished to upload media " << media_pos << " from " << message_id << " in " << dialog_id;
auto it = pending_paid_media_group_sends_.find({dialog_id, message_id});
if (it == pending_paid_media_group_sends_.end()) {
LOG(INFO) << "The message doesn't need to be sent";
// the message may be already sent or failed to be sent
return;
}
auto &request = it->second;
CHECK(static_cast<size_t>(media_pos) < request.is_finished.size());
if (request.is_finished[media_pos]) {
LOG(INFO) << "Upload media of " << message_id << " in " << dialog_id << " at pos " << media_pos
<< " was already finished";
return;
}
LOG(INFO) << "Finish to upload media of " << message_id << " in " << dialog_id << " at pos " << media_pos
<< " with result " << result << " and previous finished_count = " << request.finished_count;
request.results[media_pos] = std::move(result);
request.is_finished[media_pos] = true;
request.finished_count++;
if (request.finished_count == request.results.size() || request.results[media_pos].is_error()) {
on_media_message_ready_to_send(dialog_id, message_id,
PromiseCreator::lambda([this, dialog_id](Result<Message *> result) mutable {
if (G()->close_flag() || result.is_error()) {
return;
}
auto m = result.move_as_ok();
CHECK(m != nullptr);
do_send_paid_media_group(dialog_id, m->message_id);
}));
}
return;
}
CHECK(media_album_id < 0); CHECK(media_album_id < 0);
auto it = pending_message_group_sends_.find(media_album_id); auto it = pending_message_group_sends_.find(media_album_id);
if (it == pending_message_group_sends_.end()) { if (it == pending_message_group_sends_.end()) {
@ -24346,7 +24403,7 @@ void MessagesManager::on_upload_message_media_finished(int64 media_album_id, Dia
request.is_finished[pos] = true; request.is_finished[pos] = true;
request.finished_count++; request.finished_count++;
if (request.finished_count == request.message_ids.size() || request.results[pos].is_error()) { if (request.finished_count == request.results.size() || request.results[pos].is_error()) {
// must use send_closure_later if some messages may be being deleted now // must use send_closure_later if some messages may be being deleted now
// but this function is called only through send_closure_later, so there should be no being deleted messages // but this function is called only through send_closure_later, so there should be no being deleted messages
// we must use synchronous calls to keep the correct message order during copying of multiple messages // we must use synchronous calls to keep the correct message order during copying of multiple messages
@ -24482,6 +24539,68 @@ void MessagesManager::do_send_message_group(int64 media_album_id) {
std::move(input_single_media), is_copy); std::move(input_single_media), is_copy);
} }
void MessagesManager::do_send_paid_media_group(DialogId dialog_id, MessageId message_id) {
if (G()->close_flag()) {
return;
}
auto it = pending_paid_media_group_sends_.find({dialog_id, message_id});
if (it == pending_paid_media_group_sends_.end()) {
// the paid media may be already sent or failed to be sent
return;
}
auto &request = it->second;
Dialog *d = get_dialog(dialog_id);
CHECK(d != nullptr);
auto *m = get_message(d, message_id);
CHECK(m != nullptr);
CHECK(m->content->get_type() == MessageContentType::PaidMedia);
auto random_id = begin_send_message(dialog_id, m);
auto status = can_send_message(dialog_id);
bool success = status.is_ok();
for (auto &result : request.results) {
if (success && result.is_error()) {
status = result.clone();
success = false;
}
}
for (bool is_finished : request.is_finished) {
if (!is_finished) {
success = false;
}
}
if (!success) {
if (status.is_ok()) {
status = Status::Error(400, "Group send failed");
}
on_send_message_fail(random_id, std::move(status));
CHECK(pending_paid_media_group_sends_.count({dialog_id, message_id}) == 0);
return;
}
auto file_ids = get_message_content_any_file_ids(m->content.get());
auto thumbnail_file_ids = get_message_content_thumbnail_file_ids(m->content.get(), td_);
auto input_media = get_message_content_input_media(m->content.get(), td_, m->ttl, m->send_emoji, true);
CHECK(input_media != nullptr);
pending_paid_media_group_sends_.erase(it);
LOG(INFO) << "Begin to send paid media group " << message_id << " to " << dialog_id;
const FormattedText *caption = get_message_content_caption(m->content.get());
td_->create_handler<SendMediaQuery>()->send(
std::move(file_ids), std::move(thumbnail_file_ids), get_message_flags(m), dialog_id,
get_send_message_as_input_peer(m), *get_message_input_reply_to(m), m->initial_top_thread_message_id,
get_message_schedule_date(m), m->effect_id, get_input_reply_markup(td_->user_manager_.get(), m->reply_markup),
get_input_message_entities(td_->user_manager_.get(), caption, "do_send_paid_media_group"),
caption == nullptr ? "" : caption->text, std::move(input_media), m->content->get_type(), m->is_copy, random_id,
&m->send_query_ref);
}
void MessagesManager::on_text_message_ready_to_send(DialogId dialog_id, MessageId message_id) { void MessagesManager::on_text_message_ready_to_send(DialogId dialog_id, MessageId message_id) {
if (G()->close_flag()) { if (G()->close_flag()) {
return; return;
@ -24558,8 +24677,7 @@ void MessagesManager::on_media_message_ready_to_send(DialogId dialog_id, Message
return; return;
} }
if (it->second) { if (it->second) {
promise.set_error(Status::Error(500, "Duplicate promise")); return promise.set_error(Status::Error(500, "Duplicate promise"));
return;
} }
it->second = std::move(promise); it->second = std::move(promise);
@ -25300,7 +25418,7 @@ void MessagesManager::on_message_media_edited(DialogId dialog_id, MessageId mess
CHECK(file_id.is_valid()); CHECK(file_id.is_valid());
auto bad_parts = FileManager::get_missing_file_parts(result.error()); auto bad_parts = FileManager::get_missing_file_parts(result.error());
if (!bad_parts.empty()) { if (!bad_parts.empty()) {
do_send_message(dialog_id, m, std::move(bad_parts)); do_send_message(dialog_id, m, -1, std::move(bad_parts));
return; return;
} }
@ -25309,7 +25427,7 @@ void MessagesManager::on_message_media_edited(DialogId dialog_id, MessageId mess
if (file_id.is_valid()) { if (file_id.is_valid()) {
VLOG(file_references) << "Receive " << result.error() << " for " << file_id; VLOG(file_references) << "Receive " << result.error() << " for " << file_id;
td_->file_manager_->delete_file_reference(file_id, file_reference); td_->file_manager_->delete_file_reference(file_id, file_reference);
do_send_message(dialog_id, m, {-1}); do_send_message(dialog_id, m, -1, {-1});
return; return;
} else { } else {
LOG(ERROR) << "Receive file reference error, but have no file_id"; LOG(ERROR) << "Receive file reference error, but have no file_id";
@ -29254,7 +29372,7 @@ void MessagesManager::on_send_message_file_parts_missing(int64 random_id, vector
get_log_event_storer(log_event)); get_log_event_storer(log_event));
} }
do_send_message(dialog_id, m, std::move(bad_parts)); do_send_message(dialog_id, m, -1, std::move(bad_parts));
} }
void MessagesManager::on_send_message_file_reference_error(int64 random_id, size_t pos) { void MessagesManager::on_send_message_file_reference_error(int64 random_id, size_t pos) {
@ -29300,14 +29418,24 @@ void MessagesManager::on_send_message_file_reference_error(int64 random_id, size
get_log_event_storer(log_event)); get_log_event_storer(log_event));
} }
int32 media_pos = -1;
auto file_ids = get_message_content_any_file_ids(m->content.get()); auto file_ids = get_message_content_any_file_ids(m->content.get());
if (file_ids.size() > 1u) { if (file_ids.size() > 1u) {
// TODO PaidMedia file reference repair media_pos = pos;
return;
}
CHECK(pos == 0);
do_send_message(dialog_id, m, {-1}); LOG(INFO) << "Add paid media group send for " << message_full_id;
auto &request = pending_paid_media_group_sends_[message_full_id];
CHECK(request.is_finished.empty());
CHECK(static_cast<size_t>(media_pos) < file_ids.size());
request.is_finished.resize(file_ids.size(), true);
request.is_finished[media_pos] = false;
request.finished_count = file_ids.size() - 1;
request.results.resize(file_ids.size());
} else {
CHECK(pos == 0);
}
do_send_message(dialog_id, m, media_pos, {-1});
} }
void MessagesManager::on_send_media_group_file_reference_error(DialogId dialog_id, vector<int64> random_ids) { void MessagesManager::on_send_media_group_file_reference_error(DialogId dialog_id, vector<int64> random_ids) {
@ -29365,7 +29493,7 @@ void MessagesManager::on_send_media_group_file_reference_error(DialogId dialog_i
} }
for (auto m : messages) { for (auto m : messages) {
do_send_message(dialog_id, m, {-1}); do_send_message(dialog_id, m, -1, {-1});
} }
} }

View File

@ -878,12 +878,13 @@ class MessagesManager final : public Actor {
void on_send_message_fail(int64 random_id, Status error); void on_send_message_fail(int64 random_id, Status error);
void on_upload_message_media_success(DialogId dialog_id, MessageId message_id, void on_upload_message_media_success(DialogId dialog_id, MessageId message_id, int32 media_pos,
tl_object_ptr<telegram_api::MessageMedia> &&media); telegram_api::object_ptr<telegram_api::MessageMedia> &&media);
void on_upload_message_media_file_parts_missing(DialogId dialog_id, MessageId message_id, vector<int> &&bad_parts); void on_upload_message_media_file_parts_missing(DialogId dialog_id, MessageId message_id, int32 media_pos,
vector<int> &&bad_parts);
void on_upload_message_media_fail(DialogId dialog_id, MessageId message_id, Status error); void on_upload_message_media_fail(DialogId dialog_id, MessageId message_id, int32 media_pos, Status error);
void on_create_new_dialog(telegram_api::object_ptr<telegram_api::Updates> &&updates, void on_create_new_dialog(telegram_api::object_ptr<telegram_api::Updates> &&updates,
MissingInvitees &&missing_invitees, MissingInvitees &&missing_invitees,
@ -1852,19 +1853,22 @@ class MessagesManager final : public Actor {
tl_object_ptr<telegram_api::InputEncryptedFile> input_encrypted_file, tl_object_ptr<telegram_api::InputEncryptedFile> input_encrypted_file,
BufferSlice thumbnail); BufferSlice thumbnail);
void do_send_message(DialogId dialog_id, const Message *m, vector<int> bad_parts = {}); void do_send_message(DialogId dialog_id, const Message *m, int32 media_pos = -1, vector<int> bad_parts = {});
void on_message_media_uploaded(DialogId dialog_id, const Message *m, void on_message_media_uploaded(DialogId dialog_id, const Message *m, int32 media_pos,
tl_object_ptr<telegram_api::InputMedia> &&input_media, vector<FileId> file_ids, telegram_api::object_ptr<telegram_api::InputMedia> &&input_media,
vector<FileId> thumbnail_file_ids); vector<FileId> file_ids, vector<FileId> thumbnail_file_ids);
void on_secret_message_media_uploaded(DialogId dialog_id, const Message *m, SecretInputMedia &&secret_input_media, void on_secret_message_media_uploaded(DialogId dialog_id, const Message *m, SecretInputMedia &&secret_input_media,
FileId file_id, FileId thumbnail_file_id); FileId file_id, FileId thumbnail_file_id);
void on_upload_message_media_finished(int64 media_album_id, DialogId dialog_id, MessageId message_id, Status result); void on_upload_message_media_finished(int64 media_album_id, DialogId dialog_id, MessageId message_id, int32 media_pos,
Status result);
void do_send_message_group(int64 media_album_id); void do_send_message_group(int64 media_album_id);
void do_send_paid_media_group(DialogId dialog_id, MessageId message_id);
void on_text_message_ready_to_send(DialogId dialog_id, MessageId message_id); void on_text_message_ready_to_send(DialogId dialog_id, MessageId message_id);
void on_media_message_ready_to_send(DialogId dialog_id, MessageId message_id, Promise<Message *> &&promise); void on_media_message_ready_to_send(DialogId dialog_id, MessageId message_id, Promise<Message *> &&promise);
@ -3239,6 +3243,13 @@ class MessagesManager final : public Actor {
}; };
FlatHashMap<int64, PendingMessageGroupSend> pending_message_group_sends_; // media_album_id -> ... FlatHashMap<int64, PendingMessageGroupSend> pending_message_group_sends_; // media_album_id -> ...
struct PendingPaidMediaGroupSend {
size_t finished_count = 0;
vector<bool> is_finished;
vector<Status> results;
};
FlatHashMap<MessageFullId, PendingPaidMediaGroupSend, MessageFullIdHash> pending_paid_media_group_sends_;
WaitFreeHashMap<MessageId, DialogId, MessageIdHash> message_id_to_dialog_id_; WaitFreeHashMap<MessageId, DialogId, MessageIdHash> message_id_to_dialog_id_;
FlatHashMap<MessageId, DialogId, MessageIdHash> last_clear_history_message_id_to_dialog_id_; FlatHashMap<MessageId, DialogId, MessageIdHash> last_clear_history_message_id_to_dialog_id_;

View File

@ -2285,8 +2285,9 @@ void QuickReplyManager::do_send_media(const QuickReplyMessage *m, FileId file_id
auto content = m->message_id.is_server() ? m->edited_content.get() : m->content.get(); auto content = m->message_id.is_server() ? m->edited_content.get() : m->content.get();
CHECK(content != nullptr); CHECK(content != nullptr);
auto input_media = get_message_content_input_media(content, td_, std::move(input_file), std::move(input_thumbnail), auto input_media =
file_id, thumbnail_file_id, {}, m->send_emoji, true); get_message_content_input_media(content, -1, td_, std::move(input_file), std::move(input_thumbnail), file_id,
thumbnail_file_id, {}, m->send_emoji, true);
CHECK(input_media != nullptr); CHECK(input_media != nullptr);
on_message_media_uploaded(m, std::move(input_media), file_id, thumbnail_file_id); on_message_media_uploaded(m, std::move(input_media), file_id, thumbnail_file_id);
@ -2392,8 +2393,8 @@ void QuickReplyManager::on_upload_message_media_success(QuickReplyShortcutId sho
CHECK(message_id.is_yet_unsent()); CHECK(message_id.is_yet_unsent());
auto content = auto content =
get_uploaded_message_content(td_, m->content.get(), std::move(media), td_->dialog_manager_->get_my_dialog_id(), 0, get_uploaded_message_content(td_, m->content.get(), -1, std::move(media),
"on_upload_message_media_success"); td_->dialog_manager_->get_my_dialog_id(), 0, "on_upload_message_media_success");
update_sent_message_content_from_temporary_message(m->content, content, true); update_sent_message_content_from_temporary_message(m->content, content, true);
save_quick_reply_shortcuts(); save_quick_reply_shortcuts();