diff options
author | 2025-04-08 10:38:18 +0100 | |
---|---|---|
committer | 2025-04-08 10:38:18 +0100 | |
commit | 5b644e2dc8712d56931b410b9c46dae1ef36e691 (patch) | |
tree | 2290b3ab2a5829c3b8406ce073a95474e146a680 /filamento/src/lib.rs | |
parent | c24541b129a14a598afe00ed4244d49d27513310 (diff) | |
download | luz-5b644e2dc8712d56931b410b9c46dae1ef36e691.tar.gz luz-5b644e2dc8712d56931b410b9c46dae1ef36e691.tar.bz2 luz-5b644e2dc8712d56931b410b9c46dae1ef36e691.zip |
feat(filamento): user avatar publishing and processing
Diffstat (limited to '')
-rw-r--r-- | filamento/src/lib.rs | 154 |
1 files changed, 120 insertions, 34 deletions
diff --git a/filamento/src/lib.rs b/filamento/src/lib.rs index c44edca..42646be 100644 --- a/filamento/src/lib.rs +++ b/filamento/src/lib.rs @@ -11,9 +11,10 @@ use chrono::Utc; use db::Db; use disco::{Info, Items}; use error::{ - ConnectionJobError, DatabaseError, DiscoError, Error, IqError, MessageRecvError, NickError, - PresenceError, PublishError, RosterError, StatusError, SubscribeError, + AvatarPublishError, ConnectionJobError, DatabaseError, DiscoError, Error, IqError, + MessageRecvError, NickError, PEPError, PresenceError, RosterError, StatusError, SubscribeError, }; +use files::FileStore; use futures::FutureExt; use jid::JID; use lampada::{ @@ -35,18 +36,20 @@ use tracing::{debug, info}; use user::User; use uuid::Uuid; +pub mod avatar; pub mod caps; pub mod chat; pub mod db; pub mod disco; pub mod error; +pub mod files; mod logic; pub mod pep; pub mod presence; pub mod roster; pub mod user; -pub enum Command { +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 all chats. chat will include 10 messages in their message Vec (enough for chat previews) @@ -115,16 +118,34 @@ pub enum Command { Option<String>, oneshot::Sender<Result<disco::Items, DiscoError>>, ), - /// publish item to a pep node, specified or default according to item. - Publish { + /// publish item to a pep node specified. + PublishPEPItem { item: pep::Item, node: String, - sender: oneshot::Sender<Result<(), PublishError>>, + sender: oneshot::Sender<Result<(), PEPError>>, }, - /// change user nickname - ChangeNick(String, oneshot::Sender<Result<(), NickError>>), + DeletePEPNode { + node: String, + sender: oneshot::Sender<Result<(), PEPError>>, + }, + GetPEPItem { + jid: Option<JID>, + node: String, + id: String, + sender: oneshot::Sender<Result<pep::Item, PEPError>>, + }, + /// change client user nickname + ChangeNick(Option<String>, oneshot::Sender<Result<(), NickError>>), + // // TODO + // GetNick(...), + // GetAvatar(...) // /// get capability node // GetCaps(String, oneshot::Sender<Result<Info, CapsError>>), + /// change client user avatar + ChangeAvatar( + Option<Vec<u8>>, + oneshot::Sender<Result<(), AvatarPublishError<Fs>>>, + ), } #[derive(Debug, Clone)] @@ -155,18 +176,22 @@ pub enum UpdateMessage { SubscriptionRequest(jid::JID), NickChanged { jid: JID, - nick: String, + nick: Option<String>, + }, + AvatarChanged { + jid: JID, + id: Option<String>, }, } /// an xmpp client that is suited for a chat client use case #[derive(Debug)] -pub struct Client { - sender: mpsc::Sender<CoreClientCommand<Command>>, +pub struct Client<Fs: FileStore> { + sender: mpsc::Sender<CoreClientCommand<Command<Fs>>>, timeout: Duration, } -impl Clone for Client { +impl<Fs: FileStore> Clone for Client<Fs> { fn clone(&self) -> Self { Self { sender: self.sender.clone(), @@ -175,32 +200,27 @@ impl Clone for Client { } } -impl Deref for Client { - type Target = mpsc::Sender<CoreClientCommand<Command>>; +impl<Fs: FileStore> Deref for Client<Fs> { + type Target = mpsc::Sender<CoreClientCommand<Command<Fs>>>; fn deref(&self) -> &Self::Target { &self.sender } } -impl DerefMut for Client { +impl<Fs: FileStore> DerefMut for Client<Fs> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.sender } } -impl Client { - pub async fn connect(&self) -> Result<(), ActorError> { - self.send(CoreClientCommand::Connect).await?; - Ok(()) - } - - pub async fn disconnect(&self, offline: Offline) -> Result<(), ActorError> { - self.send(CoreClientCommand::Disconnect).await?; - Ok(()) - } - - pub fn new(jid: JID, password: String, db: Db) -> (Self, mpsc::Receiver<UpdateMessage>) { +impl<Fs: FileStore + Clone + Send + Sync + 'static> Client<Fs> { + pub fn new( + jid: JID, + password: String, + db: Db, + file_store: Fs, + ) -> (Self, mpsc::Receiver<UpdateMessage>) { let (command_sender, command_receiver) = mpsc::channel(20); let (update_send, update_recv) = mpsc::channel(20); @@ -214,14 +234,26 @@ impl Client { timeout: Duration::from_secs(10), }; - let logic = ClientLogic::new(client.clone(), jid.as_bare(), db, update_send); + let logic = ClientLogic::new(client.clone(), jid.as_bare(), db, update_send, file_store); - let actor: CoreClient<ClientLogic> = + let actor: CoreClient<ClientLogic<Fs>> = CoreClient::new(jid, password, command_receiver, None, sup_recv, logic); tokio::spawn(async move { actor.run().await }); (client, update_recv) } +} + +impl<Fs: FileStore> Client<Fs> { + pub async fn connect(&self) -> Result<(), ActorError> { + self.send(CoreClientCommand::Connect).await?; + Ok(()) + } + + pub async fn disconnect(&self, offline: Offline) -> Result<(), ActorError> { + self.send(CoreClientCommand::Disconnect).await?; + Ok(()) + } pub async fn get_roster(&self) -> Result<Vec<Contact>, CommandError<RosterError>> { let (send, recv) = oneshot::channel(); @@ -539,9 +571,9 @@ impl Client { &self, item: pep::Item, node: String, - ) -> Result<(), CommandError<PublishError>> { + ) -> Result<(), CommandError<PEPError>> { let (send, recv) = oneshot::channel(); - self.send(CoreClientCommand::Command(Command::Publish { + self.send(CoreClientCommand::Command(Command::PublishPEPItem { item, node, sender: send, @@ -555,7 +587,44 @@ impl Client { Ok(result) } - pub async fn change_nick(&self, nick: String) -> Result<(), CommandError<NickError>> { + pub async fn delete_pep_node(&self, node: String) -> Result<(), CommandError<PEPError>> { + let (send, recv) = oneshot::channel(); + self.send(CoreClientCommand::Command(Command::DeletePEPNode { + node, + sender: send, + })) + .await + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?; + let result = timeout(self.timeout, recv) + .await + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))? + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??; + Ok(result) + } + + pub async fn get_pep_item( + &self, + jid: Option<JID>, + node: String, + id: String, + ) -> Result<pep::Item, CommandError<PEPError>> { + let (send, recv) = oneshot::channel(); + self.send(CoreClientCommand::Command(Command::GetPEPItem { + jid, + node, + id, + sender: send, + })) + .await + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?; + let result = timeout(self.timeout, recv) + .await + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))? + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??; + Ok(result) + } + + pub async fn change_nick(&self, nick: Option<String>) -> Result<(), CommandError<NickError>> { let (send, recv) = oneshot::channel(); self.send(CoreClientCommand::Command(Command::ChangeNick(nick, send))) .await @@ -566,10 +635,27 @@ impl Client { .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??; Ok(result) } + + pub async fn change_avatar( + &self, + avatar: Option<Vec<u8>>, + ) -> Result<(), CommandError<AvatarPublishError<Fs>>> { + let (send, recv) = oneshot::channel(); + self.send(CoreClientCommand::Command(Command::ChangeAvatar( + avatar, send, + ))) + .await + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))?; + let result = timeout(self.timeout, recv) + .await + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))? + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??; + Ok(result) + } } -impl From<Command> for CoreClientCommand<Command> { - fn from(value: Command) -> Self { +impl<Fs: FileStore> From<Command<Fs>> for CoreClientCommand<Command<Fs>> { + fn from(value: Command<Fs>) -> Self { CoreClientCommand::Command(value) } } |