summaryrefslogblamecommitdiffstats
path: root/src/user_presences.rs
blob: e864dbf0384539f348c702931fce7a0eaf974414 (plain) (tree)












































                                                                                    
                                          










                                                          












                                                                          
         












                                                                          
         












                                                                          
         












                                                                          
         












                                                                          
         












                                                                             






                                                                                  
                                                                





                                                   
                                      













                                                                       
use std::collections::HashMap;

use chrono::Utc;
use filamento::presence::{Offline, Presence, PresenceType, Show};
use indexmap::IndexMap;
use jid::BareJID;
use leptos::prelude::*;
use reactive_stores::Store;

#[derive(Store)]
pub struct UserPresences {
    #[store(key: BareJID = |(jid, _)| jid.clone())]
    pub user_presences: HashMap<BareJID, ArcRwSignal<Presences>>,
}

impl UserPresences {
    pub fn clear(&mut self) {
        for (_user, presences) in &mut self.user_presences {
            presences.set(Presences::new())
        }
    }

    // TODO: should be a bare jid
    pub fn get_user_presences(&mut self, user: &BareJID) -> ArcRwSignal<Presences> {
        if let Some(presences) = self.user_presences.get(user) {
            presences.clone()
        } else {
            let presences = Presences::new();
            let signal = ArcRwSignal::new(presences);
            self.user_presences.insert(user.clone(), signal.clone());
            signal
        }
    }
}

impl UserPresences {
    pub fn new() -> Self {
        Self {
            user_presences: HashMap::new(),
        }
    }
}

pub struct Presences {
    /// presences are sorted by time, first by type, then by last activity.
    presences: IndexMap<String, Presence>,
}

impl Presences {
    pub fn new() -> Self {
        Self {
            presences: IndexMap::new(),
        }
    }

    /// gets the highest priority presence
    pub fn presence(&self) -> Option<(String, Presence)> {
        if let Some((resource, presence)) = self
            .presences
            .iter()
            .filter(|(_resource, presence)| {
                if let PresenceType::Online(online) = &presence.presence {
                    online.show == Some(Show::DoNotDisturb)
                } else {
                    false
                }
            })
            .next()
        {
            return Some((resource.clone(), presence.clone()));
        }
        if let Some((resource, presence)) = self
            .presences
            .iter()
            .filter(|(_resource, presence)| {
                if let PresenceType::Online(online) = &presence.presence {
                    online.show == Some(Show::Chat)
                } else {
                    false
                }
            })
            .next()
        {
            return Some((resource.clone(), presence.clone()));
        }
        if let Some((resource, presence)) = self
            .presences
            .iter()
            .filter(|(_resource, presence)| {
                if let PresenceType::Online(online) = &presence.presence {
                    online.show == None
                } else {
                    false
                }
            })
            .next()
        {
            return Some((resource.clone(), presence.clone()));
        }
        if let Some((resource, presence)) = self
            .presences
            .iter()
            .filter(|(_resource, presence)| {
                if let PresenceType::Online(online) = &presence.presence {
                    online.show == Some(Show::Away)
                } else {
                    false
                }
            })
            .next()
        {
            return Some((resource.clone(), presence.clone()));
        }
        if let Some((resource, presence)) = self
            .presences
            .iter()
            .filter(|(_resource, presence)| {
                if let PresenceType::Online(online) = &presence.presence {
                    online.show == Some(Show::ExtendedAway)
                } else {
                    false
                }
            })
            .next()
        {
            return Some((resource.clone(), presence.clone()));
        }
        if let Some((resource, presence)) = self
            .presences
            .iter()
            .filter(|(_resource, presence)| {
                if let PresenceType::Offline(_offline) = &presence.presence {
                    true
                } else {
                    false
                }
            })
            .next()
        {
            return Some((resource.clone(), presence.clone()));
        } else {
            None
        }
    }

    pub fn update_presence(&mut self, resource: String, presence: Presence) {
        let index = match self.presences.binary_search_by(|_, existing_presence| {
            presence.timestamp.cmp(&existing_presence.timestamp)
        }) {
            Ok(i) => i,
            Err(i) => i,
        };
        self.presences.insert_before(
            // TODO: check if this logic is correct
            index, resource, presence,
        );
    }

    pub fn resource_presence(&mut self, resource: String) -> Presence {
        if let Some(presence) = self.presences.get(&resource) {
            presence.clone()
        } else {
            Presence {
                timestamp: Utc::now(),
                presence: PresenceType::Offline(Offline::default()),
            }
        }
    }
}