summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/client/encrypted.rs7
-rw-r--r--src/lib.rs3
-rw-r--r--src/stanza/mod.rs110
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());
diff --git a/src/lib.rs b/src/lib.rs
index 95a228b..8162ccc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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?;