forked from lavina/lavina
Add parsing and test
This commit is contained in:
parent
847cb4867b
commit
f95a63764a
|
@ -1,5 +1,7 @@
|
|||
#![feature(coroutines, coroutine_trait, type_alias_impl_trait, impl_trait_in_assoc_type)]
|
||||
|
||||
extern crate core;
|
||||
|
||||
pub mod bind;
|
||||
pub mod client;
|
||||
pub mod disco;
|
||||
|
|
|
@ -1,26 +1,110 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use quick_xml::events::Event;
|
||||
use quick_xml::name::{Namespace, ResolveResult};
|
||||
use std::io::Read;
|
||||
|
||||
use crate::xml::*;
|
||||
|
||||
pub const XMLNS: &'static str = "urn:xmpp:mam:2";
|
||||
pub const MAM_XMLNS: &'static str = "urn:xmpp:mam:2";
|
||||
pub const DATA_XMLNS: &'static str = "jabber:x:data";
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub struct MessageArchiveRequest;
|
||||
pub struct MessageArchiveRequest {
|
||||
x: Option<X>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub struct X {
|
||||
fields: Vec<Field>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub struct Field {
|
||||
values: Vec<String>,
|
||||
}
|
||||
|
||||
impl FromXmlTag for X {
|
||||
const NAME: &'static str = "x";
|
||||
const NS: &'static str = DATA_XMLNS;
|
||||
}
|
||||
|
||||
impl FromXmlTag for MessageArchiveRequest {
|
||||
const NAME: &'static str = "query";
|
||||
const NS: &'static str = XMLNS;
|
||||
const NS: &'static str = MAM_XMLNS;
|
||||
}
|
||||
|
||||
impl FromXml for X {
|
||||
type P = impl Parser<Output = Result<Self>>;
|
||||
|
||||
fn parse() -> Self::P {
|
||||
|(mut namespace, mut event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
||||
println!("X::parse {:?}", event);
|
||||
|
||||
let bytes = match event {
|
||||
Event::Start(bytes) if bytes.name().0 == X::NAME.as_bytes() => bytes,
|
||||
Event::Empty(bytes) if bytes.name().0 == X::NAME.as_bytes() => return Ok(X { fields: vec![] }),
|
||||
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||
};
|
||||
let mut fields = vec![];
|
||||
loop {
|
||||
(namespace, event) = yield;
|
||||
match event {
|
||||
Event::Start(bytes) => {
|
||||
// start of <field>
|
||||
let mut values = vec![];
|
||||
loop {
|
||||
(namespace, event) = yield;
|
||||
match event {
|
||||
Event::Start(bytes) if bytes.name().0 == b"value" => {
|
||||
// start of <value>
|
||||
}
|
||||
Event::End(bytes) if bytes.name().0 == b"field" => {
|
||||
// end of </field>
|
||||
break;
|
||||
}
|
||||
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||
}
|
||||
(namespace, event) = yield;
|
||||
let text: String = match event {
|
||||
Event::Text(bytes) => {
|
||||
// text inside <value></value>
|
||||
String::from_utf8(bytes.to_vec())?
|
||||
}
|
||||
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||
};
|
||||
(namespace, event) = yield;
|
||||
match event {
|
||||
Event::End(bytes) if bytes.name().0 == b"value" => {
|
||||
// end of </value>
|
||||
}
|
||||
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||
}
|
||||
values.push(text);
|
||||
}
|
||||
fields.push(Field { values })
|
||||
}
|
||||
Event::End(bytes) if bytes.name().0 == X::NAME.as_bytes() => {
|
||||
// end of <x/>
|
||||
return Ok(X { fields });
|
||||
}
|
||||
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromXml for MessageArchiveRequest {
|
||||
type P = impl Parser<Output = Result<Self>>;
|
||||
|
||||
fn parse() -> Self::P {
|
||||
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
||||
let Event::Start(bytes) = event else {
|
||||
return Err(anyhow!("Unexpected XML event: {event:?}"));
|
||||
|(mut namespace, mut event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
||||
println!("MessageArchiveRequest::parse {:?}", event);
|
||||
|
||||
let bytes = match event {
|
||||
Event::Empty(_) => return Ok(MessageArchiveRequest { x: None }),
|
||||
Event::Start(bytes) => bytes,
|
||||
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||
};
|
||||
if bytes.name().0 != MessageArchiveRequest::NAME.as_bytes() {
|
||||
return Err(anyhow!("Unexpected XML tag: {:?}", bytes.name()));
|
||||
|
@ -28,19 +112,20 @@ impl FromXml for MessageArchiveRequest {
|
|||
let ResolveResult::Bound(Namespace(ns)) = namespace else {
|
||||
return Err(anyhow!("No namespace provided"));
|
||||
};
|
||||
if ns != XMLNS.as_bytes() {
|
||||
if ns != MAM_XMLNS.as_bytes() {
|
||||
return Err(anyhow!("Incorrect namespace"));
|
||||
}
|
||||
loop {
|
||||
let (namespace, event) = yield;
|
||||
match event {
|
||||
Event::End(bytes) if bytes.name().0 == MessageArchiveRequest::NAME.as_bytes() => {
|
||||
break;
|
||||
}
|
||||
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||
(namespace, event) = yield;
|
||||
match event {
|
||||
Event::End(bytes) if bytes.name().0 == MessageArchiveRequest::NAME.as_bytes() => {
|
||||
Ok(MessageArchiveRequest { x: None })
|
||||
}
|
||||
Event::Start(bytes) | Event::Empty(bytes) if bytes.name().0 == X::NAME.as_bytes() => {
|
||||
let x = delegate_parsing!(X, namespace, event)?;
|
||||
Ok(MessageArchiveRequest { x: Some(x) })
|
||||
}
|
||||
_ => Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||
}
|
||||
Ok(MessageArchiveRequest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,22 +135,62 @@ impl MessageArchiveRequest {}
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::bind::{Jid, Name, Server};
|
||||
use crate::client::{Iq, IqType};
|
||||
|
||||
#[test]
|
||||
fn test_parse() {
|
||||
let input = r#"<query xmlns="urn:xmpp:mam:2"></query>"#;
|
||||
fn test_parse_archive_query() {
|
||||
let input = r#"<iq to='pubsub.shakespeare.lit' type='set' id='juliet1'><query xmlns='urn:xmpp:mam:2' queryid='f28'/></iq>"#;
|
||||
|
||||
let result: Iq<MessageArchiveRequest> = parse(input).unwrap();
|
||||
assert_eq!(
|
||||
result,
|
||||
Iq {
|
||||
from: None,
|
||||
id: "mam_1".to_string(),
|
||||
to: None,
|
||||
r#type: IqType::Get,
|
||||
body: MessageArchiveRequest,
|
||||
id: "juliet1".to_string(),
|
||||
to: Option::from(Jid {
|
||||
name: None,
|
||||
server: Server("pubsub.shakespeare.lit".into()),
|
||||
resource: None,
|
||||
}),
|
||||
r#type: IqType::Set,
|
||||
body: MessageArchiveRequest { x: None },
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_query_messages_from_jid() {
|
||||
let input = r#"<iq type='set' id='juliet1'><query xmlns='urn:xmpp:mam:2'><x xmlns='jabber:x:data' type='submit'><field var='FORM_TYPE' type='hidden'><value>value1</value></field><field var='with'><value>juliet@capulet.lit</value></field></x></query></iq>"#;
|
||||
|
||||
let result: Iq<MessageArchiveRequest> = parse(input).unwrap();
|
||||
assert_eq!(
|
||||
result,
|
||||
Iq {
|
||||
from: None,
|
||||
id: "juliet1".to_string(),
|
||||
to: None,
|
||||
r#type: IqType::Set,
|
||||
body: MessageArchiveRequest {
|
||||
x: Some(X {
|
||||
fields: vec![
|
||||
Field {
|
||||
values: vec!["value1".to_string()],
|
||||
},
|
||||
Field {
|
||||
values: vec!["juliet@capulet.lit".to_string()],
|
||||
},
|
||||
]
|
||||
})
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_query_messages_from_jid_with_unclosed_tag() {
|
||||
let input = r#"<iq type='set' id='juliet1'><query xmlns='urn:xmpp:mam:2'><x xmlns='jabber:x:data' type='submit'><field var='FORM_TYPE' type='hidden'><value>value1</value></field><field var='with'><value>juliet@capulet.lit</value></field></query></iq>"#;
|
||||
|
||||
assert!(parse::<Iq<MessageArchiveRequest>>(input).is_err())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue