diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 16a8f063..ab7a85a8 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -516,8 +516,9 @@ messageForwardInfo origin:MessageForwardOrigin date:int32 from_chat_id:int53 fro //@description The message is being sent now, but has not yet been delivered to the server messageSendingStatePending = MessageSendingState; -//@description The message failed to be sent -messageSendingStateFailed = MessageSendingState; +//@description The message failed to be sent @error_code An error code; 0 if unknown @error_message Error message +//@can_retry True, if the message can be re-sent @retry_after Time left before the message can be re-sent, in seconds. No update is sent when this field changes +messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool retry_after:double = MessageSendingState; //@description Describes a message @@ -747,8 +748,8 @@ richTextMarked text:RichText = RichText; richTextPhoneNumber text:RichText phone_number:string = RichText; //@description A small image inside the text @document The image represented as a document. The image can be in GIF, JPEG or PNG format -//@width Width of a bounding box in which the image should be shown, 0 if unknown -//@height Height of a bounding box in which the image should be shown, 0 if unknown +//@width Width of a bounding box in which the image should be shown; 0 if unknown +//@height Height of a bounding box in which the image should be shown; 0 if unknown richTextIcon document:document width:int32 height:int32 = RichText; //@description A rich text anchor @text Text @name Anchor name @@ -855,7 +856,7 @@ pageBlockVideo video:video caption:pageBlockCaption need_autoplay:Bool is_looped //@description A page cover @cover Cover pageBlockCover cover:PageBlock = PageBlock; -//@description An embedded web page @url Web page URL, if available @html HTML-markup of the embedded page @poster_photo Poster photo, if available; may be null @width Block width, 0 if unknown @height Block height, 0 if unknown @caption Block caption @is_full_width True, if the block should be full width @allow_scrolling True, if scrolling should be allowed +//@description An embedded web page @url Web page URL, if available @html HTML-markup of the embedded page @poster_photo Poster photo, if available; may be null @width Block width; 0 if unknown @height Block height; 0 if unknown @caption Block caption @is_full_width True, if the block should be full width @allow_scrolling True, if scrolling should be allowed pageBlockEmbedded url:string html:string poster_photo:photo width:int32 height:int32 caption:pageBlockCaption is_full_width:Bool allow_scrolling:Bool = PageBlock; //@description An embedded post @url Web page URL @author Post author @author_photo Post author photo; may be null @date Point in time (Unix timestamp) when the post was created; 0 if unknown @page_blocks Post content @caption Post caption diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 2e794bb6..afe5d07e 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 5572001d..d9cd7ef0 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -4846,11 +4846,6 @@ void update_expired_message_content(unique_ptr &content) { void update_failed_to_send_message_content(Td *td, unique_ptr &content) { // do not forget about failed to send message forwards switch (content->get_type()) { - case MessageContentType::LiveLocation: { - MessageLiveLocation *message_live_location = static_cast(content.get()); - message_live_location->period = 1; - break; - } case MessageContentType::Poll: { const MessagePoll *message_poll = static_cast(content.get()); if (PollManager::is_local_poll_id(message_poll->poll_id)) { diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 927b23bb..d6b0efd9 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -3570,6 +3570,7 @@ void MessagesManager::Message::store(StorerT &storer) const { bool has_flags2 = true; bool has_notification_id = notification_id.is_valid(); bool has_forward_sender_name = is_forwarded && !forward_info->sender_name.empty(); + bool has_send_error_code = send_error_code != 0; BEGIN_STORE_FLAGS(); STORE_FLAG(is_channel_post); STORE_FLAG(is_outgoing); @@ -3608,6 +3609,7 @@ void MessagesManager::Message::store(StorerT &storer) const { STORE_FLAG(is_mention_notification_disabled); STORE_FLAG(had_forward_info); STORE_FLAG(has_forward_sender_name); + STORE_FLAG(has_send_error_code); END_STORE_FLAGS(); } @@ -3655,13 +3657,13 @@ void MessagesManager::Message::store(StorerT &storer) const { } if (has_ttl) { store(ttl, storer); - double server_time = storer.context()->server_time(); - if (ttl_expires_at == 0) { - store(-1.0, storer); - } else { - double ttl_left = max(ttl_expires_at - Time::now_cached(), 0.0); - store(ttl_left, storer); - store(server_time, storer); + store_time(ttl_expires_at, storer); + } + if (has_send_error_code) { + store(send_error_code, storer); + store(send_error_message, storer); + if (send_error_code == 429) { + store_time(try_resend_at, storer); } } if (has_author_signature) { @@ -3701,6 +3703,7 @@ void MessagesManager::Message::parse(ParserT &parser) { bool has_flags2; bool has_notification_id = false; bool has_forward_sender_name = false; + bool has_send_error_code = false; BEGIN_PARSE_FLAGS(); PARSE_FLAG(is_channel_post); PARSE_FLAG(is_outgoing); @@ -3739,6 +3742,7 @@ void MessagesManager::Message::parse(ParserT &parser) { PARSE_FLAG(is_mention_notification_disabled); PARSE_FLAG(had_forward_info); PARSE_FLAG(has_forward_sender_name); + PARSE_FLAG(has_send_error_code); END_PARSE_FLAGS(); } @@ -3791,16 +3795,13 @@ void MessagesManager::Message::parse(ParserT &parser) { } if (has_ttl) { parse(ttl, parser); - double ttl_left; - parse(ttl_left, parser); - if (ttl_left < -0.1) { - ttl_expires_at = 0; - } else { - double old_server_time; - parse(old_server_time, parser); - double passed_server_time = max(parser.context()->server_time() - old_server_time, 0.0); - ttl_left = max(ttl_left - passed_server_time, 0.0); - ttl_expires_at = Time::now_cached() + ttl_left; + parse_time(ttl_expires_at, parser); + } + if (has_send_error_code) { + parse(send_error_code, parser); + parse(send_error_message, parser); + if (send_error_code == 429) { + parse_time(try_resend_at, parser); } } if (has_author_signature) { @@ -5192,7 +5193,8 @@ void MessagesManager::on_update_message_content(FullMessageId full_message_id) { CHECK(d != nullptr); const Message *m = get_message(d, full_message_id.get_message_id()); CHECK(m != nullptr); - send_update_message_content(full_message_id.get_dialog_id(), m->message_id, m->content.get(), m->date, + auto live_location_date = m->is_failed_to_send ? 0 : m->date; + send_update_message_content(full_message_id.get_dialog_id(), m->message_id, m->content.get(), live_location_date, m->is_content_secret, "on_update_message_content"); on_message_changed(d, m, true, "on_update_message_content"); } @@ -14579,6 +14581,10 @@ vector MessagesManager::get_active_live_location_messages(Promise CHECK(m != nullptr); CHECK(m->content->get_type() == MessageContentType::LiveLocation); + if (m->is_failed_to_send) { + continue; + } + auto live_period = get_message_content_live_location_period(m->content.get()); if (live_period <= G()->unix_time() - m->date) { // bool is_expired flag? // live location is expired @@ -14635,7 +14641,7 @@ void MessagesManager::on_load_active_live_location_messages_finished() { void MessagesManager::try_add_active_live_location(DialogId dialog_id, const Message *m) { CHECK(m != nullptr); - if (m->content->get_type() != MessageContentType::LiveLocation) { + if (m->content->get_type() != MessageContentType::LiveLocation || m->is_failed_to_send) { return; } @@ -15531,7 +15537,8 @@ tl_object_ptr MessagesManager::get_message_object(DialogId dial // TODO get_message_sending_state_object tl_object_ptr sending_state; if (m->is_failed_to_send) { - sending_state = make_tl_object(); + sending_state = make_tl_object( + m->send_error_code, m->send_error_message, m->send_error_code == 429, max(m->try_resend_at - Time::now(), 0.0)); } else if (m->message_id.is_yet_unsent()) { sending_state = make_tl_object(); } @@ -15599,13 +15606,14 @@ tl_object_ptr MessagesManager::get_message_object(DialogId dial auto media_album_id = for_event_log ? static_cast(0) : m->media_album_id; auto reply_to_message_id = for_event_log ? static_cast(0) : m->reply_to_message_id.get(); bool contains_unread_mention = for_event_log ? false : m->contains_unread_mention; + auto live_location_date = m->is_failed_to_send ? 0 : m->date; return make_tl_object( m->message_id.get(), td_->contacts_manager_->get_user_id_object(m->sender_user_id, "sender_user_id"), dialog_id.get(), std::move(sending_state), is_outgoing, can_be_edited, can_be_forwarded, can_delete_for_self, can_delete_for_all_users, m->is_channel_post, contains_unread_mention, m->date, m->edit_date, get_message_forward_info_object(m->forward_info), reply_to_message_id, ttl, ttl_expires_in, td_->contacts_manager_->get_user_id_object(m->via_bot_user_id, "via_bot_user_id"), m->author_signature, m->views, - media_album_id, get_message_content_object(m->content.get(), td_, m->date, m->is_content_secret), + media_album_id, get_message_content_object(m->content.get(), td_, live_location_date, m->is_content_secret), get_reply_markup_object(m->reply_markup)); } @@ -20851,7 +20859,16 @@ void MessagesManager::fail_send_message(FullMessageId full_message_id, int error CHECK(message->message_id.is_valid()); message->random_y = get_random_y(message->message_id); message->is_failed_to_send = true; - + message->send_error_code = error_code; + message->send_error_message = error_message; + message->try_resend_at = 0.0; + Slice retry_after_prefix("Too Many Requests: retry after "); + if (error_code == 429 && begins_with(error_message, retry_after_prefix)) { + auto r_retry_after = to_integer_safe(error_message.substr(retry_after_prefix.size())); + if (r_retry_after.is_ok() && r_retry_after.ok() > 0) { + message->try_resend_at = Time::now() + r_retry_after.ok(); + } + } update_failed_to_send_message_content(td_, message->content); message->have_previous = true; diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 1b6a4d26..b4383198 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -868,7 +868,7 @@ class MessagesManager : public Actor { bool is_channel_post = false; bool is_outgoing = false; - bool is_failed_to_send = false; // TODO replace with error_code + bool is_failed_to_send = false; bool disable_notification = false; bool contains_mention = false; bool contains_unread_mention = false; @@ -891,6 +891,10 @@ class MessagesManager : public Actor { int32 views = 0; + int32 send_error_code = 0; + string send_error_message; + double try_resend_at = 0; + int32 ttl = 0; double ttl_expires_at = 0; diff --git a/td/telegram/logevent/LogEventHelper.h b/td/telegram/logevent/LogEventHelper.h index f4ae0e02..4e0adc9e 100644 --- a/td/telegram/logevent/LogEventHelper.h +++ b/td/telegram/logevent/LogEventHelper.h @@ -35,4 +35,31 @@ inline Promise get_erase_logevent_promise_impl(const char *file, int32 lin }); } +template +void store_time(double time_at, StorerT &storer) { + double server_time = storer.context()->server_time(); + if (time_at == 0) { + store(-1.0, storer); + } else { + double time_left = max(time_at - Time::now(), 0.0); + store(time_left, storer); + store(server_time, storer); + } +} + +template +void parse_time(double &time_at, ParserT &parser) { + double time_left; + parse(time_left, parser); + if (time_left < -0.1) { + time_at = 0; + } else { + double old_server_time; + parse(old_server_time, parser); + double passed_server_time = max(parser.context()->server_time() - old_server_time, 0.0); + time_left = max(time_left - passed_server_time, 0.0); + time_at = Time::now_cached() + time_left; + } +} + } // namespace td