aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@bunny.garden>2024-12-04 17:38:36 +0000
committerLibravatar cel 🌸 <cel@bunny.garden>2024-12-04 17:38:36 +0000
commit21f10a0b43c4ab1429b274b386065c023c661ab0 (patch)
tree9e65aae47363f6ba2f1f8c10cb9ed7c35c82e5b2
parent4886396044356d2676a77c3900af796fe7641f42 (diff)
downloadluz-21f10a0b43c4ab1429b274b386065c023c661ab0.tar.gz
luz-21f10a0b43c4ab1429b274b386065c023c661ab0.tar.bz2
luz-21f10a0b43c4ab1429b274b386065c023c661ab0.zip
implement send_stanza
-rw-r--r--README.md10
-rw-r--r--src/client.rs44
-rw-r--r--src/error.rs4
-rw-r--r--src/jabber.rs92
-rw-r--r--src/stanza/stream.rs1
-rw-r--r--src/stanza/stream_error.rs4
6 files changed, 38 insertions, 117 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..195860c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# jabber client library
+
+## TODO:
+
+- [ ] error states for all negotiation parts
+- [ ] better errors
+- [ ] rename structs
+- [ ] remove commented code
+- [ ] asynchronous connect (with take_mut?)
+- [ ] split into separate crates: stanza, jabber, and luz
diff --git a/src/client.rs b/src/client.rs
index 5351b34..e94008d 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -44,6 +44,8 @@ impl JabberClient {
pub async fn connect(&mut self) -> Result<()> {
match &self.connection {
ConnectionState::Disconnected => {
+ // TODO: actually set the self.connection as it is connecting, make more asynchronous (mutex while connecting?)
+ // perhaps use take_mut?
self.connection = ConnectionState::Disconnected
.connect(&mut self.jid, self.password.clone(), &mut self.server)
.await?;
@@ -53,6 +55,16 @@ impl JabberClient {
ConnectionState::Connected(_jabber_stream) => Ok(()),
}
}
+
+ pub async fn send_stanza(&mut self, stanza: &Stanza) -> Result<()> {
+ match &mut self.connection {
+ ConnectionState::Disconnected => return Err(Error::Disconnected),
+ ConnectionState::Connecting(_connecting) => return Err(Error::Connecting),
+ ConnectionState::Connected(jabber_stream) => {
+ Ok(jabber_stream.send_stanza(stanza).await?)
+ }
+ }
+ }
}
impl Stream for JabberClient {
@@ -217,38 +229,6 @@ pub enum InsecureConnecting {
Bound(JabberStream<Tls>),
}
-impl Sink<Stanza> for JabberClient {
- type Error = Error;
-
- fn poll_ready(
- self: std::pin::Pin<&mut Self>,
- cx: &mut std::task::Context<'_>,
- ) -> std::task::Poll<std::result::Result<(), Self::Error>> {
- todo!()
- }
-
- fn start_send(
- self: std::pin::Pin<&mut Self>,
- item: Stanza,
- ) -> std::result::Result<(), Self::Error> {
- todo!()
- }
-
- fn poll_flush(
- self: std::pin::Pin<&mut Self>,
- cx: &mut std::task::Context<'_>,
- ) -> std::task::Poll<std::result::Result<(), Self::Error>> {
- todo!()
- }
-
- fn poll_close(
- self: std::pin::Pin<&mut Self>,
- cx: &mut std::task::Context<'_>,
- ) -> std::task::Poll<std::result::Result<(), Self::Error>> {
- todo!()
- }
-}
-
#[cfg(test)]
mod tests {
use std::time::Duration;
diff --git a/src/error.rs b/src/error.rs
index f117e82..8875ebb 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -3,6 +3,7 @@ use std::str::Utf8Error;
use rsasl::mechname::MechanismNameError;
use crate::stanza::client::error::Error as ClientError;
+use crate::stanza::stream::Error as StreamError;
use crate::{jid::ParseError, stanza::sasl::Failure};
#[derive(Debug)]
@@ -22,7 +23,10 @@ pub enum Error {
JID(ParseError),
Authentication(Failure),
ClientError(ClientError),
+ StreamError(StreamError),
MissingError,
+ Disconnected,
+ Connecting,
}
#[derive(Debug)]
diff --git a/src/jabber.rs b/src/jabber.rs
index 30dc15d..8ee45b5 100644
--- a/src/jabber.rs
+++ b/src/jabber.rs
@@ -50,6 +50,7 @@ where
S: AsyncRead + AsyncWrite + Unpin + Send + std::fmt::Debug,
JabberStream<S>: std::fmt::Debug,
{
+ #[instrument]
pub async fn sasl(mut self, mechanisms: Mechanisms, sasl_config: Arc<SASLConfig>) -> Result<S> {
let sasl = SASLClient::new(sasl_config);
let mut offered_mechs: Vec<&Mechname> = Vec::new();
@@ -139,6 +140,7 @@ where
Ok(stream)
}
+ #[instrument]
pub async fn bind(mut self, jid: &mut JID) -> Result<Self> {
let iq_id = nanoid::nanoid!();
if let Some(resource) = &jid.resourcepart {
@@ -266,6 +268,7 @@ where
Ok(Self { reader, writer })
}
+ #[instrument]
pub async fn get_features(mut self) -> Result<(Features, Self)> {
debug!("getting features");
let features: Features = self.reader.read().await?;
@@ -276,91 +279,16 @@ where
pub fn into_inner(self) -> S {
self.reader.into_inner().unsplit(self.writer.into_inner())
}
-}
-
-impl JabberStream<Unencrypted> {
- // pub async fn negotiate<S: AsyncRead + AsyncWrite + Unpin>(
- // mut self,
- // features: Features,
- // ) -> Result<Feature> {
- // // TODO: timeout
- // if let Some(Feature::StartTls(_)) = features
- // .features
- // .iter()
- // .find(|feature| matches!(feature, Feature::StartTls(_s)))
- // {
- // return Ok(self);
- // } else {
- // // TODO: better error
- // return Err(Error::TlsRequired);
- // }
- // }
- // #[async_recursion]
- // pub async fn negotiate_tls_optional(mut self) -> Result<Connection> {
- // self.start_stream().await?;
- // // TODO: timeout
- // let features = self.get_features().await?.features;
- // if let Some(Feature::StartTls(_)) = features
- // .iter()
- // .find(|feature| matches!(feature, Feature::StartTls(_s)))
- // {
- // let jabber = self.starttls().await?;
- // let jabber = jabber.negotiate().await?;
- // return Ok(Connection::Encrypted(jabber));
- // } else if let (Some(sasl_config), Some(Feature::Sasl(mechanisms))) = (
- // self.auth.clone(),
- // features
- // .iter()
- // .find(|feature| matches!(feature, Feature::Sasl(_))),
- // ) {
- // self.sasl(mechanisms.clone(), sasl_config).await?;
- // let jabber = self.negotiate_tls_optional().await?;
- // Ok(jabber)
- // } else if let Some(Feature::Bind) = features
- // .iter()
- // .find(|feature| matches!(feature, Feature::Bind))
- // {
- // self.bind().await?;
- // Ok(Connection::Unencrypted(self))
- // } else {
- // // TODO: better error
- // return Err(Error::Negotiation);
- // }
- // }
-}
-
-impl JabberStream<Tls> {
- // #[async_recursion]
- // pub async fn negotiate(mut self) -> Result<JabberStream<Tls>> {
- // self.start_stream().await?;
- // let features = self.get_features().await?.features;
-
- // if let (Some(sasl_config), Some(Feature::Sasl(mechanisms))) = (
- // self.auth.clone(),
- // features
- // .iter()
- // .find(|feature| matches!(feature, Feature::Sasl(_))),
- // ) {
- // // TODO: avoid clone
- // self.sasl(mechanisms.clone(), sasl_config).await?;
- // let jabber = self.negotiate().await?;
- // Ok(jabber)
- // } else if let Some(Feature::Bind) = features
- // .iter()
- // .find(|feature| matches!(feature, Feature::Bind))
- // {
- // self.bind().await?;
- // Ok(self)
- // } else {
- // // TODO: better error
- // return Err(Error::Negotiation);
- // }
- // }
+ pub async fn send_stanza(&mut self, stanza: &Stanza) -> Result<()> {
+ self.writer.write(stanza).await?;
+ Ok(())
+ }
}
impl JabberStream<Unencrypted> {
- pub async fn starttls(mut self, domain: impl AsRef<str>) -> Result<Tls> {
+ #[instrument]
+ pub async fn starttls(mut self, domain: impl AsRef<str> + std::fmt::Debug) -> Result<Tls> {
self.writer
.write_full(&StartTls { required: false })
.await?;
@@ -372,8 +300,6 @@ impl JabberStream<Unencrypted> {
.connect(domain.as_ref(), stream)
.await
{
- // let (read, write) = tokio::io::split(tlsstream);
- // let client = JabberStream::new(read, write);
return Ok(tls_stream);
} else {
return Err(Error::Connection);
diff --git a/src/stanza/stream.rs b/src/stanza/stream.rs
index 4f3c435..84d62d9 100644
--- a/src/stanza/stream.rs
+++ b/src/stanza/stream.rs
@@ -164,6 +164,7 @@ impl FromElement for Feature {
}
}
+#[derive(Debug)]
pub struct Error {
error: StreamError,
text: Option<Text>,
diff --git a/src/stanza/stream_error.rs b/src/stanza/stream_error.rs
index 37db8a1..5ae04a6 100644
--- a/src/stanza/stream_error.rs
+++ b/src/stanza/stream_error.rs
@@ -5,7 +5,7 @@ use peanuts::{
pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-streams";
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub enum Error {
BadFormat,
BadNamespacePrefix,
@@ -110,7 +110,7 @@ impl IntoElement for Error {
}
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct Text {
text: Option<String>,
lang: Option<String>,