diff options
author | 2025-04-11 00:49:36 +0100 | |
---|---|---|
committer | 2025-04-11 00:49:36 +0100 | |
commit | aab4cd47b1d2da5539c50675be4c7a36898189ef (patch) | |
tree | 3338bab6b08a076c8b39e8c3cb06a22f40a66e04 /filamento/src | |
parent | af7a0f5022dfd0e04c821f0d4fc8314b3578417c (diff) | |
download | luz-aab4cd47b1d2da5539c50675be4c7a36898189ef.tar.gz luz-aab4cd47b1d2da5539c50675be4c7a36898189ef.tar.bz2 luz-aab4cd47b1d2da5539c50675be4c7a36898189ef.zip |
feat(filamento): `get_roster_with_users()`
Diffstat (limited to '')
-rw-r--r-- | filamento/src/db.rs | 40 | ||||
-rw-r--r-- | filamento/src/error.rs | 13 | ||||
-rw-r--r-- | filamento/src/lib.rs | 18 | ||||
-rw-r--r-- | filamento/src/logic/offline.rs | 11 | ||||
-rw-r--r-- | filamento/src/logic/online.rs | 18 |
5 files changed, 94 insertions, 6 deletions
diff --git a/filamento/src/db.rs b/filamento/src/db.rs index 1d3d36c..d94293d 100644 --- a/filamento/src/db.rs +++ b/filamento/src/db.rs @@ -361,10 +361,9 @@ impl Db { } pub(crate) async fn read_cached_roster(&self) -> Result<Vec<Contact>, Error> { - let mut roster: Vec<Contact> = - sqlx::query_as("select * from roster join users on jid = user_jid") - .fetch_all(&self.db) - .await?; + let mut roster: Vec<Contact> = sqlx::query_as("select * from roster") + .fetch_all(&self.db) + .await?; for contact in &mut roster { #[derive(sqlx::FromRow)] struct Row { @@ -380,6 +379,39 @@ impl Db { Ok(roster) } + pub(crate) async fn read_cached_roster_with_users( + &self, + ) -> Result<Vec<(Contact, User)>, Error> { + #[derive(sqlx::FromRow)] + struct Row { + #[sqlx(flatten)] + contact: Contact, + #[sqlx(flatten)] + user: User, + } + let mut roster: Vec<Row> = + sqlx::query_as("select * from roster join users on jid = user_jid") + .fetch_all(&self.db) + .await?; + for row in &mut roster { + #[derive(sqlx::FromRow)] + struct Row { + group_name: String, + } + let groups: Vec<Row> = + sqlx::query_as("select group_name from groups_roster where contact_jid = ?") + .bind(&row.contact.user_jid) + .fetch_all(&self.db) + .await?; + row.contact.groups = HashSet::from_iter(groups.into_iter().map(|row| row.group_name)); + } + let roster = roster + .into_iter() + .map(|row| (row.contact, row.user)) + .collect(); + Ok(roster) + } + pub(crate) async fn create_chat(&self, chat: Chat) -> Result<(), Error> { let id = Uuid::new_v4(); let jid = chat.correspondent(); diff --git a/filamento/src/error.rs b/filamento/src/error.rs index 23272b1..76509f6 100644 --- a/filamento/src/error.rs +++ b/filamento/src/error.rs @@ -3,7 +3,7 @@ use std::{num::TryFromIntError, string::FromUtf8Error, sync::Arc}; use base64::DecodeError; use image::ImageError; use jid::JID; -use lampada::error::{ConnectionError, ReadError, WriteError}; +use lampada::error::{ActorError, ConnectionError, ReadError, WriteError}; use stanza::client::{Stanza, iq::Query}; use thiserror::Error; @@ -117,6 +117,17 @@ pub enum RosterError { StanzaError(#[from] stanza::client::error::Error), #[error("could not reply to roster push: {0}")] PushReply(WriteError), + #[error("actor error: {0}")] + Actor(ActorError), +} + +impl From<CommandError<RosterError>> for RosterError { + fn from(value: CommandError<RosterError>) -> Self { + match value { + CommandError::Actor(actor_error) => Self::Actor(actor_error), + CommandError::Error(e) => e, + } + } } #[derive(Debug, Error, Clone)] diff --git a/filamento/src/lib.rs b/filamento/src/lib.rs index 7946241..9fa254e 100644 --- a/filamento/src/lib.rs +++ b/filamento/src/lib.rs @@ -52,6 +52,8 @@ pub mod user; pub enum Command<Fs: FileStore> { /// get the roster. if offline, retreive cached version from database. should be stored in application memory GetRoster(oneshot::Sender<Result<Vec<Contact>, RosterError>>), + /// get the roster. if offline, retreive cached version from database. should be stored in application memory. includes user associated with each contact + GetRosterWithUsers(oneshot::Sender<Result<Vec<(Contact, User)>, RosterError>>), /// get all chats. chat will include 10 messages in their message Vec (enough for chat previews) // TODO: paging and filtering GetChats(oneshot::Sender<Result<Vec<Chat>, DatabaseError>>), @@ -276,6 +278,22 @@ impl<Fs: FileStore> Client<Fs> { Ok(roster) } + pub async fn get_roster_with_users( + &self, + ) -> Result<Vec<(Contact, User)>, CommandError<RosterError>> { + let (send, recv) = oneshot::channel(); + self.send(CoreClientCommand::Command(Command::GetRosterWithUsers( + send, + ))) + .await + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?; + let roster = timeout(self.timeout, recv) + .await + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))? + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??; + Ok(roster) + } + pub async fn get_chats(&self) -> Result<Vec<Chat>, CommandError<DatabaseError>> { let (send, recv) = oneshot::channel(); self.send(CoreClientCommand::Command(Command::GetChats(send))) diff --git a/filamento/src/logic/offline.rs b/filamento/src/logic/offline.rs index 566972c..82b3298 100644 --- a/filamento/src/logic/offline.rs +++ b/filamento/src/logic/offline.rs @@ -14,6 +14,7 @@ use crate::{ files::FileStore, presence::Online, roster::Contact, + user::User, }; use super::{ @@ -47,6 +48,12 @@ pub async fn handle_get_roster<Fs: FileStore + Clone>( 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>, @@ -56,6 +63,10 @@ pub async fn handle_offline_result<Fs: FileStore + Clone>( 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); diff --git a/filamento/src/logic/online.rs b/filamento/src/logic/online.rs index d9441d7..d5242e0 100644 --- a/filamento/src/logic/online.rs +++ b/filamento/src/logic/online.rs @@ -18,7 +18,7 @@ use uuid::Uuid; use crate::{ avatar, chat::{Body, Chat, Delivery, Message}, disco::{Info, Items}, error::{ AvatarPublishError, DatabaseError, DiscoError, Error, IqRequestError, MessageSendError, NickError, PEPError, RosterError, StatusError, SubscribeError - }, files::FileStore, pep, presence::{Online, Presence, PresenceType}, roster::{Contact, ContactUpdate}, Command, UpdateMessage + }, files::FileStore, pep, presence::{Online, Presence, PresenceType}, roster::{Contact, ContactUpdate}, user::User, Command, UpdateMessage }; use super::{ @@ -97,6 +97,18 @@ pub async fn handle_get_roster<Fs: FileStore + Clone>( } } +pub async fn handle_get_roster_with_users<Fs: FileStore + Clone>( + logic: &ClientLogic<Fs>, +) -> Result<Vec<(Contact, User)>, RosterError> { + let roster = logic.client.get_roster().await?; + let mut users = Vec::new(); + for contact in &roster { + let user = logic.db().read_user(contact.user_jid.clone()).await?; + users.push(user); + } + Ok(roster.into_iter().zip(users).collect()) +} + pub async fn handle_add_contact<Fs: FileStore + Clone>( logic: &ClientLogic<Fs>, connection: Connected, @@ -1006,6 +1018,10 @@ pub async fn handle_online_result<Fs: FileStore + Clone>( let roster = handle_get_roster(logic, connection).await; let _ = result_sender.send(roster); } + Command::GetRosterWithUsers(result_sender) => { + let roster = handle_get_roster_with_users(logic).await; + let _ = result_sender.send(roster); + } Command::GetChats(sender) => { let chats = handle_get_chats(logic).await; let _ = sender.send(chats); |