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>, } 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 { 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 } 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()), } } } }