Replace tokio_xmpp::stream_features with parsers

xmppftw created

Change summary

tokio-xmpp/ChangeLog                   |  1 
tokio-xmpp/src/client/async_client.rs  |  3 -
tokio-xmpp/src/client/auth.rs          |  8 ++++
tokio-xmpp/src/client/simple_client.rs |  3 -
tokio-xmpp/src/lib.rs                  |  1 
tokio-xmpp/src/stream_features.rs      | 41 ----------------------------
tokio-xmpp/src/stream_start.rs         | 23 ++++++--------
tokio-xmpp/src/xmpp_stream.rs          |  7 ++--
8 files changed, 23 insertions(+), 64 deletions(-)

Detailed changes

tokio-xmpp/ChangeLog 🔗

@@ -2,6 +2,7 @@ Version NEXT:
 XXXX-YY-ZZ RELEASER <admin@example.com>
     * Breaking:
       - Remove `tokio_xmpp::ParseError` and `tokio_xmpp::starttls::ParseError` which were never used
+      - Removed StreamFeatures from this crate, replaced with xmpp_parsers::stream_features::StreamFeatures (!400)
 
 Version 4.0.0:
 2024-07-26 Maxime “pep” Buquet <pep@bouah.net>

tokio-xmpp/src/client/async_client.rs 🔗

@@ -4,12 +4,11 @@ use std::mem::replace;
 use std::pin::Pin;
 use std::task::Context;
 use tokio::task::JoinHandle;
-use xmpp_parsers::{jid::Jid, ns};
+use xmpp_parsers::{jid::Jid, ns, stream_features::StreamFeatures};
 
 use super::connect::client_login;
 use crate::connect::{AsyncReadAndWrite, ServerConnector};
 use crate::event::Event;
-use crate::stream_features::StreamFeatures;
 use crate::xmpp_codec::Packet;
 use crate::xmpp_stream::{add_stanza_id, XMPPStream};
 use crate::{Error, ProtocolError};

tokio-xmpp/src/client/auth.rs 🔗

@@ -23,7 +23,13 @@ pub async fn auth<S: AsyncRead + AsyncWrite + Unpin>(
         Box::new(|| Box::new(Anonymous::new())),
     ];
 
-    let remote_mechs: HashSet<String> = stream.stream_features.sasl_mechanisms()?.collect();
+    let remote_mechs: HashSet<String> = stream
+        .stream_features
+        .sasl_mechanisms
+        .mechanisms
+        .iter()
+        .map(|item| item.mechanism.clone())
+        .collect();
 
     for local_mech in local_mechs {
         let mut mechanism = local_mech();

tokio-xmpp/src/client/simple_client.rs 🔗

@@ -3,10 +3,9 @@ use minidom::Element;
 use std::pin::Pin;
 use std::task::{Context, Poll};
 use tokio_stream::StreamExt;
-use xmpp_parsers::{jid::Jid, ns};
+use xmpp_parsers::{jid::Jid, ns, stream_features::StreamFeatures};
 
 use crate::connect::ServerConnector;
-use crate::stream_features::StreamFeatures;
 use crate::xmpp_codec::Packet;
 use crate::xmpp_stream::{add_stanza_id, XMPPStream};
 use crate::Error;

tokio-xmpp/src/lib.rs 🔗

@@ -30,7 +30,6 @@ mod event;
 pub use event::Event;
 mod client;
 pub mod connect;
-pub mod stream_features;
 pub mod xmpp_stream;
 
 pub use client::{

tokio-xmpp/src/stream_features.rs 🔗

@@ -1,41 +0,0 @@
-//! Contains wrapper for `<stream:features/>`
-
-use crate::error::AuthError;
-use minidom::Element;
-use xmpp_parsers::ns;
-
-/// Wraps `<stream:features/>`, usually the very first nonza of an
-/// XMPPStream.
-///
-/// TODO: should this rather go into xmpp-parsers, kept in a decoded
-/// struct?
-#[derive(Debug)]
-pub struct StreamFeatures(pub Element);
-
-impl StreamFeatures {
-    /// Wrap the nonza
-    pub fn new(element: Element) -> Self {
-        StreamFeatures(element)
-    }
-
-    /// Can initiate TLS session with this server?
-    pub fn can_starttls(&self) -> bool {
-        self.0.get_child("starttls", ns::TLS).is_some()
-    }
-
-    /// Iterate over SASL mechanisms
-    pub fn sasl_mechanisms<'a>(&'a self) -> Result<impl Iterator<Item = String> + 'a, AuthError> {
-        Ok(self
-            .0
-            .get_child("mechanisms", ns::SASL)
-            .ok_or(AuthError::NoMechanism)?
-            .children()
-            .filter(|child| child.is("mechanism", ns::SASL))
-            .map(|mech_el| mech_el.text()))
-    }
-
-    /// Does server support user resource binding?
-    pub fn can_bind(&self) -> bool {
-        self.0.get_child("bind", ns::BIND).is_some()
-    }
-}

