diff options
| author | 2025-04-11 00:49:36 +0100 | |
|---|---|---|
| committer | 2025-04-11 00:49:36 +0100 | |
| commit | aab4cd47b1d2da5539c50675be4c7a36898189ef (patch) | |
| tree | 3338bab6b08a076c8b39e8c3cb06a22f40a66e04 /filamento | |
| 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); | 
