diff options
author | 2025-03-28 22:56:24 +0000 | |
---|---|---|
committer | 2025-03-28 22:56:24 +0000 | |
commit | 6d59d6690c3e5afd936f067b32e9998bc834728c (patch) | |
tree | 75c9024854cb2717e2db9fdb8cedec2c5181f493 | |
parent | ba5ad94525940e3e34983425961550c67afc49ae (diff) | |
download | luz-6d59d6690c3e5afd936f067b32e9998bc834728c.tar.gz luz-6d59d6690c3e5afd936f067b32e9998bc834728c.tar.bz2 luz-6d59d6690c3e5afd936f067b32e9998bc834728c.zip |
feat(filamento): disco items requests
-rw-r--r-- | filamento/examples/example.rs | 5 | ||||
-rw-r--r-- | filamento/src/disco.rs | 2 | ||||
-rw-r--r-- | filamento/src/lib.rs | 41 | ||||
-rw-r--r-- | filamento/src/logic/offline.rs | 5 | ||||
-rw-r--r-- | filamento/src/logic/online.rs | 85 |
5 files changed, 123 insertions, 15 deletions
diff --git a/filamento/examples/example.rs b/filamento/examples/example.rs index 10267bc..506d698 100644 --- a/filamento/examples/example.rs +++ b/filamento/examples/example.rs @@ -33,7 +33,8 @@ async fn main() { .unwrap(); info!("sent message"); info!("sending disco query"); - let info = client.disco_info(None).await.unwrap(); - tokio::time::sleep(Duration::from_secs(5)).await; + let info = client.disco_info(None, None).await.unwrap(); info!("got disco result: {:#?}", info); + let items = client.disco_items(None, None).await.unwrap(); + info!("got disco result: {:#?}", items); } diff --git a/filamento/src/disco.rs b/filamento/src/disco.rs index ccc99cb..cc48215 100644 --- a/filamento/src/disco.rs +++ b/filamento/src/disco.rs @@ -53,6 +53,7 @@ impl From<Info> for info::Query { } } +#[derive(Debug, Clone)] pub struct Items { node: Option<String>, items: Vec<Item>, @@ -80,6 +81,7 @@ impl From<Items> for items::Query { } } +#[derive(Debug, Clone)] pub struct Item { jid: JID, name: Option<String>, diff --git a/filamento/src/lib.rs b/filamento/src/lib.rs index ed33e99..4d852e2 100644 --- a/filamento/src/lib.rs +++ b/filamento/src/lib.rs @@ -9,7 +9,7 @@ use std::{ use chat::{Body, Chat, Message}; use chrono::Utc; use db::Db; -use disco::Info; +use disco::{Info, Items}; use error::{ ConnectionJobError, DatabaseError, DiscoError, Error, IqError, MessageRecvError, PresenceError, RosterError, StatusError, @@ -102,10 +102,15 @@ pub enum Command { /// disco info query DiscoInfo( Option<JID>, + Option<String>, oneshot::Sender<Result<disco::Info, DiscoError>>, ), - // /// disco items query - // DiscoItems(JID, oneshot::Sender<Result<disco::Info, DiscoError>>), + /// disco items query + DiscoItems( + Option<JID>, + Option<String>, + oneshot::Sender<Result<disco::Items, DiscoError>>, + ), } #[derive(Debug, Clone)] @@ -480,11 +485,35 @@ impl Client { Ok(result) } - pub async fn disco_info(&self, jid: Option<JID>) -> Result<Info, CommandError<DiscoError>> { + pub async fn disco_info( + &self, + jid: Option<JID>, + node: Option<String>, + ) -> Result<Info, CommandError<DiscoError>> { let (send, recv) = oneshot::channel(); - self.send(CoreClientCommand::Command(Command::DiscoInfo(jid, send))) + self.send(CoreClientCommand::Command(Command::DiscoInfo( + jid, node, 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)))? + .map_err(|e| CommandError::Actor(Into::<ActorError>::into(e)))??; + Ok(result) + } + + pub async fn disco_items( + &self, + jid: Option<JID>, + node: Option<String>, + ) -> Result<Items, CommandError<DiscoError>> { + let (send, recv) = oneshot::channel(); + self.send(CoreClientCommand::Command(Command::DiscoItems( + jid, node, 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)))? diff --git a/filamento/src/logic/offline.rs b/filamento/src/logic/offline.rs index 7dfb394..bc2666a 100644 --- a/filamento/src/logic/offline.rs +++ b/filamento/src/logic/offline.rs @@ -113,7 +113,10 @@ pub async fn handle_offline_result(logic: &ClientLogic, command: Command) -> Res Command::SendPresence(_jid, _presence, sender) => { sender.send(Err(WriteError::Disconnected)); } - Command::DiscoInfo(_jid, sender) => { + Command::DiscoInfo(_jid, _node, sender) => { + sender.send(Err(DiscoError::Write(WriteError::Disconnected))); + } + Command::DiscoItems(_jid, _node, sender) => { sender.send(Err(DiscoError::Write(WriteError::Disconnected))); } } diff --git a/filamento/src/logic/online.rs b/filamento/src/logic/online.rs index c76907b..63a4aa3 100644 --- a/filamento/src/logic/online.rs +++ b/filamento/src/logic/online.rs @@ -6,7 +6,7 @@ use stanza::{ Stanza, iq::{self, Iq, IqType, Query}, }, - xep_0030::info, + xep_0030::{info, items}, xep_0203::Delay, }; use tokio::sync::oneshot; @@ -16,7 +16,7 @@ use uuid::Uuid; use crate::{ Command, UpdateMessage, chat::{Body, Message}, - disco::Info, + disco::{Info, Items}, error::{DatabaseError, DiscoError, Error, MessageSendError, RosterError, StatusError}, presence::{Online, Presence, PresenceType}, roster::{Contact, ContactUpdate}, @@ -534,11 +534,11 @@ pub async fn handle_send_presence( Ok(()) } -// TODO: cache disco infos pub async fn handle_disco_info( logic: &ClientLogic, connection: Connected, jid: Option<JID>, + node: Option<String>, ) -> Result<Info, DiscoError> { let id = Uuid::new_v4().to_string(); let request = Iq { @@ -548,7 +548,7 @@ pub async fn handle_disco_info( r#type: IqType::Get, lang: None, query: Some(Query::DiscoInfo(info::Query { - node: None, + node, features: Vec::new(), identities: Vec::new(), })), @@ -604,6 +604,75 @@ pub async fn handle_disco_info( } } +pub async fn handle_disco_items( + logic: &ClientLogic, + connection: Connected, + jid: Option<JID>, + node: Option<String>, +) -> Result<Items, DiscoError> { + let id = Uuid::new_v4().to_string(); + let request = Iq { + from: Some(connection.jid().clone()), + id: id.clone(), + to: jid.clone(), + r#type: IqType::Get, + lang: None, + query: Some(Query::DiscoItems(items::Query { + node, + items: Vec::new(), + })), + errors: Vec::new(), + }; + match logic + .pending() + .request(&connection, Stanza::Iq(request), id) + .await? + { + Stanza::Iq(Iq { + from, + r#type, + query, + mut errors, + .. + // TODO: maybe abstract a bunch of these different errors related to iqs into an iq error thing? as in like call iq.result(), get the query from inside, error otherwise. + }) if r#type == IqType::Result || r#type == IqType::Error => { + if from == jid || { + if jid == None { + from == Some(connection.jid().as_bare()) + } else { + false + } + } { + match r#type { + IqType::Result => { + if let Some(query) = query { + match query { + Query::DiscoItems(items) => Ok(items.into()), + q => Err(DiscoError::MismatchedQuery(q)), + } + } else { + Err(DiscoError::MissingQuery) + } + } + IqType::Error => { + if let Some(error) = errors.pop() { + Err(error.into()) + } else { + Err(DiscoError::MissingError) + } + } + _ => unreachable!(), + } + } else { + Err(DiscoError::IncorrectEntity( + from.unwrap_or_else(|| connection.jid().as_bare()), + )) + } + } + s => Err(DiscoError::UnexpectedStanza(s)), + } +} + // TODO: could probably macro-ise? pub async fn handle_online_result( logic: &ClientLogic, @@ -701,8 +770,12 @@ pub async fn handle_online_result( let result = handle_send_presence(connection, jid, presence).await; let _ = sender.send(result); } - Command::DiscoInfo(jid, sender) => { - let result = handle_disco_info(logic, connection, jid).await; + Command::DiscoInfo(jid, node, sender) => { + let result = handle_disco_info(logic, connection, jid, node).await; + let _ = sender.send(result); + } + Command::DiscoItems(jid, node, sender) => { + let result = handle_disco_items(logic, connection, jid, node).await; let _ = sender.send(result); } } |