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::{
events::{BytesDecl, Event},
name::QName,
Reader, Writer,
};
use rsasl::prelude::{Mechname, SASLClient};
@ -53,7 +52,9 @@ impl<'j> JabberClient<'j> {
.write_event_async(Event::Decl(declaration))
.await;
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
let mut buf = Vec::new();
self.reader.read_event_into_async(&mut buf).await?;

View File

@ -1,12 +1,4 @@
use std::collections::BTreeMap;
use quick_xml::{
events::{BytesStart, BytesText, Event},
name::QName,
Reader,
};
use super::{Element, IntoElement, Node};
use super::{Element, ElementParseError};
use crate::{JabberError, JID};
const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-bind";
@ -17,120 +9,40 @@ pub struct Bind {
}
impl From<Bind> for Element {
fn from(value: Bind) -> Self {
let mut namespace_declarations = Box::new(BTreeMap::new());
namespace_declarations.insert(None, XMLNS.to_owned());
let mut children = Vec::new();
if let Some(resource) = value.resource {
children.push(Node::Element(
Element { prefix: None, localname: "", namespace: , namespace_declarations: , attributes: , children: }
)
)
fn from(bind: Bind) -> Self {
let bind_element = Element::new("bind", None, XMLNS);
bind_element.push_namespace_declaration((None, XMLNS));
if let Some(resource) = bind.resource {
let resource_element = Element::new("resource", None, XMLNS);
resource_element.push_child(resource);
bind_element.push_child(resource_element)
}
Self {
prefix: None,
localname: "bind".to_string(),
namespace: XMLNS.to_owned(),
namespace_declarations,
attributes: todo!(),
children: todo!(),
if let Some(jid) = bind.jid {
let jid_element = Element::new("jid", None, XMLNS);
jid_element.push_child(jid);
bind_element.push_child(jid_element)
}
bind_element
}
}
impl IntoElement 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 {
impl TryFrom<Element> for Bind {
type Error = JabberError;
fn try_from(element: Element<'static>) -> Result<Self, Self::Error> {
if let Event::Start(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
})
{
let child: Element<'static> = element.child()?.clone();
if let Event::Start(start) = &child.event {
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),
fn try_from(element: Element) -> Result<Self, Self::Error> {
if element.namespace() == XMLNS && element.localname() == "bind" {
let (resource, jid);
let child: &Element = element.child()?;
if child.namespace() == XMLNS {
match child.localname() {
"resource" => Bind::new(Some(
child
.text_content()?
.first()
.ok_or(ElementParseError::NoContent)?,
)),
}
}
}
} 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 super::{Element, IntoElement};
use crate::Result;
#[derive(Debug)]

View File

@ -17,8 +17,6 @@ use tokio::io::{AsyncBufRead, AsyncWrite};
use crate::{JabberError, Result};
pub type Prefix<'s> = Option<&'s str>;
#[derive(Clone, Debug)]
/// represents an xml element as a tree of nodes
pub struct Element {
@ -78,19 +76,6 @@ pub struct Element {
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)]
pub enum Node {
Element(Element),
@ -244,22 +229,22 @@ impl Element {
/// by a parent, or itself.
fn namespace_qualified<S: AsRef<str>>(
&self,
local_namespaces: &BTreeMap<Option<S>, S>,
namespace_context: &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 = *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 namespace != self.namespace {
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 {
if child.namespace_qualified(local_namespaces) == false {
if child.namespace_qualified(&local_namespaces) == false {
return false;
}
}
@ -267,6 +252,7 @@ impl Element {
true
}
/// 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
pub async fn write<S: AsRef<str>, W: AsyncWrite + Unpin + Send>(
@ -274,7 +260,7 @@ impl Element {
writer: &mut Writer<W>,
local_namespaces: &BTreeMap<Option<S>, S>,
) -> 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) {
let events: Vec<Event> = self.into();
for event in events {
@ -553,17 +539,107 @@ impl Node {
fn namespace_qualified<S: AsRef<str>>(
&self,
local_namespaces: &BTreeMap<Option<S>, S>,
namespace_context: &BTreeMap<Option<S>, S>,
) -> bool {
match self {
Self::Element(e) => e.namespace_qualified(local_namespaces),
Self::Element(e) => e.namespace_qualified(namespace_context),
_ => true,
}
}
}
// the issue is i don't know how to validate that an element always has a namespace when it is being written
// TODO: ElementBuilder that makes it easier to build an element under a namespace
pub enum NodeBuilder {
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)]
pub enum ElementError<'e> {

View File

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