WIP: refactor Element type

This commit is contained in:
cel 🌸 2023-08-02 18:21:57 +01:00
parent cd7bb95c0a
commit 2a7b8834d7
3 changed files with 116 additions and 4 deletions

View File

@ -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());

View File

@ -52,6 +52,9 @@ mod tests {
.unwrap()
.login()
.await
.unwrap()
.watch()
.await
.unwrap();
}
}

View File

@ -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?;