aboutsummaryrefslogblamecommitdiffstats
path: root/filamento/src/logic/offline.rs
blob: b87484c493d66d09487ffdfd69f7ac77ff80e3c8 (plain) (tree)
1
2
3
4
5
6
7
8
9

                     
                
                               
                   
               


            

                              

                                                                                               
      
                     

                     
               

  




                                                                                      

                                                                                     

      
 
                                                                                                  






                                                              



                                                      



                                                   


                                                      


                                              





                                                                 



                                                          

                                       

                                                        
         



                                                                   
                                      
                                                      


                                             
                                                              


                                                               
                                                                                   

                               



                                                                                             
                                          
                                                          


                                              
                                                                 

                                  



                                                                            
                                             
                                                              


                                                 
                                                                   


                                          
                                                         

                              



                                                                           
                                                              

                                                       
                                                              

                                                      
                                                              

                                                             
                                                              
















                                                                           
                                                                

                                




























                                                                                                                                                          








                                                                                 



                     




                                                     
                         

                       



                                                           



                                                                          

                                                                          
                                 








                                                                                     

















                                                                       
     
          
 
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<Fs: FileStore + Clone>(logic: ClientLogic<Fs>, command: Command<Fs>) {
    let result = handle_offline_result(&logic, command).await;
    match result {
        Ok(_) => {}
        Err(e) => logic.handle_error(e).await,
    }
}

pub async fn handle_set_status<Fs: FileStore + Clone>(
    logic: &ClientLogic<Fs>,
    online: Online,
) -> Result<(), StatusError> {
    logic.db().upsert_cached_status(online).await?;
    Ok(())
}

pub async fn handle_get_roster<Fs: FileStore + Clone>(
    logic: &ClientLogic<Fs>,
) -> Result<Vec<Contact>, RosterError> {
    Ok(logic.db().read_cached_roster().await?)
}

pub async fn handle_get_roster_with_users<Fs: FileStore + Clone>(
    logic: &ClientLogic<Fs>,
) -> Result<Vec<(Contact, User)>, RosterError> {
    Ok(logic.db().read_cached_roster_with_users().await?)
}

pub async fn handle_offline_result<Fs: FileStore + Clone>(
    logic: &ClientLogic<Fs>,
    command: Command<Fs>,
) -> Result<(), Error<Fs>> {
    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(())
}