tokio-xmpp/src/stream_start.rs 🔗

@@ -1,8 +1,7 @@
 use futures::{sink::SinkExt, stream::StreamExt};
-use minidom::Element;
 use tokio::io::{AsyncRead, AsyncWrite};
 use tokio_util::codec::Framed;
-use xmpp_parsers::{jid::Jid, ns};
+use xmpp_parsers::{jid::Jid, ns, stream_features::StreamFeatures};
 
 use crate::xmpp_codec::{Packet, XmppCodec};
 use crate::xmpp_stream::XMPPStream;
@@ -47,29 +46,27 @@ pub async fn start<S: AsyncRead + AsyncWrite + Unpin>(
         .get("id")
         .ok_or(ProtocolError::NoStreamId)?
         .clone();
-    let stream = if stream_ns == "jabber:client" && stream_attrs.get("version").is_some() {
-        let stream_features;
+    if stream_ns == "jabber:client" && stream_attrs.get("version").is_some() {
         loop {
             match stream.next().await {
-                Some(Ok(Packet::Stanza(stanza))) if stanza.is("features", ns::STREAM) => {
-                    stream_features = stanza;
-                    break;
+                Some(Ok(Packet::Stanza(stanza))) => {
+                    if let Ok(stream_features) = StreamFeatures::try_from(stanza) {
+                        return Ok(XMPPStream::new(jid, stream, ns, stream_id, stream_features));
+                    }
                 }
                 Some(Ok(_)) => {}
                 Some(Err(e)) => return Err(e.into()),
                 None => return Err(Error::Disconnected),
             }
         }
-        XMPPStream::new(jid, stream, ns, stream_id, stream_features)
     } else {
         // FIXME: huge hack, shouldn’t be an element!
-        XMPPStream::new(
+        return Ok(XMPPStream::new(
             jid,
             stream,
             ns,
             stream_id.clone(),
-            Element::builder(stream_id, ns::STREAM).build(),
-        )
-    };
-    Ok(stream)
+            StreamFeatures::default(),
+        ));
+    }
 }

tokio-xmpp/src/xmpp_stream.rs 🔗

@@ -8,9 +8,8 @@ use std::pin::Pin;
 use std::task::Context;
 use tokio::io::{AsyncRead, AsyncWrite};
 use tokio_util::codec::Framed;
-use xmpp_parsers::jid::Jid;
+use xmpp_parsers::{jid::Jid, stream_features::StreamFeatures};
 
-use crate::stream_features::StreamFeatures;
 use crate::stream_start;
 use crate::xmpp_codec::{Packet, XmppCodec};
 use crate::Error;
@@ -60,12 +59,12 @@ impl<S: AsyncRead + AsyncWrite + Unpin> XMPPStream<S> {
         stream: Framed<S, XmppCodec>,
         ns: String,
         id: String,
-        stream_features: Element,
+        stream_features: StreamFeatures,
     ) -> Self {
         XMPPStream {
             jid,
             stream,
-            stream_features: StreamFeatures::new(stream_features),
+            stream_features,
             ns,
             id,
         }