forked from lavina/lavina
feat(xmpp): presence parsing
This commit is contained in:
parent
6add6db371
commit
1cc4761aeb
|
@ -23,8 +23,8 @@ 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::bind::{BindResponse, Jid, Name, Resource, Server};
|
||||
use crate::protos::xmpp::client::{Iq, Presence};
|
||||
use crate::protos::xmpp::roster::RosterQuery;
|
||||
use crate::protos::xmpp::session::Session;
|
||||
use crate::protos::xmpp::stream::*;
|
||||
|
@ -294,7 +294,7 @@ async fn socket_final(
|
|||
body: BindResponse(Jid {
|
||||
name: Name("darova".to_string()),
|
||||
server: Server("localhost".to_string()),
|
||||
resource: b.0,
|
||||
resource: Resource("kek".to_string()),
|
||||
}),
|
||||
};
|
||||
req.serialize(&mut events);
|
||||
|
@ -335,6 +335,19 @@ async fn socket_final(
|
|||
}
|
||||
},
|
||||
proto::ClientPacket::Message(_) => todo!(),
|
||||
proto::ClientPacket::Presence(p) => {
|
||||
let mut events = vec![];
|
||||
let response = Presence {
|
||||
to: Some("darova@localhost/kek".to_string()),
|
||||
from: Some("darova@localhost/kek".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
response.serialize(&mut events);
|
||||
for i in events {
|
||||
xml_writer.write_event_async(i).await?;
|
||||
}
|
||||
xml_writer.get_mut().flush().await?;
|
||||
}
|
||||
}
|
||||
parser = proto::ClientPacket::parse();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use quick_xml::events::Event;
|
|||
use quick_xml::name::{Namespace, ResolveResult};
|
||||
|
||||
use crate::protos::xmpp::bind::BindRequest;
|
||||
use crate::protos::xmpp::client::{Iq, Message};
|
||||
use crate::protos::xmpp::client::{Iq, Message, Presence};
|
||||
use crate::protos::xmpp::roster::RosterQuery;
|
||||
use crate::protos::xmpp::session::Session;
|
||||
use crate::util::xml::*;
|
||||
|
@ -72,6 +72,7 @@ impl Parser for IqClientBodyParser {
|
|||
pub enum ClientPacket {
|
||||
Iq(Iq<IqClientBody>),
|
||||
Message(Message),
|
||||
Presence(Presence),
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
|
@ -88,8 +89,9 @@ impl FromXml for ClientPacket {
|
|||
#[derive(From)]
|
||||
enum ClientPacketParserInner {
|
||||
Initial,
|
||||
Iq(<Iq<IqClientBody> as FromXml>::P),
|
||||
Message(<Message as FromXml>::P),
|
||||
IqV(<Iq<IqClientBody> as FromXml>::P),
|
||||
MessageV(<Message as FromXml>::P),
|
||||
PresenceV(<Presence as FromXml>::P),
|
||||
}
|
||||
|
||||
impl Parser for ClientPacketParser {
|
||||
|
@ -100,7 +102,7 @@ impl Parser for ClientPacketParser {
|
|||
namespace: ResolveResult,
|
||||
event: &Event<'a>,
|
||||
) -> Continuation<Self, Self::Output> {
|
||||
use ClientPacketParserInner::{Initial, Iq as IqV, Message as MessageV};
|
||||
use ClientPacketParserInner::*;
|
||||
match self.0 {
|
||||
Initial => {
|
||||
let Event::Start(bytes) = event else {
|
||||
|
@ -109,11 +111,13 @@ impl Parser for ClientPacketParser {
|
|||
let name = bytes.name();
|
||||
match_parser!(ClientPacketParser, name, namespace, event;
|
||||
Iq::<IqClientBody>,
|
||||
Presence,
|
||||
Message
|
||||
)
|
||||
}
|
||||
IqV(p) => delegate_parsing!(p, ClientPacketParserInner, namespace, event),
|
||||
MessageV(p) => delegate_parsing!(p, ClientPacketParserInner, namespace, event),
|
||||
PresenceV(p) => delegate_parsing!(p, ClientPacketParserInner, namespace, event),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ pub struct Name(pub String);
|
|||
pub struct Server(pub String);
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub struct Resource(pub(super) String);
|
||||
pub struct Resource(pub String);
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub struct Jid {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use derive_more::From;
|
||||
use quick_xml::events::attributes::Attribute;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, Event};
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
|
||||
use quick_xml::name::{QName, ResolveResult};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
@ -342,6 +342,198 @@ impl<T: ToXml> ToXml for Iq<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Default)]
|
||||
pub struct Presence {
|
||||
pub to: Option<String>,
|
||||
pub from: Option<String>,
|
||||
pub priority: Option<PresencePriority>,
|
||||
pub show: Option<PresenceShow>,
|
||||
pub status: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum PresenceShow {
|
||||
Away,
|
||||
Chat,
|
||||
Dnd,
|
||||
Xa,
|
||||
}
|
||||
|
||||
/// Presence priority is an integer number in range [-128; 127].
|
||||
///
|
||||
/// Presence priority < 0 means that the bound resource will never be chosen unless it was asked for specifically.
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub struct PresencePriority(pub i8);
|
||||
|
||||
impl PresenceShow {
|
||||
pub fn from_str(s: &[u8]) -> Result<Self> {
|
||||
use PresenceShow::*;
|
||||
let s = std::str::from_utf8(s)?;
|
||||
match s {
|
||||
"away" => Ok(Away),
|
||||
"chat" => Ok(Chat),
|
||||
"dnd" => Ok(Dnd),
|
||||
"xa" => Ok(Xa),
|
||||
t => Err(ffail!("Unknown presence show type: {t}")),
|
||||
}
|
||||
}
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
use PresenceShow::*;
|
||||
match self {
|
||||
Away => "away",
|
||||
Chat => "chat",
|
||||
Dnd => "dnd",
|
||||
Xa => "xa",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
pub struct PresenceParser(PresenceParserInner);
|
||||
enum PresenceParserInner {
|
||||
Initial,
|
||||
InPresence(Presence),
|
||||
InPriority(Presence),
|
||||
InPriorityEnd(Presence),
|
||||
InShow(Presence),
|
||||
InShowEnd(Presence),
|
||||
InStatus(Presence),
|
||||
InStatusEnd(Presence),
|
||||
}
|
||||
|
||||
impl Parser for PresenceParser {
|
||||
type Output = Result<Presence>;
|
||||
|
||||
fn consume<'a>(
|
||||
self: Self,
|
||||
namespace: ResolveResult,
|
||||
event: &Event<'a>,
|
||||
) -> Continuation<Self, Self::Output> {
|
||||
match self.0 {
|
||||
PresenceParserInner::Initial => match event {
|
||||
//TODO validate
|
||||
Event::Start(bytes) => Continuation::Continue(
|
||||
PresenceParserInner::InPresence(Presence::default()).into(),
|
||||
),
|
||||
Event::Empty(bytes) => Continuation::Final(Ok(Presence::default())),
|
||||
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
|
||||
},
|
||||
PresenceParserInner::InPresence(p) => match event {
|
||||
Event::Start(bytes) => match bytes.name().0 {
|
||||
b"show" => Continuation::Continue(PresenceParserInner::InShow(p).into()),
|
||||
b"status" => Continuation::Continue(PresenceParserInner::InStatus(p).into()),
|
||||
b"priority" => {
|
||||
Continuation::Continue(PresenceParserInner::InPriority(p).into())
|
||||
}
|
||||
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
|
||||
},
|
||||
Event::End(_) => Continuation::Final(Ok(p)),
|
||||
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
|
||||
},
|
||||
PresenceParserInner::InPriority(p) => match event {
|
||||
Event::Text(bytes) => {
|
||||
match (|| {
|
||||
let s = std::str::from_utf8(bytes)?;
|
||||
let i = s.parse()?;
|
||||
Ok(Presence {
|
||||
priority: Some(PresencePriority(i)),
|
||||
..p
|
||||
})
|
||||
})() {
|
||||
Ok(res) => {
|
||||
Continuation::Continue(PresenceParserInner::InPriorityEnd(res).into())
|
||||
}
|
||||
Err(e) => Continuation::Final(Err(e)),
|
||||
}
|
||||
}
|
||||
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
|
||||
},
|
||||
PresenceParserInner::InPriorityEnd(p) => match event {
|
||||
Event::End(_) => Continuation::Continue(PresenceParserInner::InPresence(p).into()),
|
||||
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
|
||||
},
|
||||
PresenceParserInner::InShow(p) => match event {
|
||||
Event::Text(bytes) => {
|
||||
match (|| {
|
||||
let i = PresenceShow::from_str(bytes)?;
|
||||
Ok(Presence { show: Some(i), ..p })
|
||||
})() {
|
||||
Ok(res) => {
|
||||
Continuation::Continue(PresenceParserInner::InShowEnd(res).into())
|
||||
}
|
||||
Err(e) => Continuation::Final(Err(e)),
|
||||
}
|
||||
}
|
||||
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
|
||||
},
|
||||
PresenceParserInner::InShowEnd(p) => match event {
|
||||
Event::End(_) => Continuation::Continue(PresenceParserInner::InPresence(p).into()),
|
||||
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
|
||||
},
|
||||
PresenceParserInner::InStatus(mut p) => match event {
|
||||
Event::Text(bytes) => {
|
||||
match (|| {
|
||||
let i = std::str::from_utf8(bytes)?;
|
||||
p.status.push(i.to_string());
|
||||
Ok(p)
|
||||
})() {
|
||||
Ok(res) => {
|
||||
Continuation::Continue(PresenceParserInner::InStatusEnd(res).into())
|
||||
}
|
||||
Err(e) => Continuation::Final(Err(e)),
|
||||
}
|
||||
}
|
||||
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
|
||||
},
|
||||
PresenceParserInner::InStatusEnd(p) => match event {
|
||||
Event::End(_) => Continuation::Continue(PresenceParserInner::InPresence(p).into()),
|
||||
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromXml for Presence {
|
||||
type P = PresenceParser;
|
||||
|
||||
fn parse() -> Self::P {
|
||||
PresenceParserInner::Initial.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromXmlTag for Presence {
|
||||
const NAME: &'static str = "presence";
|
||||
const NS: &'static str = XMLNS;
|
||||
}
|
||||
|
||||
impl ToXml for Presence {
|
||||
fn serialize(&self, events: &mut Vec<Event<'static>>) {
|
||||
let mut start = BytesStart::new("presence");
|
||||
if let Some(ref to) = self.to {
|
||||
start.extend_attributes([Attribute {
|
||||
key: QName(b"to"),
|
||||
value: to.as_bytes().into(),
|
||||
}]);
|
||||
}
|
||||
if let Some(ref from) = self.from {
|
||||
start.extend_attributes([Attribute {
|
||||
key: QName(b"from"),
|
||||
value: from.as_bytes().into(),
|
||||
}]);
|
||||
}
|
||||
events.push(Event::Start(start));
|
||||
if let Some(ref priority) = self.priority {
|
||||
let s = priority.0.to_string();
|
||||
events.extend_from_slice(&[
|
||||
Event::Start(BytesStart::new(r#"priority"#)),
|
||||
Event::Text(BytesText::new(s.as_str()).into_owned()),
|
||||
Event::End(BytesEnd::new("priority")),
|
||||
]);
|
||||
}
|
||||
events.push(Event::End(BytesEnd::new("presence")));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::protos::xmpp::bind::{BindRequest, Resource};
|
||||
|
|
Loading…
Reference in New Issue