feat(xmpp): implement session iq

This commit is contained in:
Nikita Vilunov 2023-03-12 14:15:13 +01:00
parent 4107c5b663
commit 33dbfba116
7 changed files with 117 additions and 21 deletions

View File

@ -25,6 +25,7 @@ use crate::prelude::*;
use crate::protos::xmpp; use crate::protos::xmpp;
use crate::protos::xmpp::bind::{BindResponse, Jid, Name, Server}; use crate::protos::xmpp::bind::{BindResponse, Jid, Name, Server};
use crate::protos::xmpp::client::Iq; use crate::protos::xmpp::client::Iq;
use crate::protos::xmpp::session::Session;
use crate::protos::xmpp::stream::*; use crate::protos::xmpp::stream::*;
use crate::util::xml::{Continuation, FromXml, Parser, ToXml}; use crate::util::xml::{Continuation, FromXml, Parser, ToXml};
use crate::util::Terminator; use crate::util::Terminator;
@ -301,6 +302,21 @@ async fn socket_final(
} }
xml_writer.get_mut().flush().await?; xml_writer.get_mut().flush().await?;
} }
proto::IqClientBody::Session(_) => {
let mut events = vec![];
let req = Iq {
from: None,
id: iq.id,
to: None,
r#type: xmpp::client::IqType::Result,
body: Session,
};
req.serialize(&mut events);
for i in events {
xml_writer.write_event_async(i).await?;
}
xml_writer.get_mut().flush().await?;
}
}, },
proto::ClientPacket::Message(_) => todo!(), proto::ClientPacket::Message(_) => todo!(),
} }

View File

@ -4,13 +4,15 @@ use quick_xml::name::{Namespace, ResolveResult};
use crate::protos::xmpp::bind::BindRequest; use crate::protos::xmpp::bind::BindRequest;
use crate::protos::xmpp::client::{Iq, Message}; use crate::protos::xmpp::client::{Iq, Message};
use crate::util::xml::{Continuation, FromXml, Parser}; use crate::protos::xmpp::session::Session;
use crate::util::xml::{Continuation, FromXml, FromXmlTag, Parser};
use crate::prelude::*; use crate::prelude::*;
#[derive(PartialEq, Eq, Debug, From)] #[derive(PartialEq, Eq, Debug, From)]
pub enum IqClientBody { pub enum IqClientBody {
Bind(BindRequest), Bind(BindRequest),
Session(Session),
} }
#[derive(From)] #[derive(From)]
@ -20,6 +22,7 @@ pub struct IqClientBodyParser(IqClientBodyParserInner);
enum IqClientBodyParserInner { enum IqClientBodyParserInner {
Initial, Initial,
Bind(<BindRequest as FromXml>::P), Bind(<BindRequest as FromXml>::P),
SessionV(<Session as FromXml>::P),
} }
impl FromXml for IqClientBody { impl FromXml for IqClientBody {
@ -41,20 +44,21 @@ impl Parser for IqClientBodyParser {
use IqClientBodyParserInner::*; use IqClientBodyParserInner::*;
match self.0 { match self.0 {
Initial => { Initial => {
let Event::Start(bytes) = event else { let bytes = match event {
return Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}. Expected start of {}", BindRequest::NAME))); Event::Start(bytes) => bytes,
Event::Empty(bytes) => bytes,
_ => {
return Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}")))
}
}; };
if bytes.name().0 == BindRequest::NAME.as_bytes() if bytes.name().0 == BindRequest::NAME.as_bytes()
&& namespace == ResolveResult::Bound(Namespace(BindRequest::NS.as_bytes())) && namespace == ResolveResult::Bound(Namespace(BindRequest::NS.as_bytes()))
{ {
match BindRequest::parse().consume(namespace, event) { IqClientBodyParser(BindRequest::parse().into()).consume(namespace, event)
Continuation::Final(Ok(r)) => Continuation::Final(Ok(r.into())), } else if bytes.name().0 == Session::NAME.as_bytes()
Continuation::Final(Err(e)) => Continuation::Final(Err(e)), && namespace == ResolveResult::Bound(Namespace(Session::NS.as_bytes()))
Continuation::Continue(s) => { {
let inner: IqClientBodyParserInner = s.into(); IqClientBodyParser(Session::parse().into()).consume(namespace, event)
Continuation::Continue(inner.into())
}
}
} else { } else {
Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))) Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}")))
} }
@ -67,6 +71,14 @@ impl Parser for IqClientBodyParser {
Continuation::Continue(inner.into()) Continuation::Continue(inner.into())
} }
}, },
SessionV(p) => match p.consume(namespace, event) {
Continuation::Final(Ok(r)) => Continuation::Final(Ok(r.into())),
Continuation::Final(Err(e)) => Continuation::Final(Err(e)),
Continuation::Continue(s) => {
let inner: IqClientBodyParserInner = s.into();
Continuation::Continue(inner.into())
}
},
} }
} }
} }

