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::Presence(p) => {
let mut events = vec![];
let response = Presence {
let response = Presence::<()> {
to: Some("darova@localhost/kek".to_string()),
from: Some("darova@localhost/kek".to_string()),
..Default::default()

View File

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

View File

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

View File

@ -3,6 +3,9 @@ use quick_xml::name::ResolveResult;
use crate::prelude::Result;
mod ignore;
pub use ignore::Ignore;
pub trait FromXml: Sized {
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>>) {}
}