//! Test implementation of the TDLib client traits for FakeTdClient. use super::fake_tdclient::FakeTdClient; use async_trait::async_trait; use std::borrow::Cow; use std::path::PathBuf; use tdlib_rs::enums::{ChatAction, Update}; use tele_tui::tdlib::{ AccountClient, AuthClient, ChatActionClient, ChatClient, ClientState, FileClient, MessageClient, ReactionClient, UpdateClient, UserClient, }; use tele_tui::tdlib::{ AuthState, ChatInfo, FolderInfo, MessageInfo, ProfileInfo, ReplyInfo, UserCache, UserOnlineStatus, }; use tele_tui::types::{ChatId, MessageId, UserId}; #[async_trait] impl AuthClient for FakeTdClient { async fn send_phone_number(&self, _phone: String) -> Result<(), String> { Ok(()) } async fn send_code(&self, _code: String) -> Result<(), String> { Ok(()) } async fn send_password(&self, _password: String) -> Result<(), String> { Ok(()) } } #[async_trait] impl ChatClient for FakeTdClient { async fn load_chats(&mut self, limit: i32) -> Result<(), String> { let _ = FakeTdClient::load_chats(self, limit as usize).await?; Ok(()) } async fn load_folder_chats(&mut self, folder_id: i32, limit: i32) -> Result<(), String> { FakeTdClient::load_folder_chats(self, folder_id, limit as usize).await } async fn leave_chat(&self, _chat_id: ChatId) -> Result<(), String> { Ok(()) } async fn get_profile_info(&self, chat_id: ChatId) -> Result { FakeTdClient::get_profile_info(self, chat_id).await } fn chats(&self) -> &[ChatInfo] { &[] } fn folders(&self) -> &[FolderInfo] { &[] } fn main_chat_list_position(&self) -> i32 { 0 } fn set_main_chat_list_position(&mut self, _position: i32) {} fn update_chats(&mut self, updater: F) where F: FnOnce(&mut Vec), { updater(&mut self.chats.lock().unwrap()); } fn update_folders(&mut self, updater: F) where F: FnOnce(&mut Vec), { updater(&mut self.folders.lock().unwrap()); } } #[async_trait] impl ChatActionClient for FakeTdClient { async fn send_chat_action(&self, chat_id: ChatId, action: ChatAction) { FakeTdClient::send_chat_action(self, chat_id, format!("{:?}", action)).await; } fn clear_stale_typing_status(&mut self) -> bool { false } fn typing_status(&self) -> Option<&(UserId, String, std::time::Instant)> { None } fn set_typing_status(&mut self, _status: Option<(UserId, String, std::time::Instant)>) {} } #[async_trait] impl MessageClient for FakeTdClient { async fn get_chat_history( &mut self, chat_id: ChatId, limit: i32, ) -> Result, String> { FakeTdClient::get_chat_history(self, chat_id, limit).await } async fn load_older_messages( &mut self, chat_id: ChatId, from_message_id: MessageId, ) -> Result, String> { FakeTdClient::load_older_messages(self, chat_id, from_message_id).await } async fn get_pinned_messages(&mut self, _chat_id: ChatId) -> Result, String> { Ok(vec![]) } async fn load_current_pinned_message(&mut self, _chat_id: ChatId) {} async fn search_messages( &self, chat_id: ChatId, query: &str, ) -> Result, String> { FakeTdClient::search_messages(self, chat_id, query).await } async fn send_message( &mut self, chat_id: ChatId, text: String, reply_to_message_id: Option, reply_info: Option, ) -> Result { FakeTdClient::send_message(self, chat_id, text, reply_to_message_id, reply_info).await } async fn edit_message( &mut self, chat_id: ChatId, message_id: MessageId, new_text: String, ) -> Result { FakeTdClient::edit_message(self, chat_id, message_id, new_text).await } async fn delete_messages( &mut self, chat_id: ChatId, message_ids: Vec, revoke: bool, ) -> Result<(), String> { FakeTdClient::delete_messages(self, chat_id, message_ids, revoke).await } async fn forward_messages( &mut self, to_chat_id: ChatId, from_chat_id: ChatId, message_ids: Vec, ) -> Result<(), String> { FakeTdClient::forward_messages(self, from_chat_id, to_chat_id, message_ids).await } async fn set_draft_message(&self, chat_id: ChatId, text: String) -> Result<(), String> { FakeTdClient::set_draft_message(self, chat_id, text).await } fn current_chat_messages(&self) -> Cow<'_, [MessageInfo]> { if let Some(chat_id) = *self.current_chat_id.lock().unwrap() { Cow::Owned(self.get_messages(chat_id)) } else { Cow::Owned(Vec::new()) } } fn current_chat_id(&self) -> Option { self.get_current_chat_id().map(ChatId::new) } fn current_pinned_message(&self) -> Option { self.current_pinned_message.lock().unwrap().clone() } fn push_message(&mut self, msg: MessageInfo) { if let Some(chat_id) = *self.current_chat_id.lock().unwrap() { self.messages .lock() .unwrap() .entry(chat_id) .or_default() .push(msg); } } fn clear_current_chat_messages(&mut self) { if let Some(chat_id) = *self.current_chat_id.lock().unwrap() { self.messages.lock().unwrap().remove(&chat_id); } } fn set_current_chat_messages(&mut self, messages: Vec) { if let Some(chat_id) = *self.current_chat_id.lock().unwrap() { self.messages.lock().unwrap().insert(chat_id, messages); } } fn update_current_chat_messages(&mut self, updater: F) where F: FnOnce(&mut Vec), { if let Some(chat_id) = *self.current_chat_id.lock().unwrap() { let mut all_messages = self.messages.lock().unwrap(); updater(all_messages.entry(chat_id).or_default()); } } fn set_current_chat_id(&mut self, chat_id: Option) { *self.current_chat_id.lock().unwrap() = chat_id.map(|id| id.as_i64()); } fn set_current_pinned_message(&mut self, msg: Option) { *self.current_pinned_message.lock().unwrap() = msg; } fn pending_view_messages(&self) -> &[(ChatId, Vec)] { &[] } fn enqueue_pending_view_messages(&mut self, chat_id: ChatId, message_ids: Vec) { self.pending_view_messages .lock() .unwrap() .push((chat_id, message_ids)); } async fn fetch_missing_reply_info(&mut self) {} async fn process_pending_view_messages(&mut self) { let mut pending = self.pending_view_messages.lock().unwrap(); for (chat_id, message_ids) in pending.drain(..) { let ids: Vec = message_ids.iter().map(|id| id.as_i64()).collect(); self.viewed_messages .lock() .unwrap() .push((chat_id.as_i64(), ids)); } } } #[async_trait] impl UserClient for FakeTdClient { fn get_user_status_by_chat_id(&self, _chat_id: ChatId) -> Option<&UserOnlineStatus> { None } fn pending_user_ids(&self) -> &[UserId] { &[] } fn user_cache(&self) -> &UserCache { use std::sync::OnceLock; static EMPTY_CACHE: OnceLock = OnceLock::new(); EMPTY_CACHE.get_or_init(|| UserCache::new(0)) } fn update_user_cache(&mut self, _updater: F) where F: FnOnce(&mut UserCache), { } async fn process_pending_user_ids(&mut self) {} } #[async_trait] impl ReactionClient for FakeTdClient { async fn get_message_available_reactions( &self, chat_id: ChatId, message_id: MessageId, ) -> Result, String> { FakeTdClient::get_message_available_reactions(self, chat_id, message_id).await } async fn toggle_reaction( &self, chat_id: ChatId, message_id: MessageId, reaction: String, ) -> Result<(), String> { FakeTdClient::toggle_reaction(self, chat_id, message_id, reaction).await } } #[async_trait] impl FileClient for FakeTdClient { async fn download_file(&self, file_id: i32) -> Result { FakeTdClient::download_file(self, file_id).await } async fn download_voice_note(&self, file_id: i32) -> Result { Ok(format!("/tmp/fake_voice_{}.ogg", file_id)) } } #[async_trait] impl ClientState for FakeTdClient { fn client_id(&self) -> i32 { 0 } async fn get_me(&self) -> Result { Ok(12345) } fn auth_state(&self) -> &AuthState { use std::sync::OnceLock; static AUTH_STATE_READY: AuthState = AuthState::Ready; static AUTH_STATE_WAIT_PHONE: OnceLock = OnceLock::new(); static AUTH_STATE_WAIT_CODE: OnceLock = OnceLock::new(); static AUTH_STATE_WAIT_PASSWORD: OnceLock = OnceLock::new(); let current = self.auth_state.lock().unwrap(); match *current { AuthState::Ready => &AUTH_STATE_READY, AuthState::WaitPhoneNumber => { AUTH_STATE_WAIT_PHONE.get_or_init(|| AuthState::WaitPhoneNumber) } AuthState::WaitCode => AUTH_STATE_WAIT_CODE.get_or_init(|| AuthState::WaitCode), AuthState::WaitPassword => { AUTH_STATE_WAIT_PASSWORD.get_or_init(|| AuthState::WaitPassword) } _ => &AUTH_STATE_READY, } } fn network_state(&self) -> tele_tui::tdlib::types::NetworkState { FakeTdClient::get_network_state(self) } } #[async_trait] impl AccountClient for FakeTdClient { async fn recreate_client(&mut self, _db_path: PathBuf) -> Result<(), String> { Ok(()) } } impl UpdateClient for FakeTdClient { fn handle_update(&mut self, _update: Update) {} fn drain_incoming_message_events(&mut self) -> Vec { Vec::new() } }