View File

@ -3,7 +3,7 @@ use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::name::{Namespace, ResolveResult}; use quick_xml::name::{Namespace, ResolveResult};
use crate::prelude::*; use crate::prelude::*;
use crate::util::xml::{Continuation, FromXml, Parser, ToXml}; use crate::util::xml::*;
pub const XMLNS: &'static str = "urn:ietf:params:xml:ns:xmpp-bind"; pub const XMLNS: &'static str = "urn:ietf:params:xml:ns:xmpp-bind";
@ -55,9 +55,9 @@ enum BindRequestParserInner {
InBindResourceEnd(String), InBindResourceEnd(String),
} }
impl BindRequest { impl FromXmlTag for BindRequest {
pub const NS: &'static str = XMLNS; const NS: &'static str = XMLNS;
pub const NAME: &'static str = "bind"; const NAME: &'static str = "bind";
} }
impl FromXml for BindRequest { impl FromXml for BindRequest {

View File

@ -21,9 +21,9 @@ pub struct Message {
pub body: String, pub body: String,
} }
impl Message { impl FromXmlTag for Message {
pub const NS: &'static str = XMLNS; const NS: &'static str = XMLNS;
pub const NAME: &'static str = "message"; const NAME: &'static str = "message";
} }
impl FromXml for Message { impl FromXml for Message {
@ -180,9 +180,9 @@ pub struct Iq<T> {
pub body: T, pub body: T,
} }
impl<T> Iq<T> { impl<T: FromXml> FromXmlTag for Iq<T> {
pub const NS: &'static str = XMLNS; const NAME: &'static str = "iq";
pub const NAME: &'static str = "iq"; const NS: &'static str = XMLNS;
} }
impl<T: FromXml> FromXml for Iq<T> { impl<T: FromXml> FromXml for Iq<T> {

View File

@ -1,6 +1,7 @@
pub mod bind; pub mod bind;
pub mod client; pub mod client;
pub mod sasl; pub mod sasl;
pub mod session;
pub mod stanzaerror; pub mod stanzaerror;
pub mod stream; pub mod stream;
pub mod tls; pub mod tls;

View File

@ -0,0 +1,62 @@
use quick_xml::events::{BytesStart, Event};
use crate::prelude::*;
use crate::util::xml::*;
pub const XMLNS: &'static str = "urn:ietf:params:xml:ns:xmpp-session";
#[derive(PartialEq, Eq, Debug)]
pub struct Session;
pub struct SessionParser(SessionParserInner);
enum SessionParserInner {
Initial,
InSession,
}
impl Parser for SessionParser {
type Output = Result<Session>;
fn consume<'a>(
self: Self,
namespace: quick_xml::name::ResolveResult,
event: &quick_xml::events::Event<'a>,
) -> Continuation<Self, Self::Output> {
match self.0 {
SessionParserInner::Initial => match event {
Event::Start(_) => {
Continuation::Continue(SessionParser(SessionParserInner::InSession))
}
Event::Empty(_) => Continuation::Final(Ok(Session)),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
SessionParserInner::InSession => match event {
Event::End(_) => Continuation::Final(Ok(Session)),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
}
}
}
impl FromXml for Session {
type P = SessionParser;
fn parse() -> Self::P {
SessionParser(SessionParserInner::Initial)
}
}
impl FromXmlTag for Session {
const NAME: &'static str = "session";
const NS: &'static str = XMLNS;
}
impl ToXml for Session {
fn serialize(&self, events: &mut Vec<Event<'static>>) {
events.push(Event::Empty(BytesStart::new(format!(
r#"session xmlns="{}""#,
XMLNS
))));
}
}

View File

@ -13,6 +13,11 @@ pub trait ToXml: Sized {
fn serialize(&self, events: &mut Vec<Event<'static>>); fn serialize(&self, events: &mut Vec<Event<'static>>);
} }
pub trait FromXmlTag: FromXml {
const NAME: &'static str;
const NS: &'static str;
}
pub trait Parser: Sized { pub trait Parser: Sized {
type Output; type Output;