WIP: mess
This commit is contained in:
parent
b4652b3939
commit
2536fa4937
|
@ -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?;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ use quick_xml::{
|
|||
|
||||
use crate::{JabberClient, JabberError, JID};
|
||||
|
||||
use super::{Element, IntoElement};
|
||||
use crate::Result;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
Loading…
Reference in New Issue