Support file reference errors in SendMultiMediaActor.

GitOrigin-RevId: ef25dd8bedab0998db1e57572e46e072c5e2e374
This commit is contained in:
levlam 2019-02-08 17:54:23 +03:00
parent 60241730da
commit 6a43a9e91e
9 changed files with 110 additions and 7 deletions

View File

@ -101,6 +101,7 @@ class SaveGifQuery : public Td::ResultHandler {
void on_error(uint64 id, Status status) override { void on_error(uint64 id, Status status) override {
if (FileReferenceManager::is_file_reference_error(status)) { if (FileReferenceManager::is_file_reference_error(status)) {
VLOG(file_references) << "Receive " << status << " for " << file_id_;
td->file_manager_->delete_file_reference(file_id_, file_reference_); td->file_manager_->delete_file_reference(file_id_, file_reference_);
td->file_reference_manager_->repair_file_reference( td->file_reference_manager_->repair_file_reference(
file_id_, PromiseCreator::lambda([animation_id = file_id_, unsave = unsave_, file_id_, PromiseCreator::lambda([animation_id = file_id_, unsave = unsave_,

View File

@ -740,6 +740,7 @@ class UpdateProfilePhotoQuery : public Td::ResultHandler {
void on_error(uint64 id, Status status) override { void on_error(uint64 id, Status status) override {
if (FileReferenceManager::is_file_reference_error(status)) { if (FileReferenceManager::is_file_reference_error(status)) {
if (file_id_.is_valid()) { if (file_id_.is_valid()) {
VLOG(file_references) << "Receive " << status << " for " << file_id_;
td->file_manager_->delete_file_reference(file_id_, file_reference_); td->file_manager_->delete_file_reference(file_id_, file_reference_);
td->contacts_manager_->upload_profile_photo(file_id_, std::move(promise_)); td->contacts_manager_->upload_profile_photo(file_id_, std::move(promise_));
return; return;
@ -6840,7 +6841,7 @@ void ContactsManager::add_user_photo_id(User *u, UserId user_id, int64 photo_id,
file_source_id = it->second; file_source_id = it->second;
user_profile_photo_file_source_ids_.erase(it); user_profile_photo_file_source_ids_.erase(it);
} else { } else {
VLOG(file_references) << "Need to create new file source for " << photo_id << " of " << user_id; VLOG(file_references) << "Need to create new file source for photo " << photo_id << " of " << user_id;
file_source_id = td_->file_reference_manager_->create_user_photo_file_source(user_id, photo_id); file_source_id = td_->file_reference_manager_->create_user_photo_file_source(user_id, photo_id);
} }
for (auto &file_id : photo_file_ids) { for (auto &file_id : photo_file_ids) {

View File

@ -27,6 +27,17 @@ bool FileReferenceManager::is_file_reference_error(const Status &error) {
return error.is_error() && error.code() == 400 && begins_with(error.message(), "FILE_REFERENCE_"); return error.is_error() && error.code() == 400 && begins_with(error.message(), "FILE_REFERENCE_");
} }
size_t FileReferenceManager::get_file_reference_error_pos(const Status &error) {
if (!is_file_reference_error(error)) {
return 0;
}
auto offset = Slice("FILE_REFERENCE_").size();
if (error.message().size() <= offset || !is_digit(error.message()[offset])) {
return 0;
}
return to_integer<size_t>(error.message().substr(offset)) + 1;
}
/* /*
fileSourceMessage chat_id:int53 message_id:int53 = FileSource; // repaired with get_messages_from_server fileSourceMessage chat_id:int53 message_id:int53 = FileSource; // repaired with get_messages_from_server
fileSourceUserProfilePhoto user_id:int32 photo_id:int64 = FileSource; // repaired with photos.getUserPhotos fileSourceUserProfilePhoto user_id:int32 photo_id:int64 = FileSource; // repaired with photos.getUserPhotos

View File

@ -33,6 +33,7 @@ extern int VERBOSITY_NAME(file_references);
class FileReferenceManager : public Actor { class FileReferenceManager : public Actor {
public: public:
static bool is_file_reference_error(const Status &error); static bool is_file_reference_error(const Status &error);
static size_t get_file_reference_error_pos(const Status &error);
FileSourceId create_message_file_source(FullMessageId full_message_id); FileSourceId create_message_file_source(FullMessageId full_message_id);
FileSourceId create_user_photo_file_source(UserId user_id, int64 photo_id); FileSourceId create_user_photo_file_source(UserId user_id, int64 photo_id);

View File

@ -627,6 +627,7 @@ class EditDialogPhotoQuery : public Td::ResultHandler {
} }
if (FileReferenceManager::is_file_reference_error(status)) { if (FileReferenceManager::is_file_reference_error(status)) {
if (file_id_.is_valid() && !was_uploaded_) { 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_); td->file_manager_->delete_file_reference(file_id_, file_reference_);
td->messages_manager_->upload_dialog_photo(dialog_id_, file_id_, std::move(promise_)); td->messages_manager_->upload_dialog_photo(dialog_id_, file_id_, std::move(promise_));
return; return;
@ -1871,16 +1872,22 @@ class SendInlineBotResultQuery : public Td::ResultHandler {
}; };
class SendMultiMediaActor : public NetActorOnce { class SendMultiMediaActor : public NetActorOnce {
vector<FileId> file_ids_;
vector<string> file_references_;
vector<int64> random_ids_; vector<int64> random_ids_;
DialogId dialog_id_; DialogId dialog_id_;
public: public:
void send(int32 flags, DialogId dialog_id, MessageId reply_to_message_id, void send(int32 flags, DialogId dialog_id, MessageId reply_to_message_id, vector<FileId> &&file_ids,
vector<tl_object_ptr<telegram_api::inputSingleMedia>> &&input_single_media, uint64 sequence_dispatcher_id) { vector<tl_object_ptr<telegram_api::inputSingleMedia>> &&input_single_media, uint64 sequence_dispatcher_id) {
for (auto &single_media : input_single_media) { for (auto &single_media : input_single_media) {
random_ids_.push_back(single_media->random_id_); random_ids_.push_back(single_media->random_id_);
CHECK(FileManager::extract_was_uploaded(single_media->media_) == false);
file_references_.push_back(FileManager::extract_file_reference(single_media->media_));
} }
dialog_id_ = dialog_id; dialog_id_ = dialog_id;
file_ids_ = std::move(file_ids);
CHECK(file_ids_.size() == random_ids_.size());
auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Write); auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
if (input_peer == nullptr) { if (input_peer == nullptr) {
@ -1958,6 +1965,18 @@ class SendMultiMediaActor : public NetActorOnce {
// do not send error, message will be re-sent // do not send error, message will be re-sent
return; 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->messages_manager_->on_send_media_group_file_reference_error(dialog_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->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendMultiMediaActor"); td->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendMultiMediaActor");
for (auto &random_id : random_ids_) { for (auto &random_id : random_ids_) {
td->messages_manager_->on_send_message_fail(random_id, status.clone()); td->messages_manager_->on_send_message_fail(random_id, status.clone());
@ -2042,7 +2061,6 @@ class SendMediaActor : public NetActorOnce {
// do not send error, message will be re-sent // do not send error, message will be re-sent
return; return;
} }
td->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendMediaActor");
if (was_uploaded_) { if (was_uploaded_) {
if (was_thumbnail_uploaded_) { if (was_thumbnail_uploaded_) {
CHECK(thumbnail_file_id_.is_valid()); CHECK(thumbnail_file_id_.is_valid());
@ -2062,6 +2080,7 @@ class SendMediaActor : public NetActorOnce {
} }
} else if (FileReferenceManager::is_file_reference_error(status)) { } else if (FileReferenceManager::is_file_reference_error(status)) {
if (file_id_.is_valid() && !was_uploaded_) { 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_); td->file_manager_->delete_file_reference(file_id_, file_reference_);
td->messages_manager_->on_send_message_file_reference_error(random_id_); td->messages_manager_->on_send_message_file_reference_error(random_id_);
return; return;
@ -2071,6 +2090,7 @@ class SendMediaActor : public NetActorOnce {
} }
} }
td->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendMediaActor");
td->messages_manager_->on_send_message_fail(random_id_, std::move(status)); td->messages_manager_->on_send_message_fail(random_id_, std::move(status));
} }
}; };
@ -15658,6 +15678,7 @@ void MessagesManager::do_send_message_group(int64 media_album_id) {
auto default_status = can_send_message(dialog_id); auto default_status = can_send_message(dialog_id);
bool success = default_status.is_ok(); bool success = default_status.is_ok();
vector<FileId> file_ids;
vector<int64> random_ids; vector<int64> random_ids;
vector<tl_object_ptr<telegram_api::inputSingleMedia>> input_single_media; vector<tl_object_ptr<telegram_api::inputSingleMedia>> input_single_media;
MessageId reply_to_message_id; MessageId reply_to_message_id;
@ -15673,9 +15694,11 @@ void MessagesManager::do_send_message_group(int64 media_album_id) {
reply_to_message_id = m->reply_to_message_id; reply_to_message_id = m->reply_to_message_id;
flags = get_message_flags(m); flags = get_message_flags(m);
file_ids.push_back(get_message_content_file_id(m->content.get()));
random_ids.push_back(begin_send_message(dialog_id, m)); random_ids.push_back(begin_send_message(dialog_id, m));
const FormattedText *caption = get_message_content_caption(m->content.get()); const FormattedText *caption = get_message_content_caption(m->content.get());
auto input_media = get_input_media(m->content.get(), td_, m->ttl); auto input_media = get_input_media(m->content.get(), td_, m->ttl);
CHECK(input_media != nullptr);
auto entities = get_input_message_entities(td_->contacts_manager_.get(), caption, "do_send_message_group"); auto entities = get_input_message_entities(td_->contacts_manager_.get(), caption, "do_send_message_group");
int32 input_single_media_flags = 0; int32 input_single_media_flags = 0;
if (!entities.empty()) { if (!entities.empty()) {
@ -15713,7 +15736,7 @@ void MessagesManager::do_send_message_group(int64 media_album_id) {
LOG(INFO) << "Media group " << media_album_id << " from " << dialog_id << " is empty"; LOG(INFO) << "Media group " << media_album_id << " from " << dialog_id << " is empty";
} }
send_closure(td_->create_net_actor<SendMultiMediaActor>(), &SendMultiMediaActor::send, flags, dialog_id, send_closure(td_->create_net_actor<SendMultiMediaActor>(), &SendMultiMediaActor::send, flags, dialog_id,
reply_to_message_id, std::move(input_single_media), reply_to_message_id, std::move(file_ids), std::move(input_single_media),
get_sequence_dispatcher_id(dialog_id, MessageContentType::Photo)); get_sequence_dispatcher_id(dialog_id, MessageContentType::Photo));
} }
@ -16377,6 +16400,7 @@ void MessagesManager::on_message_media_edited(DialogId dialog_id, MessageId mess
} }
} else if (FileReferenceManager::is_file_reference_error(result.error())) { } else if (FileReferenceManager::is_file_reference_error(result.error())) {
if (file_id.is_valid()) { if (file_id.is_valid()) {
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});
return; return;
@ -19016,6 +19040,65 @@ void MessagesManager::on_send_message_file_reference_error(int64 random_id) {
do_send_message(dialog_id, m, {-1}); do_send_message(dialog_id, m, {-1});
} }
void MessagesManager::on_send_media_group_file_reference_error(DialogId dialog_id, vector<int64> random_ids) {
int64 media_album_id = 0;
vector<MessageId> message_ids;
vector<Message *> messages;
for (auto &random_id : random_ids) {
auto it = being_sent_messages_.find(random_id);
if (it == being_sent_messages_.end()) {
// we can't receive fail more than once
// but message can be successfully sent before
LOG(ERROR) << "Receive file reference invalid error about successfully sent message with random_id = "
<< random_id;
continue;
}
auto full_message_id = it->second;
being_sent_messages_.erase(it);
Message *m = get_message(full_message_id);
if (m == nullptr) {
// message has already been deleted by the user or sent to inaccessible channel
// don't need to send error to the user, because the message has already been deleted
// and there is nothing to be deleted from the server
LOG(INFO) << "Fail to send already deleted by the user or sent to inaccessible chat " << full_message_id;
continue;
}
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;
CHECK(dialog_id == full_message_id.get_dialog_id());
message_ids.push_back(full_message_id.get_message_id());
messages.push_back(m);
}
CHECK(dialog_id.get_type() != DialogType::SecretChat);
if (message_ids.empty()) {
// all messages was deleted, nothing to do
return;
}
auto &request = pending_message_group_sends_[media_album_id];
CHECK(!request.dialog_id.is_valid());
CHECK(request.finished_count == 0);
CHECK(request.results.empty());
request.dialog_id = dialog_id;
request.message_ids = std::move(message_ids);
request.is_finished.resize(request.message_ids.size(), false);
for (size_t i = 0; i < request.message_ids.size(); i++) {
request.results.push_back(Status::OK());
}
for (auto m : messages) {
do_send_message(dialog_id, m, {-1});
}
}
void MessagesManager::on_send_message_fail(int64 random_id, Status error) { void MessagesManager::on_send_message_fail(int64 random_id, Status error) {
CHECK(error.is_error()); CHECK(error.is_error());

View File

@ -641,6 +641,8 @@ class MessagesManager : public Actor {
void on_send_message_file_reference_error(int64 random_id); void on_send_message_file_reference_error(int64 random_id);
void on_send_media_group_file_reference_error(DialogId dialog_id, vector<int64> random_ids);
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,

View File

@ -201,6 +201,7 @@ class GetAttachedStickerSetsQuery : public Td::ResultHandler {
void on_error(uint64 id, Status status) override { void on_error(uint64 id, Status status) override {
if (FileReferenceManager::is_file_reference_error(status)) { if (FileReferenceManager::is_file_reference_error(status)) {
VLOG(file_references) << "Receive " << status << " for " << file_id_;
td->file_manager_->delete_file_reference(file_id_, file_reference_); td->file_manager_->delete_file_reference(file_id_, file_reference_);
td->file_reference_manager_->repair_file_reference( td->file_reference_manager_->repair_file_reference(
file_id_, file_id_,
@ -300,6 +301,7 @@ class SaveRecentStickerQuery : public Td::ResultHandler {
void on_error(uint64 id, Status status) override { void on_error(uint64 id, Status status) override {
if (FileReferenceManager::is_file_reference_error(status)) { if (FileReferenceManager::is_file_reference_error(status)) {
VLOG(file_references) << "Receive " << status << " for " << file_id_;
td->file_manager_->delete_file_reference(file_id_, file_reference_); td->file_manager_->delete_file_reference(file_id_, file_reference_);
td->file_reference_manager_->repair_file_reference( td->file_reference_manager_->repair_file_reference(
file_id_, PromiseCreator::lambda([sticker_id = file_id_, is_attached = is_attached_, unsave = unsave_, file_id_, PromiseCreator::lambda([sticker_id = file_id_, is_attached = is_attached_, unsave = unsave_,
@ -427,6 +429,7 @@ class FaveStickerQuery : public Td::ResultHandler {
void on_error(uint64 id, Status status) override { void on_error(uint64 id, Status status) override {
if (FileReferenceManager::is_file_reference_error(status)) { if (FileReferenceManager::is_file_reference_error(status)) {
VLOG(file_references) << "Receive " << status << " for " << file_id_;
td->file_manager_->delete_file_reference(file_id_, file_reference_); td->file_manager_->delete_file_reference(file_id_, file_reference_);
td->file_reference_manager_->repair_file_reference( td->file_reference_manager_->repair_file_reference(
file_id_, PromiseCreator::lambda([sticker_id = file_id_, unsave = unsave_, file_id_, PromiseCreator::lambda([sticker_id = file_id_, unsave = unsave_,

View File

@ -536,7 +536,7 @@ class CliClient final : public Actor {
} }
static tl_object_ptr<td_api::InputFile> as_input_file(string str) { static tl_object_ptr<td_api::InputFile> as_input_file(string str) {
if ((str.size() >= 20 && is_base64(str)) || begins_with(str, "http")) { if ((str.size() >= 20 && is_base64url(str)) || begins_with(str, "http")) {
return as_remote_file(str); return as_remote_file(str);
} }
auto r_id = to_integer_safe<int32>(trim(str)); auto r_id = to_integer_safe<int32>(trim(str));
@ -867,7 +867,7 @@ class CliClient final : public Actor {
static tl_object_ptr<td_api::formattedText> as_formatted_text( static tl_object_ptr<td_api::formattedText> as_formatted_text(
string text, vector<td_api::object_ptr<td_api::textEntity>> entities = {}) { string text, vector<td_api::object_ptr<td_api::textEntity>> entities = {}) {
if (entities.empty()) { if (entities.empty() && !text.empty()) {
auto parsed_text = auto parsed_text =
execute(make_tl_object<td_api::parseTextEntities>(text, make_tl_object<td_api::textParseModeMarkdown>())); execute(make_tl_object<td_api::parseTextEntities>(text, make_tl_object<td_api::textParseModeMarkdown>()));
if (parsed_text->get_id() == td_api::formattedText::ID) { if (parsed_text->get_id() == td_api::formattedText::ID) {
@ -2632,7 +2632,7 @@ class CliClient final : public Actor {
as_chat_id(chat_id), as_message_id(reply_to_message_id), false, false, as_chat_id(chat_id), as_message_id(reply_to_message_id), false, false,
transform(photos, [](const string &photo_path) { transform(photos, [](const string &photo_path) {
tl_object_ptr<td_api::InputMessageContent> content = make_tl_object<td_api::inputMessagePhoto>( tl_object_ptr<td_api::InputMessageContent> content = make_tl_object<td_api::inputMessagePhoto>(
as_local_file(photo_path), nullptr, Auto(), 0, 0, as_caption(""), 0); as_input_file(photo_path), nullptr, Auto(), 0, 0, as_caption(""), 0);
return content; return content;
}))); })));
} else if (op == "em") { } else if (op == "em") {

View File

@ -274,6 +274,7 @@ Status FileDownloader::check_net_query(NetQueryPtr &net_query) {
if (net_query->is_error()) { if (net_query->is_error()) {
auto error = net_query->move_as_error(); auto error = net_query->move_as_error();
if (FileReferenceManager::is_file_reference_error(error)) { if (FileReferenceManager::is_file_reference_error(error)) {
VLOG(file_references) << "Receive " << error << " for downloaded file";
error = Status::Error(error.code(), PSLICE() << error.message() << "#BASE64" error = Status::Error(error.code(), PSLICE() << error.message() << "#BASE64"
<< base64_encode(remote_.get_download_file_reference())); << base64_encode(remote_.get_download_file_reference()));
} }