aboutsummaryrefslogblamecommitdiffstats
path: root/filamento/src/chat.rs
blob: 07577fdb393f1b20590424fd9e6d666ef67fde5a (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                               
                            
                        
               
          
                                         
  

               

                                                                            
                                                                        
                    
                 
                                                                                                                                          
                      
                                   
                                 


                                                                                                                                                                                                                                            
                   

 


























                                                                                                                                                                                                                                                                 

                                                                            









                   













                                                                        





























                                                                                                    





                        

                                                                            
                 
                                               
                     

 

                                                                            
                                                                        
                 
                               
                           


                                                                                                               

                                                                   

 

                      
           
                                                                    



                          
     
                                             

                           

 
                    




                          
use std::fmt::{Display, Write};

use chrono::{DateTime, Utc};
use jid::{BareJID, JID};
use rusqlite::{
    ToSql,
    types::{FromSql, ToSqlOutput, Value},
};
use uuid::Uuid;

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "reactive_stores", derive(reactive_stores::Store))]
pub struct Message {
    pub id: Uuid,
    /// jid of user currently tied to the original sender, updated by jid move event. original sender can be found within the source data.
    pub from: BareJID,
    pub delivery: Option<Delivery>,
    pub timestamp: DateTime<Utc>,
    // TODO: message edits. message edits will need to include the edit and the source stanza that caused the edit.
    /// original message sources (XMPP, imported, etc.). cannot change, but may be deleted or have information redacted. can be multiple because a message may be updated, have reactions appended to it, delivery receipt, user moved, etc.
    pub source: Vec<Source>,
    pub body: Body,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Source {
    XMPP(XMPPMessage),
    // TODO: imported information
    Imported,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct XMPPMessage {
    // TODO: upon software updates, upgrade all message and xmppmessage structs with missed data from old XMPP raw messages. maybe just don't store parsed message in xmpp message, have it be a method
    /// the raw data received from the xml stream
    pub raw: String,
    /// the timestamp the client received the stanza, or associated with the <delay> in the envelope.
    pub timestamp: DateTime<Utc>,
    /// if message was received in a carbon envolope, forwarded, or in an encrypted envelope, etc., the full xmpp message it came from is included here, linked. there could technically be multiple envelopes (same stanza received through multiple envelopes).
    pub envelopes: Vec<XMPPMessage>,
}

impl XMPPMessage {
    // TODO: syncify
    // pub async fn parsed(&self) -> stanza::client::message::Message {
    //     let reader = peanuts::Reader::new(peanuts::ReadableString(self.raw.to_string()));
    //     let message = reader.read().await?;
    //     message
    // }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum Delivery {
    Sending,
    Written,
    Sent,
    Delivered,
    Read,
    Failed,
    Queued,
}

impl Display for Delivery {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Delivery::Sending => f.write_str("sending"),
            Delivery::Written => f.write_str("written"),
            Delivery::Sent => f.write_str("sent"),
            Delivery::Delivered => f.write_str("delivered"),
            Delivery::Read => f.write_str("read"),
            Delivery::Failed => f.write_str("failed"),
            Delivery::Queued => f.write_str("queued"),
        }
    }
}

impl ToSql for Delivery {
    fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
        Ok(match self {
            Delivery::Sending => ToSqlOutput::Owned(Value::Text("sending".to_string())),
            Delivery::Written => ToSqlOutput::Owned(Value::Text("written".to_string())),
            Delivery::Sent => ToSqlOutput::Owned(Value::Text("sent".to_string())),
            Delivery::Delivered => ToSqlOutput::Owned(Value::Text("delivered".to_string())),
            Delivery::Read => ToSqlOutput::Owned(Value::Text("read".to_string())),
            Delivery::Failed => ToSqlOutput::Owned(Value::Text("failed".to_string())),
            Delivery::Queued => ToSqlOutput::Owned(Value::Text("queued".to_string())),
        })
    }
}

impl FromSql for Delivery {
    fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
        Ok(match value.as_str()? {
            "sending" => Self::Sending,
            "written" => Self::Written,
            "sent" => Self::Sent,
            "delivered" => Self::Delivered,
            "read" => Self::Read,
            "failed" => Self::Failed,
            "queued" => Self::Queued,
            // TODO: don't have these lol
            value => panic!("unexpected subscription `{value}`"),
        })
    }
}

// TODO: user migrations
// pub enum Migrated {
//     Jabber(User),
//     Outside,
// }

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Body {
    // TODO: rich text, other contents, threads
    pub body: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "reactive_stores", derive(reactive_stores::Store))]
pub struct Chat {
    pub correspondent: BareJID,
    pub have_chatted: bool,
    // pub unread_messages: i32,
    // pub latest_message: Message,
    // when a new message is received, the chat should be updated, and the new message should be delivered too.
    // message history is not stored in chat, retreived separately.
    // pub message_history: Vec<Message>,
}

pub enum ChatUpdate {}

impl Chat {
    pub fn new(correspondent: BareJID, have_chatted: bool) -> Self {
        Self {
            correspondent,
            have_chatted,
        }
    }
    pub fn correspondent(&self) -> &BareJID {
        &self.correspondent
    }
}

// TODO: group chats
// pub enum Chat {
//     Direct(DirectChat),
//     Channel(Channel),
// }
// pub struct Channel {}