From 5f1d715e8f4797fdcf11ef9f404bd42a49b4bbf0 Mon Sep 17 00:00:00 2001 From: Mikhail Kilin Date: Thu, 5 Feb 2026 12:52:42 +0300 Subject: [PATCH] fix: eliminate infinite recursion in TdClientTrait implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL BUG FIX: Three methods in TdClientTrait impl were calling themselves recursively instead of delegating to actual implementations, causing stack overflow and application panic on startup. Fixed methods: 1. user_cache_mut() - now returns &mut self.user_cache directly 2. sync_notification_muted_chats() - now delegates to notification_manager.sync_muted_chats() 3. handle_update() - now properly delegates to TdClient::handle_update() using qualified path This bug caused the app to hang on "Инициализация TDLib..." screen and exit raw mode, displaying escape sequences ("CB52") on key presses when user tried to interact. Root cause: Introduced in refactoring commit bd5e5be where trait implementations were created but incorrectly delegated to self.method() instead of accessing struct fields directly or using qualified path syntax. Also added panic hook in main.rs to ensure terminal restoration on panic for better debugging experience. Impact: Application completely broken - couldn't start. Stack overflow on first update. Co-Authored-By: Claude Sonnet 4.5 --- src/main.rs | 14 +++++++++++--- src/tdlib/client_impl.rs | 7 ++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 633a16f..86cb4dc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,14 +55,22 @@ async fn main() -> Result<(), io::Error> { let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend)?; + // Ensure terminal restoration on panic + let panic_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |info| { + let _ = disable_raw_mode(); + let _ = execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture); + panic_hook(info); + })); + // Create app state let mut app = App::new(config); - + // Запускаем инициализацию TDLib в фоне (только для реального клиента) let client_id = app.td_client.client_id(); let api_id = app.td_client.api_id; let api_hash = app.td_client.api_hash.clone(); - + tokio::spawn(async move { let _ = tdlib_rs::functions::set_tdlib_parameters( false, // use_test_dc @@ -83,7 +91,7 @@ async fn main() -> Result<(), io::Error> { ) .await; }); - + let res = run_app(&mut terminal, &mut app).await; // Restore terminal diff --git a/src/tdlib/client_impl.rs b/src/tdlib/client_impl.rs index 48557d1..2590206 100644 --- a/src/tdlib/client_impl.rs +++ b/src/tdlib/client_impl.rs @@ -260,16 +260,17 @@ impl TdClientTrait for TdClient { } fn user_cache_mut(&mut self) -> &mut UserCache { - self.user_cache_mut() + &mut self.user_cache } // ============ Notification methods ============ fn sync_notification_muted_chats(&mut self) { - self.sync_notification_muted_chats() + self.notification_manager.sync_muted_chats(&self.chat_manager.chats); } // ============ Update handling ============ fn handle_update(&mut self, update: Update) { - self.handle_update(update) + // Delegate to the real implementation + TdClient::handle_update(self, update) } }