use chrono::Utc;
use lampada::error::WriteError;
use uuid::Uuid;
use crate::{
Command,
chat::{Delivery, Message},
error::{
DatabaseError, DiscoError, Error, IqRequestError, MessageSendError, NickError, RosterError,
StatusError,
},
presence::Online,
roster::Contact,
};
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_messages, 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<Vec<Contact>, RosterError> {
Ok(logic.db().read_cached_roster().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::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::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::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);
}
// TODO: offline queue to modify roster
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);
}
// TODO: offline message queue
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;
}
logic
.update_sender()
.send(crate::UpdateMessage::Message {
to: jid.as_bare(),
message,
})
.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::Publish {
item: _,
node: _,
sender,
} => {
sender.send(Err(IqRequestError::Write(WriteError::Disconnected).into()));
}
Command::ChangeNick(_, sender) => {
sender.send(Err(NickError::Disconnected));
}
}
Ok(())
}