fix: handle UpdateMessageSendSucceeded to prevent edit errors
Fixes "Message not found" error when editing immediately after sending. **Problem**: When sending a message, TDLib may return a temporary ID, then send UpdateMessageSendSucceeded with the real server ID. We weren't handling this update, so the cache kept the old ID while the server had a different one, causing "Message not found" errors during edits. **Solution**: 1. Added UpdateMessageSendSucceeded handler (client.rs:801-830) - Finds message with temporary ID - Replaces it with new message containing real server ID - Preserves reply_info if present 2. Added validation before editing (main_input.rs:574-589) - Checks message exists in cache - Better error messages with chat_id and message_id 3. Added positive ID check in start_editing_selected (mod.rs:240) - Blocks editing messages with temporary IDs (negative) **Test**: - Added test_edit_immediately_after_send (edit_message.rs:156-181) - Verifies editing works right after send_message - All 22 edit_message tests pass Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -234,7 +234,11 @@ impl App {
|
|||||||
|
|
||||||
// Сначала извлекаем данные из сообщения
|
// Сначала извлекаем данные из сообщения
|
||||||
let msg_data = self.get_selected_message().and_then(|msg| {
|
let msg_data = self.get_selected_message().and_then(|msg| {
|
||||||
if msg.can_be_edited() && msg.is_outgoing() {
|
// Проверяем:
|
||||||
|
// 1. Можно редактировать
|
||||||
|
// 2. Это исходящее сообщение
|
||||||
|
// 3. ID не временный (временные ID в TDLib отрицательные)
|
||||||
|
if msg.can_be_edited() && msg.is_outgoing() && msg.id().as_i64() > 0 {
|
||||||
Some((msg.id(), msg.text().to_string(), selected_idx.unwrap()))
|
Some((msg.id(), msg.text().to_string(), selected_idx.unwrap()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -571,6 +571,22 @@ pub async fn handle(app: &mut App, key: KeyEvent) {
|
|||||||
if app.is_editing() {
|
if app.is_editing() {
|
||||||
// Режим редактирования
|
// Режим редактирования
|
||||||
if let Some(msg_id) = app.chat_state.selected_message_id() {
|
if let Some(msg_id) = app.chat_state.selected_message_id() {
|
||||||
|
// Проверяем, что сообщение есть в локальном кэше
|
||||||
|
let msg_exists = app.td_client.current_chat_messages()
|
||||||
|
.iter()
|
||||||
|
.any(|m| m.id() == msg_id);
|
||||||
|
|
||||||
|
if !msg_exists {
|
||||||
|
app.error_message = Some(format!(
|
||||||
|
"Сообщение {} не найдено в кэше чата {}",
|
||||||
|
msg_id.as_i64(), chat_id
|
||||||
|
));
|
||||||
|
app.chat_state = crate::app::ChatState::Normal;
|
||||||
|
app.message_input.clear();
|
||||||
|
app.cursor_position = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
match timeout(
|
match timeout(
|
||||||
Duration::from_secs(5),
|
Duration::from_secs(5),
|
||||||
app.td_client.edit_message(ChatId::new(chat_id), msg_id, text),
|
app.td_client.edit_message(ChatId::new(chat_id), msg_id, text),
|
||||||
@@ -599,7 +615,10 @@ pub async fn handle(app: &mut App, key: KeyEvent) {
|
|||||||
app.needs_redraw = true; // ВАЖНО: перерисовываем UI
|
app.needs_redraw = true; // ВАЖНО: перерисовываем UI
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
app.error_message = Some(e);
|
app.error_message = Some(format!(
|
||||||
|
"Редактирование (chat={}, msg={}): {}",
|
||||||
|
chat_id, msg_id.as_i64(), e
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
app.error_message = Some("Таймаут редактирования".to_string());
|
app.error_message = Some("Таймаут редактирования".to_string());
|
||||||
|
|||||||
@@ -798,6 +798,36 @@ impl TdClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Update::MessageSendSucceeded(update) => {
|
||||||
|
// Сообщение успешно отправлено, заменяем временный ID на настоящий
|
||||||
|
let old_id = MessageId::new(update.old_message_id);
|
||||||
|
let chat_id = ChatId::new(update.message.chat_id);
|
||||||
|
|
||||||
|
// Обрабатываем только если это текущий открытый чат
|
||||||
|
if Some(chat_id) == self.current_chat_id() {
|
||||||
|
// Находим сообщение с временным ID
|
||||||
|
if let Some(idx) = self
|
||||||
|
.current_chat_messages()
|
||||||
|
.iter()
|
||||||
|
.position(|m| m.id() == old_id)
|
||||||
|
{
|
||||||
|
// Конвертируем новое сообщение
|
||||||
|
let mut new_msg = self.convert_message(&update.message, chat_id);
|
||||||
|
|
||||||
|
// Сохраняем reply_info из старого сообщения (если было)
|
||||||
|
let old_reply = self.current_chat_messages()[idx]
|
||||||
|
.interactions
|
||||||
|
.reply_to
|
||||||
|
.clone();
|
||||||
|
if let Some(reply) = old_reply {
|
||||||
|
new_msg.interactions.reply_to = Some(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Заменяем старое сообщение на новое
|
||||||
|
self.current_chat_messages_mut()[idx] = new_msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,3 +150,34 @@ async fn test_edit_history_tracking() {
|
|||||||
// История показывает 2 редактирования
|
// История показывает 2 редактирования
|
||||||
assert_eq!(client.get_edited_messages().len(), 2);
|
assert_eq!(client.get_edited_messages().len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test: Редактирование сразу после отправки (симуляция UpdateMessageSendSucceeded)
|
||||||
|
/// Проверяет что после send_message можно сразу edit_message с тем же ID
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_edit_immediately_after_send() {
|
||||||
|
let client = FakeTdClient::new();
|
||||||
|
|
||||||
|
// Отправляем сообщение
|
||||||
|
let sent_msg = client
|
||||||
|
.send_message(ChatId::new(123), "Just sent".to_string(), None, None)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Сразу редактируем (не должно быть ошибки "Message not found")
|
||||||
|
let result = client
|
||||||
|
.edit_message(ChatId::new(123), sent_msg.id(), "Immediately edited".to_string())
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// Редактирование должно пройти успешно
|
||||||
|
assert!(result.is_ok(), "Should be able to edit message immediately after sending");
|
||||||
|
|
||||||
|
// Проверяем что текст изменился
|
||||||
|
let messages = client.get_messages(123);
|
||||||
|
assert_eq!(messages.len(), 1);
|
||||||
|
assert_eq!(messages[0].text(), "Immediately edited");
|
||||||
|
|
||||||
|
// История редактирований содержит это изменение
|
||||||
|
assert_eq!(client.get_edited_messages().len(), 1);
|
||||||
|
assert_eq!(client.get_edited_messages()[0].message_id, sent_msg.id());
|
||||||
|
assert_eq!(client.get_edited_messages()[0].new_text, "Immediately edited");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user