feat(xmpp): make presence polymorphic wrt any fields

This commit is contained in:
Nikita Vilunov 2023-03-20 17:25:14 +01:00
parent 1cc4761aeb
commit a65ea89ce1
5 changed files with 117 additions and 22 deletions

View File

@ -337,7 +337,7 @@ async fn socket_final(
proto::ClientPacket::Message(_) => todo!(), proto::ClientPacket::Message(_) => todo!(),
proto::ClientPacket::Presence(p) => { proto::ClientPacket::Presence(p) => {
let mut events = vec![]; let mut events = vec![];
let response = Presence { let response = Presence::<()> {
to: Some("darova@localhost/kek".to_string()), to: Some("darova@localhost/kek".to_string()),
from: Some("darova@localhost/kek".to_string()), from: Some("darova@localhost/kek".to_string()),
..Default::default() ..Default::default()

View File

@ -72,7 +72,7 @@ impl Parser for IqClientBodyParser {
pub enum ClientPacket { pub enum ClientPacket {
Iq(Iq<IqClientBody>), Iq(Iq<IqClientBody>),
Message(Message), Message(Message),
Presence(Presence), Presence(Presence<Ignore>),
} }
#[derive(From)] #[derive(From)]
@ -91,7 +91,7 @@ enum ClientPacketParserInner {
Initial, Initial,
IqV(<Iq<IqClientBody> as FromXml>::P), IqV(<Iq<IqClientBody> as FromXml>::P),
MessageV(<Message as FromXml>::P), MessageV(<Message as FromXml>::P),
PresenceV(<Presence as FromXml>::P), PresenceV(<Presence<Ignore> as FromXml>::P),
} }
impl Parser for ClientPacketParser { impl Parser for ClientPacketParser {
@ -111,7 +111,7 @@ impl Parser for ClientPacketParser {
let name = bytes.name(); let name = bytes.name();
match_parser!(ClientPacketParser, name, namespace, event; match_parser!(ClientPacketParser, name, namespace, event;
Iq::<IqClientBody>, Iq::<IqClientBody>,
Presence, Presence::<Ignore>,
Message Message
) )
} }

View File

@ -342,13 +342,27 @@ impl<T: ToXml> ToXml for Iq<T> {
} }
} }
#[derive(PartialEq, Eq, Debug, Default)] #[derive(PartialEq, Eq, Debug)]
pub struct Presence { pub struct Presence<T> {
pub to: Option<String>, pub to: Option<String>,
pub from: Option<String>, pub from: Option<String>,
pub priority: Option<PresencePriority>, pub priority: Option<PresencePriority>,
pub show: Option<PresenceShow>, pub show: Option<PresenceShow>,
pub status: Vec<String>, pub status: Vec<String>,
pub custom: Vec<T>,
}
impl<T> Default for Presence<T> {
fn default() -> Self {
Self {
to: Default::default(),
from: Default::default(),
priority: Default::default(),
show: Default::default(),
status: Default::default(),
custom: Default::default(),
}
}
} }
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug)]
@ -389,20 +403,21 @@ impl PresenceShow {
} }
#[derive(From)] #[derive(From)]
pub struct PresenceParser(PresenceParserInner); pub struct PresenceParser<T: FromXml>(PresenceParserInner<T>);
enum PresenceParserInner { enum PresenceParserInner<T: FromXml> {
Initial, Initial,
InPresence(Presence), InPresence(Presence<T>),
InPriority(Presence), InPriority(Presence<T>),
InPriorityEnd(Presence), InPriorityEnd(Presence<T>),
InShow(Presence), InShow(Presence<T>),
InShowEnd(Presence), InShowEnd(Presence<T>),
InStatus(Presence), InStatus(Presence<T>),
InStatusEnd(Presence), InStatusEnd(Presence<T>),
InCustom(Presence<T>, T::P),
} }
impl Parser for PresenceParser { impl<T: FromXml> Parser for PresenceParser<T> {
type Output = Result<Presence>; type Output = Result<Presence<T>>;
fn consume<'a>( fn consume<'a>(
self: Self, self: Self,
@ -425,8 +440,11 @@ impl Parser for PresenceParser {
b"priority" => { b"priority" => {
Continuation::Continue(PresenceParserInner::InPriority(p).into()) Continuation::Continue(PresenceParserInner::InPriority(p).into())
} }
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))), _ => PresenceParser(PresenceParserInner::InCustom(p, T::parse()))
.consume(namespace, event),
}, },
Event::Empty(_) => PresenceParser(PresenceParserInner::InCustom(p, T::parse()))
.consume(namespace, event),
Event::End(_) => Continuation::Final(Ok(p)), Event::End(_) => Continuation::Final(Ok(p)),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))), _ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
}, },
@ -489,24 +507,36 @@ impl Parser for PresenceParser {
Event::End(_) => Continuation::Continue(PresenceParserInner::InPresence(p).into()), Event::End(_) => Continuation::Continue(PresenceParserInner::InPresence(p).into()),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))), _ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
}, },
PresenceParserInner::InCustom(mut p, c) => match c.consume(namespace, event) {
Continuation::Final(Ok(res)) => {
p.custom.push(res);
Continuation::Continue(PresenceParserInner::InPresence(p).into())
}
Continuation::Final(Err(err)) => Continuation::Final(Err(ffail!(
"Failed to parse custom presence element: {err}"
))),
Continuation::Continue(c) => {
Continuation::Continue(PresenceParserInner::InCustom(p, c).into())
}
},
} }
} }
} }
impl FromXml for Presence { impl<T: FromXml> FromXml for Presence<T> {
type P = PresenceParser; type P = PresenceParser<T>;
fn parse() -> Self::P { fn parse() -> Self::P {
PresenceParserInner::Initial.into() PresenceParserInner::Initial.into()
} }
} }
impl FromXmlTag for Presence { impl<T: FromXml> FromXmlTag for Presence<T> {
const NAME: &'static str = "presence"; const NAME: &'static str = "presence";
const NS: &'static str = XMLNS; const NS: &'static str = XMLNS;
} }
impl ToXml for Presence { impl<T: ToXml> ToXml for Presence<T> {
fn serialize(&self, events: &mut Vec<Event<'static>>) { fn serialize(&self, events: &mut Vec<Event<'static>>) {
let mut start = BytesStart::new("presence"); let mut start = BytesStart::new("presence");
if let Some(ref to) = self.to { if let Some(ref to) = self.to {

View File

@ -3,6 +3,9 @@ use quick_xml::name::ResolveResult;
use crate::prelude::Result; use crate::prelude::Result;
mod ignore;
pub use ignore::Ignore;
pub trait FromXml: Sized { pub trait FromXml: Sized {
type P: Parser<Output = Result<Self>>; type P: Parser<Output = Result<Self>>;

62
src/util/xml/ignore.rs Normal file
View File

@ -0,0 +1,62 @@
use super::*;
use derive_more::From;
#[derive(Default, Debug, PartialEq, Eq)]
pub struct Ignore;
#[derive(From)]
pub struct IgnoreParser(IgnoreParserInner);
enum IgnoreParserInner {
Initial,
InTag { name: Vec<u8>, depth: u8 },
}
impl Parser for IgnoreParser {
type Output = Result<Ignore>;
fn consume<'a>(
self: Self,
namespace: ResolveResult,
event: &Event<'a>,
) -> Continuation<Self, Self::Output> {
match self.0 {
IgnoreParserInner::Initial => match event {
Event::Start(bytes) => {
let name = bytes.name().0.to_owned();
Continuation::Continue(IgnoreParserInner::InTag { name, depth: 0 }.into())
}
Event::Empty(_) => Continuation::Final(Ok(Ignore)),
_ => Continuation::Final(Ok(Ignore)),
},
IgnoreParserInner::InTag { name, depth } => match event {
Event::End(bytes) if name == bytes.name().0 => {
if depth == 0 {
Continuation::Final(Ok(Ignore))
} else {
Continuation::Continue(
IgnoreParserInner::InTag {
name,
depth: depth - 1,
}
.into(),
)
}
}
_ => Continuation::Final(Ok(Ignore)),
},
}
}
}
impl FromXml for Ignore {
type P = IgnoreParser;
fn parse() -> Self::P {
IgnoreParserInner::Initial.into()
}
}
impl ToXml for () {
fn serialize(&self, events: &mut Vec<Event<'static>>) {}
}