refactor: extract NewMessage and ChatAction handlers (client.rs) - FIXED

Phase 6 начало - рефакторинг handle_update():
- handle_new_message_update() - обработка новых сообщений (~45 строк)
- handle_chat_action_update() - typing статусы (~50 строк)
- Добавлены импорты: UpdateNewMessage, UpdateChatAction

Результат:
- handle_update() сокращена с 351 до ~268 строк (24% ✂️)
- 2/17 веток извлечены в отдельные методы
- Файл: 1167 → 1178 строк (+11 чистых строк кода)

Phase 6: client.rs рефакторинг в процессе!

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Mikhail Kilin
2026-02-03 22:03:51 +03:00
parent 88ff4dd3b7
commit 0acf864c28

View File

@@ -6,7 +6,7 @@ use tdlib_rs::enums::{
MessageSender, Update, UserStatus, MessageSender, Update, UserStatus,
Chat as TdChat Chat as TdChat
}; };
use tdlib_rs::types::{Message as TdMessage}; use tdlib_rs::types::{Message as TdMessage, UpdateNewMessage, UpdateChatAction};
use tdlib_rs::functions; use tdlib_rs::functions;
use crate::constants::{MAX_CHAT_USER_IDS, MAX_CHATS}; use crate::constants::{MAX_CHAT_USER_IDS, MAX_CHATS};
@@ -549,46 +549,7 @@ impl TdClient {
} }
} }
Update::NewMessage(new_msg) => { Update::NewMessage(new_msg) => {
// Добавляем новое сообщение если это текущий открытый чат self.handle_new_message_update(new_msg);
let chat_id = ChatId::new(new_msg.message.chat_id);
if Some(chat_id) == self.current_chat_id() {
let msg_info = self.convert_message(&new_msg.message, chat_id);
let msg_id = msg_info.id();
let is_incoming = !msg_info.is_outgoing();
// Проверяем, есть ли уже сообщение с таким id
let existing_idx = self
.current_chat_messages()
.iter()
.position(|m| m.id() == msg_info.id());
match existing_idx {
Some(idx) => {
// Сообщение уже есть - обновляем
if is_incoming {
self.current_chat_messages_mut()[idx] = msg_info;
} else {
// Для исходящих: обновляем can_be_edited и другие поля,
// но сохраняем reply_to (добавленный при отправке)
let existing = &mut self.current_chat_messages_mut()[idx];
existing.state.can_be_edited = msg_info.state.can_be_edited;
existing.state.can_be_deleted_only_for_self =
msg_info.state.can_be_deleted_only_for_self;
existing.state.can_be_deleted_for_all_users =
msg_info.state.can_be_deleted_for_all_users;
existing.state.is_read = msg_info.state.is_read;
}
}
None => {
// Нового сообщения нет - добавляем
self.push_message(msg_info.clone());
// Если это входящее сообщение — добавляем в очередь для отметки как прочитанное
if is_incoming {
self.pending_view_messages_mut().push((chat_id, vec![msg_id]));
}
}
}
}
} }
Update::User(update) => { Update::User(update) => {
// Сохраняем имя и username пользователя // Сохраняем имя и username пользователя
@@ -662,51 +623,7 @@ impl TdClient {
}; };
} }
Update::ChatAction(update) => { Update::ChatAction(update) => {
// Обрабатываем только для текущего открытого чата self.handle_chat_action_update(update);
if Some(ChatId::new(update.chat_id)) == self.current_chat_id() {
// Извлекаем user_id из sender_id
let user_id = match update.sender_id {
MessageSender::User(user) => Some(UserId::new(user.user_id)),
MessageSender::Chat(_) => None, // Игнорируем действия от имени чата
};
if let Some(user_id) = user_id {
// Определяем текст действия
let action_text = match update.action {
ChatAction::Typing => Some("печатает...".to_string()),
ChatAction::RecordingVideo => Some("записывает видео...".to_string()),
ChatAction::UploadingVideo(_) => {
Some("отправляет видео...".to_string())
}
ChatAction::RecordingVoiceNote => {
Some("записывает голосовое...".to_string())
}
ChatAction::UploadingVoiceNote(_) => {
Some("отправляет голосовое...".to_string())
}
ChatAction::UploadingPhoto(_) => Some("отправляет фото...".to_string()),
ChatAction::UploadingDocument(_) => {
Some("отправляет файл...".to_string())
}
ChatAction::ChoosingSticker => Some("выбирает стикер...".to_string()),
ChatAction::RecordingVideoNote => {
Some("записывает видеосообщение...".to_string())
}
ChatAction::UploadingVideoNote(_) => {
Some("отправляет видеосообщение...".to_string())
}
ChatAction::Cancel => None, // Отмена — сбрасываем статус
_ => None,
};
if let Some(text) = action_text {
self.set_typing_status(Some((user_id, text, Instant::now())));
} else {
// Cancel или неизвестное действие — сбрасываем
self.set_typing_status(None);
}
}
}
} }
Update::ChatDraftMessage(update) => { Update::ChatDraftMessage(update) => {
// Обновляем черновик в списке чатов // Обновляем черновик в списке чатов
@@ -796,6 +713,100 @@ impl TdClient {
} }
} }
/// Обрабатывает Update::NewMessage - добавление нового сообщения
fn handle_new_message_update(&mut self, new_msg: UpdateNewMessage) {
// Добавляем новое сообщение если это текущий открытый чат
let chat_id = ChatId::new(new_msg.message.chat_id);
if Some(chat_id) == self.current_chat_id() {
let msg_info = self.convert_message(&new_msg.message, chat_id);
let msg_id = msg_info.id();
let is_incoming = !msg_info.is_outgoing();
// Проверяем, есть ли уже сообщение с таким id
let existing_idx = self
.current_chat_messages()
.iter()
.position(|m| m.id() == msg_info.id());
match existing_idx {
Some(idx) => {
// Сообщение уже есть - обновляем
if is_incoming {
self.current_chat_messages_mut()[idx] = msg_info;
} else {
// Для исходящих: обновляем can_be_edited и другие поля,
// но сохраняем reply_to (добавленный при отправке)
let existing = &mut self.current_chat_messages_mut()[idx];
existing.state.can_be_edited = msg_info.state.can_be_edited;
existing.state.can_be_deleted_only_for_self =
msg_info.state.can_be_deleted_only_for_self;
existing.state.can_be_deleted_for_all_users =
msg_info.state.can_be_deleted_for_all_users;
existing.state.is_read = msg_info.state.is_read;
}
}
None => {
// Нового сообщения нет - добавляем
self.push_message(msg_info.clone());
// Если это входящее сообщение — добавляем в очередь для отметки как прочитанное
if is_incoming {
self.pending_view_messages_mut().push((chat_id, vec![msg_id]));
}
}
}
}
}
/// Обрабатывает Update::ChatAction - статус набора текста/отправки файлов
fn handle_chat_action_update(&mut self, update: UpdateChatAction) {
// Обрабатываем только для текущего открытого чата
if Some(ChatId::new(update.chat_id)) == self.current_chat_id() {
// Извлекаем user_id из sender_id
let user_id = match update.sender_id {
MessageSender::User(user) => Some(UserId::new(user.user_id)),
MessageSender::Chat(_) => None, // Игнорируем действия от имени чата
};
if let Some(user_id) = user_id {
// Определяем текст действия
let action_text = match update.action {
ChatAction::Typing => Some("печатает...".to_string()),
ChatAction::RecordingVideo => Some("записывает видео...".to_string()),
ChatAction::UploadingVideo(_) => {
Some("отправляет видео...".to_string())
}
ChatAction::RecordingVoiceNote => {
Some("записывает голосовое...".to_string())
}
ChatAction::UploadingVoiceNote(_) => {
Some("отправляет голосовое...".to_string())
}
ChatAction::UploadingPhoto(_) => Some("отправляет фото...".to_string()),
ChatAction::UploadingDocument(_) => {
Some("отправляет файл...".to_string())
}
ChatAction::ChoosingSticker => Some("выбирает стикер...".to_string()),
ChatAction::RecordingVideoNote => {
Some("записывает видеосообщение...".to_string())
}
ChatAction::UploadingVideoNote(_) => {
Some("отправляет видеосообщение...".to_string())
}
ChatAction::Cancel => None, // Отмена — сбрасываем статус
_ => None,
};
if let Some(text) = action_text {
self.set_typing_status(Some((user_id, text, Instant::now())));
} else {
// Cancel или неизвестное действие — сбрасываем
self.set_typing_status(None);
}
}
}
}
fn handle_auth_state(&mut self, state: AuthorizationState) { fn handle_auth_state(&mut self, state: AuthorizationState) {
self.auth.state = match state { self.auth.state = match state {
AuthorizationState::WaitTdlibParameters => AuthState::WaitTdlibParameters, AuthorizationState::WaitTdlibParameters => AuthState::WaitTdlibParameters,