use std::process::id; use chrono::Utc; use lampada::error::WriteError; use tracing::error; use uuid::Uuid; use crate::{ Command, chat::{Delivery, Message}, error::{ AvatarPublishError, DatabaseError, DiscoError, Error, IqRequestError, MessageSendError, NickError, PEPError, RosterError, StatusError, }, files::FileStore, presence::Online, roster::Contact, user::User, }; use super::{ ClientLogic, local_only::{ handle_delete_chat, handle_delete_messaage, handle_get_chat, handle_get_chats, handle_get_chats_ordered, handle_get_chats_ordered_with_latest_messages, handle_get_chats_ordered_with_latest_messages_and_users, handle_get_messages, handle_get_messages_with_users, handle_get_user, }, }; pub async fn handle_offline(logic: ClientLogic, command: Command) { let result = handle_offline_result(&logic, command).await; match result { Ok(_) => {} Err(e) => logic.handle_error(e).await, } } pub async fn handle_set_status( logic: &ClientLogic, online: Online, ) -> Result<(), StatusError> { logic.db().upsert_cached_status(online).await?; Ok(()) } pub async fn handle_get_roster( logic: &ClientLogic, ) -> Result, RosterError> { Ok(logic.db().read_cached_roster().await?) } pub async fn handle_get_roster_with_users( logic: &ClientLogic, ) -> Result, RosterError> { Ok(logic.db().read_cached_roster_with_users().await?) } pub async fn handle_offline_result( logic: &ClientLogic, command: Command, ) -> Result<(), Error> { match command { Command::GetRoster(sender) => { let roster = handle_get_roster(logic).await; sender.send(roster); } Command::GetRosterWithUsers(sender) => { let roster = handle_get_roster_with_users(logic).await; sender.send(roster); } Command::GetChats(sender) => { let chats = handle_get_chats(logic).await; sender.send(chats); } Command::GetChatsOrdered(sender) => { let chats = handle_get_chats_ordered(logic).await; sender.send(chats); } Command::GetChatsOrderedWithLatestMessages(sender) => { let chats = handle_get_chats_ordered_with_latest_messages(logic).await; sender.send(chats); } Command::GetChatsOrderedWithLatestMessagesAndUsers(sender) => { let chats = handle_get_chats_ordered_with_latest_messages_and_users(logic).await; sender.send(chats); } Command::GetChat(jid, sender) => { let chats = handle_get_chat(logic, jid).await; sender.send(chats); } Command::GetMessages(jid, sender) => { let messages = handle_get_messages(logic, jid).await; sender.send(messages); } Command::GetMessagesWithUsers(jid, sender) => { let messages = handle_get_messages_with_users(logic, jid).await; sender.send(messages); } Command::DeleteChat(jid, sender) => { let result = handle_delete_chat(logic, jid).await; sender.send(result); } Command::DeleteMessage(uuid, sender) => { let result = handle_delete_messaage(logic, uuid).await; sender.send(result); } Command::GetUser(jid, sender) => { let user = handle_get_user(logic, jid).await; sender.send(user); } Command::AddContact(_jid, sender) => { sender.send(Err(RosterError::Write(WriteError::Disconnected))); } Command::BuddyRequest(_jid, sender) => { sender.send(Err(WriteError::Disconnected.into())); } Command::SubscriptionRequest(_jid, sender) => { sender.send(Err(WriteError::Disconnected.into())); } Command::AcceptBuddyRequest(_jid, sender) => { sender.send(Err(WriteError::Disconnected.into())); } Command::AcceptSubscriptionRequest(_jid, sender) => { sender.send(Err(WriteError::Disconnected.into())); } Command::UnsubscribeFromContact(_jid, sender) => { sender.send(Err(WriteError::Disconnected)); } Command::UnsubscribeContact(_jid, sender) => { sender.send(Err(WriteError::Disconnected)); } Command::UnfriendContact(_jid, sender) => { sender.send(Err(WriteError::Disconnected)); } Command::DeleteContact(_jid, sender) => { sender.send(Err(RosterError::Write(WriteError::Disconnected))); } Command::UpdateContact(_jid, _contact_update, sender) => { sender.send(Err(RosterError::Write(WriteError::Disconnected))); } Command::SetStatus(online, sender) => { let result = handle_set_status(logic, online).await; sender.send(result); } Command::SendMessage(jid, body) => { let id = Uuid::new_v4(); let timestamp = Utc::now(); let message = Message { id, from: logic.bare_jid.clone(), // TODO: failure reason delivery: Some(Delivery::Failed), timestamp, body, }; // try to store in message history that there is a new message that is sending. if client is quit mid-send then can mark as failed and re-send // TODO: mark these as potentially failed upon client launch if let Err(e) = logic .db() .create_message_with_self_resource( message.clone(), jid.clone(), // TODO: when message is queued and sent, the from must also be updated with the correct resource logic.bare_jid.clone(), ) .await { // TODO: should these really be handle_error or just the error macro? logic .handle_error(MessageSendError::MessageHistory(e.into()).into()) .await; } let from = match logic.db().read_user(logic.bare_jid.clone()).await { Ok(u) => u, Err(e) => { error!("{}", e); User { jid: logic.bare_jid.clone(), nick: None, avatar: None, } } }; logic .update_sender() .send(crate::UpdateMessage::Message { to: jid.as_bare(), message, from, }) .await; } Command::SendPresence(_jid, _presence, sender) => { sender.send(Err(WriteError::Disconnected)); } Command::DiscoInfo(_jid, _node, sender) => { sender.send(Err(DiscoError::Write(WriteError::Disconnected))); } Command::DiscoItems(_jid, _node, sender) => { sender.send(Err(DiscoError::Write(WriteError::Disconnected))); } Command::PublishPEPItem { item: _, node: _, sender, } => { sender.send(Err(IqRequestError::Write(WriteError::Disconnected).into())); } Command::ChangeNick(_, sender) => { sender.send(Err(NickError::Disconnected)); } Command::ChangeAvatar(_items, sender) => { sender.send(Err(AvatarPublishError::Disconnected)); } Command::DeletePEPNode { node: _, sender } => { sender.send(Err(PEPError::IqResponse(IqRequestError::Write( WriteError::Disconnected, )))); } Command::GetPEPItem { node: _, sender, jid: _, id: _, } => { sender.send(Err(PEPError::IqResponse(IqRequestError::Write( WriteError::Disconnected, )))); } } Ok(()) }