diff options
-rw-r--r-- | src/client/encrypted.rs | 7 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/stanza/mod.rs | 110 |
3 files changed, 116 insertions, 4 deletions
diff --git a/src/client/encrypted.rs b/src/client/encrypted.rs index 86aba13..03ae295 100644 --- a/src/client/encrypted.rs +++ b/src/client/encrypted.rs @@ -85,6 +85,13 @@ impl<'j> JabberClient<'j> { } } + pub async fn watch(&mut self) -> Result<()> { + loop { + let element = Element::read(&mut self.reader).await?; + println!("{:#?}", element); + } + } + pub async fn sasl(&mut self, mechanisms: &Vec<String>) -> Result<()> { println!("{:?}", mechanisms); let sasl = SASLClient::new(self.jabber.auth.clone()); @@ -52,6 +52,9 @@ mod tests { .unwrap() .login() .await + .unwrap() + .watch() + .await .unwrap(); } } diff --git a/src/stanza/mod.rs b/src/stanza/mod.rs index ad9e228..8251422 100644 --- a/src/stanza/mod.rs +++ b/src/stanza/mod.rs @@ -5,18 +5,117 @@ pub mod iq; pub mod sasl; pub mod stream; +use std::collections::BTreeMap; + // const DECLARATION: BytesDecl<'_> = BytesDecl::new("1.0", None, None); use async_recursion::async_recursion; -use quick_xml::events::Event; +use quick_xml::events::{BytesStart, Event}; use quick_xml::{Reader, Writer}; use tokio::io::{AsyncBufRead, AsyncWrite}; use crate::JabberError; +// #[derive(Clone, Debug)] +// pub struct EventTree<'e> { +// pub event: Event<'e>, +// pub children: Option<Vec<Element<'e>>>, +// } + +pub type Prefix<'s> = Option<&'s str>; + #[derive(Clone, Debug)] -pub struct Element<'e> { - pub event: Event<'e>, - pub children: Option<Vec<Element<'e>>>, +/// represents an xml element as a tree of nodes +pub struct Element<'s> { + /// element prefix + /// e.g. `foo` in `<foo:bar />`. + prefix: Option<&'s str>, + /// qualifying namespace + /// an element must be qualified by a namespace + /// e.g. for `<stream:features>` in + /// ``` + /// <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'> + /// <stream:features> + /// <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/> + /// <compression xmlns='http://jabber.org/features/compress'> + /// <method>zlib</method> + /// <method>lzw</method> + /// </compression> + /// </stream:features> + /// </stream:stream> + /// ``` + /// would be `"http://etherx.jabber.org/streams"` but for + /// ``` + /// <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'> + /// <features> + /// <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/> + /// <compression xmlns='http://jabber.org/features/compress'> + /// <method>zlib</method> + /// <method>lzw</method> + /// </compression> + /// </features> + /// </stream:stream> + /// ``` + /// would be `"jabber:client"` + namespace: &'s str, + /// element name + /// e.g. `bar` in `<foo:bar />`. + name: &'s str, + /// all namespaces applied to element + /// e.g. for `<bind>` in + /// ``` + /// <stream:features xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'> + /// <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/> + /// <compression xmlns='http://jabber.org/features/compress'> + /// <method>zlib</method> + /// <method>lzw</method> + /// </compression> + /// </stream:features> + /// ``` + /// would be `[(None, "urn:ietf:params:xml:ns:xmpp-bind")]` despite + /// `(Some("stream"), "http://etherx.jabber.org/streams")` also being available + namespaces: Box<BTreeMap<Option<&'s str>, &'s str>>, + /// element attributes + attributes: Box<BTreeMap<&'s str, &'s str>>, + // children elements namespaces contain their parents' namespaces + /// + children: Option<Box<Vec<Node<'s>>>>, +} + +#[derive(Clone, Debug)] +pub enum Node<'s> { + Element(Element<'s>), + Text(&'s str), +} + +impl<'s> From<&Element<'s>> for Event<'s> { + fn from(element: &Element<'s>) -> Self { + let event; + if let Some(prefix) = element.prefix { + event = BytesStart::new(format!("{}:{}", prefix, element.name)); + } else { + event = BytesStart::new(element.name); + } + + event + + let event = event.with_attributes(element.attributes.into_iter()); + + match element.children.is_none() { + true => return Event::Empty(event), + false => return Event::Start(event), + } + } +} + +impl<'s> Element<'s> { + /// returns the namespace which applies to the current element, e.g. for + /// `<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>` + /// it will be `http://etherx.jabber.org/streams` but for + /// `<stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>` + /// it will be `jabber:client`. + pub fn get_namespace(&self) -> &str { + self.namespace + } } impl<'e: 'async_recursion, 'async_recursion> Element<'e> { @@ -35,6 +134,9 @@ impl<'e: 'async_recursion, 'async_recursion> Element<'e> { 'life0: 'async_recursion, { Box::pin(async move { + match &self.children.is_empty() { + true => {} + } match &self.event { Event::Start(e) => { writer.write_event_async(Event::Start(e.clone())).await?; |