From 4107c5b663ca8c3152ff93ccd7e766413218a841 Mon Sep 17 00:00:00 2001 From: Nikita Vilunov Date: Sun, 12 Mar 2023 13:25:23 +0100 Subject: [PATCH] feat(xmpp): answer to bind requests --- src/projections/xmpp/mod.rs | 30 ++++++++++++++++++++++-- src/protos/xmpp/bind.rs | 34 ++++++++++++++++++++++----- src/protos/xmpp/client.rs | 46 +++++++++++++++++++++++++++++++++++-- src/util/xml.rs | 4 ++++ 4 files changed, 104 insertions(+), 10 deletions(-) diff --git a/src/projections/xmpp/mod.rs b/src/projections/xmpp/mod.rs index fe5d017..286b29d 100644 --- a/src/projections/xmpp/mod.rs +++ b/src/projections/xmpp/mod.rs @@ -23,8 +23,10 @@ use crate::core::player::PlayerRegistry; use crate::core::room::RoomRegistry; use crate::prelude::*; use crate::protos::xmpp; +use crate::protos::xmpp::bind::{BindResponse, Jid, Name, Server}; +use crate::protos::xmpp::client::Iq; use crate::protos::xmpp::stream::*; -use crate::util::xml::{Continuation, FromXml, Parser}; +use crate::util::xml::{Continuation, FromXml, Parser, ToXml}; use crate::util::Terminator; #[derive(Deserialize, Debug, Clone)] @@ -277,7 +279,31 @@ async fn socket_final( match parser.consume(ns, &event) { Continuation::Final(res) => { let res = res?; - dbg!(res); + dbg!(&res); + match res { + proto::ClientPacket::Iq(iq) => match iq.body { + proto::IqClientBody::Bind(b) => { + let mut events = vec![]; + let req = Iq { + from: None, + id: iq.id, + to: None, + r#type: xmpp::client::IqType::Result, + body: BindResponse(Jid { + name: Name("darova".to_string()), + server: Server("localhost".to_string()), + resource: b.0, + }), + }; + 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!(), + } parser = proto::ClientPacket::parse(); } Continuation::Continue(p) => parser = p, diff --git a/src/protos/xmpp/bind.rs b/src/protos/xmpp/bind.rs index d8e2772..08102ad 100644 --- a/src/protos/xmpp/bind.rs +++ b/src/protos/xmpp/bind.rs @@ -1,17 +1,19 @@ use nom::AsBytes; -use quick_xml::events::Event; +use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::name::{Namespace, ResolveResult}; use crate::prelude::*; -use crate::util::xml::{Continuation, FromXml, Parser}; +use crate::util::xml::{Continuation, FromXml, Parser, ToXml}; pub const XMLNS: &'static str = "urn:ietf:params:xml:ns:xmpp-bind"; -#[derive(PartialEq, Eq, Debug)] -pub struct Name(String); +// TODO remove `pub` in newtypes, introduce validation #[derive(PartialEq, Eq, Debug)] -pub struct Server(String); +pub struct Name(pub String); + +#[derive(PartialEq, Eq, Debug)] +pub struct Server(pub String); #[derive(PartialEq, Eq, Debug)] pub struct Resource(pub(super) String); @@ -23,6 +25,12 @@ pub struct Jid { pub resource: Resource, } +impl Jid { + pub fn to_string(&self) -> String { + format!("{}@{}/{}", self.name.0, self.server.0, self.resource.0) + } +} + /// Request to bind to a resource. /// /// Example: @@ -121,7 +129,21 @@ impl Parser for BindRequestParser { } } -pub struct BindResponse(Jid); +pub struct BindResponse(pub Jid); + +impl ToXml for BindResponse { + fn serialize(&self, events: &mut Vec>) { + events.extend_from_slice(&[ + Event::Start(BytesStart::new( + r#"bind xmlns="urn:ietf:params:xml:ns:xmpp-bind""#, + )), + Event::Start(BytesStart::new(r#"jid"#)), + Event::Text(BytesText::new(self.0.to_string().as_str()).into_owned()), + Event::End(BytesEnd::new("jid")), + Event::End(BytesEnd::new("bind")), + ]); + } +} #[cfg(test)] mod tests { diff --git a/src/protos/xmpp/client.rs b/src/protos/xmpp/client.rs index 25316be..028b64d 100644 --- a/src/protos/xmpp/client.rs +++ b/src/protos/xmpp/client.rs @@ -1,6 +1,7 @@ use derive_more::From; -use quick_xml::events::Event; -use quick_xml::name::ResolveResult; +use quick_xml::events::attributes::Attribute; +use quick_xml::events::{BytesEnd, BytesStart, Event}; +use quick_xml::name::{QName, ResolveResult}; use crate::prelude::*; use crate::util::xml::*; @@ -298,6 +299,47 @@ impl IqType { t => Err(ffail!("Unknown iq type: {t}")), } } + pub fn as_str(&self) -> &'static str { + match self { + IqType::Error => "error", + IqType::Get => "get", + IqType::Result => "result", + IqType::Set => "set", + } + } +} + +impl ToXml for Iq { + fn serialize(&self, events: &mut Vec>) { + let start = format!(r#"iq xmlns="{}""#, XMLNS); + let mut start = BytesStart::new(start); + let mut attrs = vec![]; + if let Some(ref from) = self.from { + attrs.push(Attribute { + key: QName(b"from"), + value: from.as_bytes().into(), + }); + }; + if let Some(ref to) = self.to { + attrs.push(Attribute { + key: QName(b"to"), + value: to.as_bytes().into(), + }); + } + attrs.push(Attribute { + key: QName(b"id"), + value: self.id.as_bytes().into(), + }); + attrs.push(Attribute { + key: QName(b"type"), + value: self.r#type.as_str().as_bytes().into(), + }); + start.extend_attributes(attrs.into_iter()); + + events.push(Event::Start(start)); + self.body.serialize(events); + events.push(Event::End(BytesEnd::new("iq"))); + } } #[cfg(test)] diff --git a/src/util/xml.rs b/src/util/xml.rs index ad6ea3a..3e7d0de 100644 --- a/src/util/xml.rs +++ b/src/util/xml.rs @@ -9,6 +9,10 @@ pub trait FromXml: Sized { fn parse() -> Self::P; } +pub trait ToXml: Sized { + fn serialize(&self, events: &mut Vec>); +} + pub trait Parser: Sized { type Output;