//! TDLib message conversion: JSON → MessageInfo, reply info fetching. use crate::types::{ChatId, MessageId}; use tdlib_rs::functions; use tdlib_rs::types::Message as TdMessage; use crate::tdlib::types::{MessageBuilder, MessageInfo}; use super::MessageManager; impl MessageManager { /// Конвертировать TdMessage в MessageInfo pub(crate) async fn convert_message(&self, msg: &TdMessage) -> Option { use crate::tdlib::message_conversion::{ extract_content_text, extract_entities, extract_forward_info, extract_media_info, extract_reactions, extract_reply_info, extract_sender_name, }; // Извлекаем все части сообщения используя вспомогательные функции let content_text = extract_content_text(msg); let entities = extract_entities(msg); let sender_name = extract_sender_name(msg, self.client_id).await; let forward_from = extract_forward_info(msg); let reply_to = extract_reply_info(msg); let reactions = extract_reactions(msg); let media = extract_media_info(msg); let mut builder = MessageBuilder::new(MessageId::new(msg.id)) .sender_name(sender_name) .text(content_text) .entities(entities) .date(msg.date) .edit_date(msg.edit_date) .media_album_id(msg.media_album_id); if msg.is_outgoing { builder = builder.outgoing(); } else { builder = builder.incoming(); } if !msg.contains_unread_mention { builder = builder.read(); } else { builder = builder.unread(); } if msg.can_be_edited { builder = builder.editable(); } if msg.can_be_deleted_only_for_self { builder = builder.deletable_for_self(); } if msg.can_be_deleted_for_all_users { builder = builder.deletable_for_all(); } if let Some(reply) = reply_to { builder = builder.reply_to(reply); } if let Some(forward) = forward_from { builder = builder.forward_from(forward); } builder = builder.reactions(reactions); if let Some(media) = media { builder = builder.media(media); } Some(builder.build()) } /// Загружает недостающую информацию об исходных сообщениях для ответов. /// /// Ищет все reply-сообщения с `sender_name == "Unknown"` и загружает /// полную информацию (имя отправителя, текст) из TDLib. /// /// # Note /// /// Вызывайте после загрузки истории чата для заполнения информации о цитируемых сообщениях. pub async fn fetch_missing_reply_info(&mut self) { // Early return if no chat selected let Some(chat_id) = self.current_chat_id else { return; }; // Collect message IDs with missing reply info using filter_map let to_fetch: Vec = self .current_chat_messages .iter() .filter_map(|msg| { msg.interactions .reply_to .as_ref() .filter(|reply| reply.sender_name == "Unknown") .map(|reply| reply.message_id) }) .collect(); // Fetch and update each missing message for message_id in to_fetch { self.fetch_and_update_reply(chat_id, message_id).await; } } /// Загружает одно сообщение и обновляет reply информацию. async fn fetch_and_update_reply(&mut self, chat_id: ChatId, message_id: MessageId) { // Try to fetch the original message let Ok(original_msg_enum) = functions::get_message(chat_id.as_i64(), message_id.as_i64(), self.client_id).await else { return; }; let tdlib_rs::enums::Message::Message(original_msg) = original_msg_enum; let Some(orig_info) = self.convert_message(&original_msg).await else { return; }; // Extract text preview (first 50 chars) let text_preview: String = orig_info .content .text .chars() .take(50) .collect(); // Update reply info in all messages that reference this message self.current_chat_messages .iter_mut() .filter_map(|msg| msg.interactions.reply_to.as_mut()) .filter(|reply| reply.message_id == message_id) .for_each(|reply| { reply.sender_name = orig_info.metadata.sender_name.clone(); reply.text = text_preview.clone(); }); } }