forked from lavina/lavina
1
0
Fork 0

fix message parsing

This commit is contained in:
Nikita Vilunov 2023-10-01 21:54:14 +02:00
parent 7c89936a87
commit ea0377c78a
3 changed files with 57 additions and 58 deletions

View File

@ -328,7 +328,7 @@ async fn socket_final(
if let Some(update) = update { if let Some(update) = update {
match update { match update {
lavina_core::player::Updates::NewMessage { room_id, author_id, body } => { lavina_core::player::Updates::NewMessage { room_id, author_id, body } => {
Message { Message::<()> {
to: Some(Jid { to: Some(Jid {
name: Some(authenticated.xmpp_name.clone()), name: Some(authenticated.xmpp_name.clone()),
server: Server("localhost".into()), server: Server("localhost".into()),
@ -344,6 +344,7 @@ async fn socket_final(
lang: None, lang: None,
subject: None, subject: None,
body: body.into(), body: body.into(),
custom: vec![],
} }
.serialize(&mut events); .serialize(&mut events);
} }
@ -393,7 +394,7 @@ async fn handle_packet(
user_handle user_handle
.send_message(RoomId::from(name.0.clone())?, m.body.clone().into()) .send_message(RoomId::from(name.0.clone())?, m.body.clone().into())
.await?; .await?;
Message { Message::<()> {
to: Some(Jid { to: Some(Jid {
name: Some(user.xmpp_name.clone()), name: Some(user.xmpp_name.clone()),
server: Server("localhost".into()), server: Server("localhost".into()),
@ -409,6 +410,7 @@ async fn handle_packet(
lang: None, lang: None,
subject: None, subject: None,
body: m.body.clone(), body: m.body.clone(),
custom: vec![],
} }
.serialize(output); .serialize(output);
false false

View File

@ -49,7 +49,7 @@ impl FromXml for IqClientBody {
#[derive(PartialEq, Eq, Debug, From)] #[derive(PartialEq, Eq, Debug, From)]
pub enum ClientPacket { pub enum ClientPacket {
Iq(Iq<IqClientBody>), Iq(Iq<IqClientBody>),
Message(Message), Message(Message<Ignore>),
Presence(Presence<Ignore>), Presence(Presence<Ignore>),
StreamEnd, StreamEnd,
} }
@ -65,7 +65,7 @@ impl FromXml for ClientPacket {
match_parser!(name, namespace, event; match_parser!(name, namespace, event;
Iq::<IqClientBody>, Iq::<IqClientBody>,
Presence::<Ignore>, Presence::<Ignore>,
Message, Message::<Ignore>,
{ {
Err(anyhow!( Err(anyhow!(
"Unexpected XML event of name {:?} in namespace {:?}", "Unexpected XML event of name {:?} in namespace {:?}",

View File

@ -3,8 +3,7 @@ use quick_xml::events::attributes::Attribute;
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::name::{QName, ResolveResult}; use quick_xml::name::{QName, ResolveResult};
use anyhow::{Result, anyhow as ffail}; use anyhow::{anyhow as ffail, Result};
use crate::prelude::*; use crate::prelude::*;
use crate::xml::*; use crate::xml::*;
@ -26,33 +25,33 @@ pub struct Message<T> {
pub custom: Vec<T>, pub custom: Vec<T>,
} }
impl<T> FromXmlTag for Message<T> { impl<T: FromXml> FromXmlTag for Message<T> {
const NS: &'static str = XMLNS; const NS: &'static str = XMLNS;
const NAME: &'static str = "message"; const NAME: &'static str = "message";
} }
impl<T> FromXml for Message<T> { impl<T: FromXml> FromXml for Message<T> {
type P = MessageParser<T>; type P = impl Parser<Output = Result<Self>>;
fn parse() -> Self::P { fn parse() -> Self::P {
MessageParserInner::Init.into() MessageParser(MessageParserInner::Init)
} }
} }
#[derive(From)] #[derive(From)]
pub struct MessageParser<T: FromXml>(MessageParserInner<T>); struct MessageParser<T: FromXml>(MessageParserInner<T>);
#[derive(Default)] #[derive(Default)]
enum MessageParserInner<T: FromXml> { enum MessageParserInner<T: FromXml> {
#[default] #[default]
Init, Init,
Outer(MessageParserState), Outer(MessageParserState<T>),
InSubject(MessageParserState), InSubject(MessageParserState<T>),
InBody(MessageParserState), InBody(MessageParserState<T>),
InCustom(T::P), InCustom(MessageParserState<T>, T::P),
} }
#[derive(Default)] #[derive(Default)]
struct MessageParserState { struct MessageParserState<T> {
from: Option<Jid>, from: Option<Jid>,
id: Option<String>, id: Option<String>,
to: Option<Jid>, to: Option<Jid>,
@ -60,21 +59,27 @@ struct MessageParserState {
lang: Option<Str>, lang: Option<Str>,
subject: Option<Str>, subject: Option<Str>,
body: Option<Str>, body: Option<Str>,
custom: Vec<T>,
} }
impl<T> Parser for MessageParser<T> { impl<T: FromXml> Parser for MessageParser<T> {
type Output = Result<Message<T>>; type Output = Result<Message<T>>;
fn consume<'a>( fn consume<'a>(self: Self, namespace: ResolveResult, event: &Event<'a>) -> Continuation<Self, Self::Output> {
self: Self,
namespace: ResolveResult,
event: &Event<'a>,
) -> Continuation<Self, Self::Output> {
// TODO validate tag name and namespace at each stage // TODO validate tag name and namespace at each stage
use MessageParserInner::*; use MessageParserInner::*;
match self.0 { match self.0 {
Init => { Init => {
if let Event::Start(ref bytes) = event { if let Event::Start(ref bytes) = event {
let mut state: MessageParserState = Default::default(); let mut state: MessageParserState<T> = MessageParserState {
from: None,
id: None,
to: None,
r#type: MessageType::Normal,
lang: None,
subject: None,
body: None,
custom: vec![],
};
for attr in bytes.attributes() { for attr in bytes.attributes() {
let attr = fail_fast!(attr); let attr = fail_fast!(attr);
if attr.key.0 == b"from" { if attr.key.0 == b"from" {
@ -105,7 +110,7 @@ impl<T> Parser for MessageParser<T> {
} else if bytes.name().0 == b"body" { } else if bytes.name().0 == b"body" {
Continuation::Continue(InBody(state).into()) Continuation::Continue(InBody(state).into())
} else { } else {
Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))) Continuation::Continue(InCustom(state, T::parse()).into())
} }
} }
Event::End(_) => { Event::End(_) => {
@ -118,6 +123,7 @@ impl<T> Parser for MessageParser<T> {
lang: state.lang, lang: state.lang,
subject: state.subject, subject: state.subject,
body, body,
custom: state.custom,
})) }))
} else { } else {
Continuation::Final(Err(ffail!("Body not found"))) Continuation::Final(Err(ffail!("Body not found")))
@ -145,6 +151,14 @@ impl<T> Parser for MessageParser<T> {
Event::End(_) => Continuation::Continue(Outer(state).into()), Event::End(_) => Continuation::Continue(Outer(state).into()),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))), _ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
}, },
InCustom(mut state, mut custom) => match custom.consume(namespace, event) {
Continuation::Final(Ok(e)) => {
state.custom.push(e);
Continuation::Continue(Outer(state).into())
}
Continuation::Final(Err(e)) => Continuation::Final(Err(e)),
Continuation::Continue(c) => Continuation::Continue(InCustom(state, c).into()),
},
} }
} }
} }
@ -262,11 +276,7 @@ struct IqParserState<T> {
impl<T: FromXml> Parser for IqParser<T> { impl<T: FromXml> Parser for IqParser<T> {
type Output = Result<Iq<T>>; type Output = Result<Iq<T>>;
fn consume<'a>( fn consume<'a>(self: Self, namespace: ResolveResult, event: &Event<'a>) -> Continuation<Self, Self::Output> {
self: Self,
namespace: ResolveResult,
event: &Event<'a>,
) -> Continuation<Self, Self::Output> {
match self.0 { match self.0 {
IqParserInner::Init => { IqParserInner::Init => {
if let Event::Start(ref bytes) = event { if let Event::Start(ref bytes) = event {
@ -298,18 +308,16 @@ impl<T: FromXml> Parser for IqParser<T> {
Continuation::Final(Err(ffail!("Expected start"))) Continuation::Final(Err(ffail!("Expected start")))
} }
} }
IqParserInner::ParsingBody(mut state, parser) => { IqParserInner::ParsingBody(mut state, parser) => match parser.consume(namespace, event) {
match parser.consume(namespace, event) { Continuation::Final(f) => {
Continuation::Final(f) => { let body = fail_fast!(f);
let body = fail_fast!(f); state.body = Some(body);
state.body = Some(body); Continuation::Continue(IqParser(IqParserInner::Final(state)))
Continuation::Continue(IqParser(IqParserInner::Final(state)))
}
Continuation::Continue(parser) => {
Continuation::Continue(IqParser(IqParserInner::ParsingBody(state, parser)))
}
} }
} Continuation::Continue(parser) => {
Continuation::Continue(IqParser(IqParserInner::ParsingBody(state, parser)))
}
},
IqParserInner::Final(state) => { IqParserInner::Final(state) => {
if let Event::End(ref bytes) = event { if let Event::End(ref bytes) = event {
let id = fail_fast!(state.id.ok_or_else(|| ffail!("No id provided"))); let id = fail_fast!(state.id.ok_or_else(|| ffail!("No id provided")));
@ -590,22 +598,16 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn parse_message() { async fn parse_message() {
let input = r#"<message id="aacea" type="chat" to="nikita@vlnv.dev"><subject>daa</subject><body>bbb</body></message>"#; let input = r#"<message id="aacea" type="chat" to="nikita@vlnv.dev"><subject>daa</subject><body>bbb</body><unknown-stuff></unknown-stuff></message>"#;
let mut reader = NsReader::from_reader(input.as_bytes()); let mut reader = NsReader::from_reader(input.as_bytes());
let mut buf = vec![]; let mut buf = vec![];
let (ns, event) = reader let (ns, event) = reader.read_resolved_event_into_async(&mut buf).await.unwrap();
.read_resolved_event_into_async(&mut buf)
.await
.unwrap();
let mut parser = Message::parse().consume(ns, &event); let mut parser = Message::parse().consume(ns, &event);
let result = loop { let result = loop {
match parser { match parser {
Continuation::Final(res) => break res, Continuation::Final(res) => break res,
Continuation::Continue(next) => { Continuation::Continue(next) => {
let (ns, event) = reader let (ns, event) = reader.read_resolved_event_into_async(&mut buf).await.unwrap();
.read_resolved_event_into_async(&mut buf)
.await
.unwrap();
parser = next.consume(ns, &event); parser = next.consume(ns, &event);
} }
} }
@ -613,7 +615,7 @@ mod tests {
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
result, result,
Message { Message::<Ignore> {
from: None, from: None,
id: Some("aacea".to_string()), id: Some("aacea".to_string()),
to: Some(Jid { to: Some(Jid {
@ -625,6 +627,7 @@ mod tests {
lang: None, lang: None,
subject: Some("daa".into()), subject: Some("daa".into()),
body: "bbb".into(), body: "bbb".into(),
custom: vec![Ignore],
} }
) )
} }
@ -634,19 +637,13 @@ mod tests {
let input = r#"<iq id="bind_1" type="set"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>mobile</resource></bind></iq>"#; let input = r#"<iq id="bind_1" type="set"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>mobile</resource></bind></iq>"#;
let mut reader = NsReader::from_reader(input.as_bytes()); let mut reader = NsReader::from_reader(input.as_bytes());
let mut buf = vec![]; let mut buf = vec![];
let (ns, event) = reader let (ns, event) = reader.read_resolved_event_into_async(&mut buf).await.unwrap();
.read_resolved_event_into_async(&mut buf)
.await
.unwrap();
let mut parser = Iq::<BindRequest>::parse().consume(ns, &event); let mut parser = Iq::<BindRequest>::parse().consume(ns, &event);
let result = loop { let result = loop {
match parser { match parser {
Continuation::Final(res) => break res, Continuation::Final(res) => break res,
Continuation::Continue(next) => { Continuation::Continue(next) => {
let (ns, event) = reader let (ns, event) = reader.read_resolved_event_into_async(&mut buf).await.unwrap();
.read_resolved_event_into_async(&mut buf)
.await
.unwrap();
parser = next.consume(ns, &event); parser = next.consume(ns, &event);
} }
} }