WIP: mess

This commit is contained in:
cel 🌸 2023-10-20 02:34:47 +01:00
parent b4652b3939
commit 2536fa4937
5 changed files with 134 additions and 147 deletions

View File

@ -1,8 +1,7 @@
use std::str; use std::{collections::BTreeMap, str};
use quick_xml::{ use quick_xml::{
events::{BytesDecl, Event}, events::{BytesDecl, Event},
name::QName,
Reader, Writer, Reader, Writer,
}; };
use rsasl::prelude::{Mechname, SASLClient}; use rsasl::prelude::{Mechname, SASLClient};
@ -53,7 +52,9 @@ impl<'j> JabberClient<'j> {
.write_event_async(Event::Decl(declaration)) .write_event_async(Event::Decl(declaration))
.await; .await;
let stream_element: Element<'_> = stream_element.into(); let stream_element: Element<'_> = stream_element.into();
stream_element.write_start(&mut self.writer).await?; stream_element
.write_start(&mut self.writer, &BTreeMap::new())
.await?;
// server to client // server to client
let mut buf = Vec::new(); let mut buf = Vec::new();
self.reader.read_event_into_async(&mut buf).await?; self.reader.read_event_into_async(&mut buf).await?;

View File

@ -1,12 +1,4 @@
use std::collections::BTreeMap; use super::{Element, ElementParseError};
use quick_xml::{
events::{BytesStart, BytesText, Event},
name::QName,
Reader,
};
use super::{Element, IntoElement, Node};
use crate::{JabberError, JID}; use crate::{JabberError, JID};
const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-bind"; const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-bind";
@ -17,120 +9,40 @@ pub struct Bind {
} }
impl From<Bind> for Element { impl From<Bind> for Element {
fn from(value: Bind) -> Self { fn from(bind: Bind) -> Self {
let mut namespace_declarations = Box::new(BTreeMap::new()); let bind_element = Element::new("bind", None, XMLNS);
namespace_declarations.insert(None, XMLNS.to_owned()); bind_element.push_namespace_declaration((None, XMLNS));
let mut children = Vec::new(); if let Some(resource) = bind.resource {
if let Some(resource) = value.resource { let resource_element = Element::new("resource", None, XMLNS);
children.push(Node::Element( resource_element.push_child(resource);
Element { prefix: None, localname: "", namespace: , namespace_declarations: , attributes: , children: } bind_element.push_child(resource_element)
)
)
} }
Self { if let Some(jid) = bind.jid {
prefix: None, let jid_element = Element::new("jid", None, XMLNS);
localname: "bind".to_string(), jid_element.push_child(jid);
namespace: XMLNS.to_owned(), bind_element.push_child(jid_element)
namespace_declarations,
attributes: todo!(),
children: todo!(),
} }
bind_element
} }
} }
impl IntoElement for Bind { impl TryFrom<Element> for Bind {
fn event(&self) -> quick_xml::events::Event<'static> {
let mut bind_event = BytesStart::new("bind");
bind_event.push_attribute(("xmlns", XMLNS));
if self.resource.is_none() && self.jid.is_none() {
return Event::Empty(bind_event);
} else {
return Event::Start(bind_event);
}
}
fn children(&self) -> Option<Vec<Element<'static>>> {
if let Some(resource) = &self.resource {
let resource_event: BytesStart<'static> = BytesStart::new("resource");
let resource_child: BytesText<'static> = BytesText::new(resource).into_owned();
let resource_child: Element<'static> = Element {
event: Event::Text(resource_child),
children: None,
};
let resource_element: Element<'static> = Element {
event: Event::Start(resource_event),
children: Some(vec![resource_child]),
};
return Some(vec![resource_element]);
} else if let Some(jid) = &self.jid {
let jid_event = BytesStart::new("jid");
let jid_child = BytesText::new(&jid.to_string()).into_owned();
let jid_child = Element {
event: Event::Text(jid_child),
children: None,
};
let jid_element = Element {
event: Event::Start(jid_event),
children: Some(vec![jid_child]),
};
return Some(vec![jid_element]);
}
None
}
}
impl TryFrom<Element<'static>> for Bind {
type Error = JabberError; type Error = JabberError;
fn try_from(element: Element<'static>) -> Result<Self, Self::Error> { fn try_from(element: Element) -> Result<Self, Self::Error> {
if let Event::Start(start) = &element.event { if element.namespace() == XMLNS && element.localname() == "bind" {
let buf: Vec<u8> = Vec::new(); let (resource, jid);
let reader = Reader::from_reader(buf); let child: &Element = element.child()?;
if start.name() == QName(b"bind") if child.namespace() == XMLNS {
&& start.try_get_attribute("xmlns")?.is_some_and(|attribute| { match child.localname() {
attribute.decode_and_unescape_value(&reader).unwrap() == XMLNS "resource" => Bind::new(Some(
}) child
{ .text_content()?
let child: Element<'static> = element.child()?.clone(); .first()
if let Event::Start(start) = &child.event { .ok_or(ElementParseError::NoContent)?,
match start.name() { )),
QName(b"resource") => {
let resource_text = child.child()?;
if let Event::Text(text) = &resource_text.event {
return Ok(Self {
resource: Some(text.unescape()?.into_owned()),
jid: None,
});
}
}
QName(b"jid") => {
let jid_text = child.child()?;
if let Event::Text(text) = &jid_text.event {
return Ok(Self {
jid: Some(text.unescape()?.into_owned().try_into()?),
resource: None,
});
}
}
_ => return Err(JabberError::UnexpectedElement),
}
} }
} }
} else if let Event::Empty(start) = &element.event {
let buf: Vec<u8> = Vec::new();
let reader = Reader::from_reader(buf);
if start.name() == QName(b"bind")
&& start.try_get_attribute("xmlns")?.is_some_and(|attribute| {
attribute.decode_and_unescape_value(&reader).unwrap() == XMLNS
})
{
return Ok(Bind {
resource: None,
jid: None,
});
}
} }
Err(JabberError::UnexpectedElement)
} }
} }

View File

@ -7,7 +7,6 @@ use quick_xml::{
use crate::{JabberClient, JabberError, JID}; use crate::{JabberClient, JabberError, JID};
use super::{Element, IntoElement};
use crate::Result; use crate::Result;
#[derive(Debug)] #[derive(Debug)]

View File

@ -17,8 +17,6 @@ use tokio::io::{AsyncBufRead, AsyncWrite};
use crate::{JabberError, Result}; use crate::{JabberError, Result};
pub type Prefix<'s> = Option<&'s str>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// represents an xml element as a tree of nodes /// represents an xml element as a tree of nodes
pub struct Element { pub struct Element {
@ -78,19 +76,6 @@ pub struct Element {
children: Box<Vec<Node>>, children: Box<Vec<Node>>,
} }
impl Element {
pub fn new_empty<S: ToString, C: Into<Node>>(
prefix: Option<S>,
localname: S,
namespace: S,
namespace_declarations: BTreeMap<Option<S>, S>,
attributes: BTreeMap<S, S>,
children: Vec<C>,
) {
}
pub fn push_child<C: Into<Node>>(&mut self, node: C) {}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Node { pub enum Node {
Element(Element), Element(Element),
@ -244,22 +229,22 @@ impl Element {
/// by a parent, or itself. /// by a parent, or itself.
fn namespace_qualified<S: AsRef<str>>( fn namespace_qualified<S: AsRef<str>>(
&self, &self,
local_namespaces: &BTreeMap<Option<S>, S>, namespace_context: &BTreeMap<Option<S>, S>,
) -> bool { ) -> bool {
// create a new local_namespaces combining that in the context and those declared within the element
let mut local_namespaces = *namespace_context.clone();
self.namespace_declarations.iter().for_each(|prefix, declaration| local_namespaces.insert(prefix, declaration));
if let Some(namespace) = local_namespaces.get(self.prefix) { if let Some(namespace) = local_namespaces.get(self.prefix) {
if namespace != self.namespace { if namespace != self.namespace {
return false; return false;
} }
} else {
return false;
}; };
if let Some(namespace) = self.namespace_declarations.get(&self.prefix) {
if namespace != self.namespace {
return false;
}
}
for child in *self.children { for child in *self.children {
if child.namespace_qualified(local_namespaces) == false { if child.namespace_qualified(&local_namespaces) == false {
return false; return false;
} }
} }
@ -267,6 +252,7 @@ impl Element {
true true
} }
/// writes an element to a writer. the element's namespace must be qualified by the /// writes an element to a writer. the element's namespace must be qualified by the
/// context given in `local_namespaces` or the element's internal namespace declarations /// context given in `local_namespaces` or the element's internal namespace declarations
pub async fn write<S: AsRef<str>, W: AsyncWrite + Unpin + Send>( pub async fn write<S: AsRef<str>, W: AsyncWrite + Unpin + Send>(
@ -274,7 +260,7 @@ impl Element {
writer: &mut Writer<W>, writer: &mut Writer<W>,
local_namespaces: &BTreeMap<Option<S>, S>, local_namespaces: &BTreeMap<Option<S>, S>,
) -> Result<()> { ) -> Result<()> {
// TODO: NEXT: instead of having a check if namespace qualified function, have the namespace declarations be added if needed given the context when converting from `Element` to `Event`s // TODO: instead of having a check if namespace qualified function, have the namespace declarations be added if needed given the context when converting from `Element` to `Event`s
if self.namespace_qualified(local_namespaces) { if self.namespace_qualified(local_namespaces) {
let events: Vec<Event> = self.into(); let events: Vec<Event> = self.into();
for event in events { for event in events {
@ -553,17 +539,107 @@ impl Node {
fn namespace_qualified<S: AsRef<str>>( fn namespace_qualified<S: AsRef<str>>(
&self, &self,
local_namespaces: &BTreeMap<Option<S>, S>, namespace_context: &BTreeMap<Option<S>, S>,
) -> bool { ) -> bool {
match self { match self {
Self::Element(e) => e.namespace_qualified(local_namespaces), Self::Element(e) => e.namespace_qualified(namespace_context),
_ => true, _ => true,
} }
} }
} }
// the issue is i don't know how to validate that an element always has a namespace when it is being written pub enum NodeBuilder {
// TODO: ElementBuilder that makes it easier to build an element under a namespace Text(String),
Element(ElementBuilder),
}
pub struct ElementBuilder {
localname: String,
prefix: Option<String>,
namespace: String,
namespace_declarations: BTreeMap<Option<String>, String>,
attributes: BTreeMap<String, String>,
children: Vec<NodeBuilder>,
}
impl ElementBuilder {
pub fn new<S: ToString>(localname: S, prefix: Option<S>, namespace: S) -> Self {
Self {
prefix,
localname,
namespace,
namespace_declarations: Box::new(BTreeMap::new()),
attributes: Box::new(BTreeMap::new()),
children: Box::new(Vec::new()),
}
}
pub fn push_namespace_declaration<S: ToString>(
&mut self,
(prefix, namespace): (Option<S>, S),
) -> Option<S> {
self.namespace_declarations.insert(prefix, namespace)
}
pub fn push_attribute<S: ToString>(&mut self, (key, value): (S, S)) -> Option<S> {
self.attributes.insert(key, value)
}
pub fn push_child(&mut self, child: Node) {
self.children.push(child)
}
/// checks if there is a namespace conflict within the element being built
pub fn namespace_conflict<S: AsRef<str>>(
&self
) -> bool {
self.namespace_conflict_recursive(&BTreeMap::new())
}
fn namespace_conflict_recursive<S: AsRef<str>>(
&self,
parent_namespaces: &BTreeMap<Option<S>, S>,
) -> bool {
// create a new local_namespaces combining that in the context and those declared within the element
let mut local_namespaces = *parent_namespaces.clone();
self.namespace_declarations.iter().for_each(|prefix, declaration| local_namespaces.insert(prefix, declaration));
if let Some(namespace) = local_namespaces.get(self.prefix) {
if namespace != self.namespace {
return false;
}
} else {
return false;
};
for child in *self.children {
if child.namespace_conflict(&local_namespaces) == false {
return false;
}
}
true
}
// check for possible conflicts in namespace
pub fn build(self) -> Result<Element> {
for child in self.children {
match child {
Node::Element(e) => {
if !e.namespace_conflict()
}
}
}
Element {
prefix: self.prefix,
localname: self.localname,
namespace: self.namespace,
namespace_declarations: self.namespace_declarations,
attributes: self.attributes,
children: self.children,
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum ElementError<'e> { pub enum ElementError<'e> {

View File

@ -7,7 +7,6 @@ use crate::error::SASLError;
use crate::JabberError; use crate::JabberError;
use super::Element; use super::Element;
use super::IntoElement;
const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-sasl"; const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-sasl";