forked from lavina/lavina
Compare commits
No commits in common. "dd33b41beb22a7f67a9361e2d0667d3496de2f0f" and "89918d9de1fac1e5d024af7737d3db41afa9e5ab" have entirely different histories.
dd33b41beb
...
89918d9de1
|
@ -20,8 +20,7 @@ impl<'a> XmppConnection<'a> {
|
||||||
}) = m.to
|
}) = m.to
|
||||||
{
|
{
|
||||||
if server.0.as_ref() == &*self.hostname_rooms && m.r#type == MessageType::Groupchat {
|
if server.0.as_ref() == &*self.hostname_rooms && m.r#type == MessageType::Groupchat {
|
||||||
let Some(body) = &m.body else { return Ok(()) };
|
self.user_handle.send_message(RoomId::from(name.0.clone())?, m.body.clone().into()).await?;
|
||||||
self.user_handle.send_message(RoomId::from(name.0.clone())?, body.clone()).await?;
|
|
||||||
Message::<()> {
|
Message::<()> {
|
||||||
to: Some(Jid {
|
to: Some(Jid {
|
||||||
name: Some(self.user.xmpp_name.clone()),
|
name: Some(self.user.xmpp_name.clone()),
|
||||||
|
@ -43,8 +42,7 @@ impl<'a> XmppConnection<'a> {
|
||||||
.serialize(output);
|
.serialize(output);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if server.0.as_ref() == &*self.hostname && m.r#type == MessageType::Chat {
|
} else if server.0.as_ref() == &*self.hostname && m.r#type == MessageType::Chat {
|
||||||
let Some(body) = &m.body else { return Ok(()) };
|
self.user_handle.send_dialog_message(PlayerId::from(name.0.clone())?, m.body.clone()).await?;
|
||||||
self.user_handle.send_dialog_message(PlayerId::from(name.0.clone())?, body.clone()).await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
|
|
|
@ -5,8 +5,7 @@ use quick_xml::events::Event;
|
||||||
|
|
||||||
use lavina_core::room::RoomId;
|
use lavina_core::room::RoomId;
|
||||||
use proto_xmpp::bind::{Jid, Name, Server};
|
use proto_xmpp::bind::{Jid, Name, Server};
|
||||||
use proto_xmpp::client::{Message, MessageType, Presence, Subject};
|
use proto_xmpp::client::Presence;
|
||||||
use proto_xmpp::muc::{Affiliation, Role, XUser, XUserItem};
|
|
||||||
use proto_xmpp::xml::{Ignore, ToXml};
|
use proto_xmpp::xml::{Ignore, ToXml};
|
||||||
|
|
||||||
use crate::XmppConnection;
|
use crate::XmppConnection;
|
||||||
|
@ -23,28 +22,8 @@ impl<'a> XmppConnection<'a> {
|
||||||
// resources in MUCs are members' personas – not implemented (yet?)
|
// resources in MUCs are members' personas – not implemented (yet?)
|
||||||
resource: Some(_),
|
resource: Some(_),
|
||||||
}) if server.0 == self.hostname_rooms => {
|
}) if server.0 == self.hostname_rooms => {
|
||||||
let mut response = self.muc_presence(&name).await?;
|
let response = self.muc_presence(&name).await?;
|
||||||
response.id = p.id;
|
|
||||||
let subject = Message::<()> {
|
|
||||||
from: Some(Jid {
|
|
||||||
name: Some(name),
|
|
||||||
server: Server(self.hostname_rooms.clone()),
|
|
||||||
resource: None,
|
|
||||||
}),
|
|
||||||
id: None,
|
|
||||||
to: Some(Jid {
|
|
||||||
name: Some(self.user.xmpp_name.clone()),
|
|
||||||
server: Server(self.hostname.clone()),
|
|
||||||
resource: Some(self.user.xmpp_resource.clone()),
|
|
||||||
}),
|
|
||||||
r#type: MessageType::Groupchat,
|
|
||||||
lang: None,
|
|
||||||
subject: Some(Subject(None)),
|
|
||||||
body: None,
|
|
||||||
custom: vec![],
|
|
||||||
};
|
|
||||||
response.serialize(output);
|
response.serialize(output);
|
||||||
subject.serialize(output);
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// TODO other presence cases
|
// TODO other presence cases
|
||||||
|
@ -76,17 +55,15 @@ impl<'a> XmppConnection<'a> {
|
||||||
};
|
};
|
||||||
response.serialize(output);
|
response.serialize(output);
|
||||||
}
|
}
|
||||||
e => {
|
_ => todo!(),
|
||||||
tracing::error!("TODO: unknown presence type: {e:?}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: return Presence and serialize on the outside.
|
// todo: return Presence and serialize on the outside.
|
||||||
async fn muc_presence(&mut self, name: &Name) -> Result<(Presence<XUser>)> {
|
async fn muc_presence(&mut self, name: &Name) -> Result<(Presence<()>)> {
|
||||||
let a = self.user_handle.join_room(RoomId::from(name.0.clone())?).await?;
|
let a = self.user_handle.join_room(RoomId::from(name.0.clone())?).await?;
|
||||||
// TODO handle bans
|
// TODO handle bans
|
||||||
let response = Presence {
|
let response = Presence::<()> {
|
||||||
to: Some(Jid {
|
to: Some(Jid {
|
||||||
name: Some(self.user.xmpp_name.clone()),
|
name: Some(self.user.xmpp_name.clone()),
|
||||||
server: Server(self.hostname.clone()),
|
server: Server(self.hostname.clone()),
|
||||||
|
@ -97,17 +74,6 @@ impl<'a> XmppConnection<'a> {
|
||||||
server: Server(self.hostname_rooms.clone()),
|
server: Server(self.hostname_rooms.clone()),
|
||||||
resource: Some(self.user.xmpp_muc_name.clone()),
|
resource: Some(self.user.xmpp_muc_name.clone()),
|
||||||
}),
|
}),
|
||||||
custom: vec![XUser {
|
|
||||||
item: XUserItem {
|
|
||||||
affiliation: Affiliation::Member,
|
|
||||||
role: Role::Participant,
|
|
||||||
jid: Jid {
|
|
||||||
name: Some(self.user.xmpp_name.clone()),
|
|
||||||
server: Server(self.hostname.clone()),
|
|
||||||
resource: Some(self.user.xmpp_resource.clone()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
Ok(response)
|
Ok(response)
|
||||||
|
@ -125,7 +91,6 @@ mod tests {
|
||||||
use lavina_core::player::PlayerId;
|
use lavina_core::player::PlayerId;
|
||||||
use proto_xmpp::bind::{Jid, Name, Resource, Server};
|
use proto_xmpp::bind::{Jid, Name, Resource, Server};
|
||||||
use proto_xmpp::client::Presence;
|
use proto_xmpp::client::Presence;
|
||||||
use proto_xmpp::muc::XUser;
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_muc_joining() -> Result<()> {
|
async fn test_muc_joining() -> Result<()> {
|
||||||
|
@ -145,7 +110,7 @@ mod tests {
|
||||||
let mut conn = expect_user_authenticated(&server, &user, &mut player_conn).await.unwrap();
|
let mut conn = expect_user_authenticated(&server, &user, &mut player_conn).await.unwrap();
|
||||||
|
|
||||||
let response = conn.muc_presence(&user.xmpp_name).await.unwrap();
|
let response = conn.muc_presence(&user.xmpp_name).await.unwrap();
|
||||||
let expected = Presence {
|
let expected = Presence::<()> {
|
||||||
to: Some(Jid {
|
to: Some(Jid {
|
||||||
name: Some(conn.user.xmpp_name.clone()),
|
name: Some(conn.user.xmpp_name.clone()),
|
||||||
server: Server(conn.hostname.clone()),
|
server: Server(conn.hostname.clone()),
|
||||||
|
@ -156,7 +121,6 @@ mod tests {
|
||||||
server: Server(conn.hostname_rooms.clone()),
|
server: Server(conn.hostname_rooms.clone()),
|
||||||
resource: Some(conn.user.xmpp_muc_name.clone()),
|
resource: Some(conn.user.xmpp_muc_name.clone()),
|
||||||
}),
|
}),
|
||||||
custom: vec![XUser],
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert_eq!(expected, response);
|
assert_eq!(expected, response);
|
||||||
|
@ -185,7 +149,7 @@ mod tests {
|
||||||
let mut conn = expect_user_authenticated(&server, &user, &mut player_conn).await.unwrap();
|
let mut conn = expect_user_authenticated(&server, &user, &mut player_conn).await.unwrap();
|
||||||
|
|
||||||
let response = conn.muc_presence(&user.xmpp_name).await.unwrap();
|
let response = conn.muc_presence(&user.xmpp_name).await.unwrap();
|
||||||
let expected = Presence {
|
let expected = Presence::<()> {
|
||||||
to: Some(Jid {
|
to: Some(Jid {
|
||||||
name: Some(conn.user.xmpp_name.clone()),
|
name: Some(conn.user.xmpp_name.clone()),
|
||||||
server: Server(conn.hostname.clone()),
|
server: Server(conn.hostname.clone()),
|
||||||
|
@ -196,7 +160,6 @@ mod tests {
|
||||||
server: Server(conn.hostname_rooms.clone()),
|
server: Server(conn.hostname_rooms.clone()),
|
||||||
resource: Some(conn.user.xmpp_muc_name.clone()),
|
resource: Some(conn.user.xmpp_muc_name.clone()),
|
||||||
}),
|
}),
|
||||||
custom: vec![XUser],
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert_eq!(expected, response);
|
assert_eq!(expected, response);
|
||||||
|
|
|
@ -20,8 +20,8 @@ pub struct Message<T> {
|
||||||
// default is Normal
|
// default is Normal
|
||||||
pub r#type: MessageType,
|
pub r#type: MessageType,
|
||||||
pub lang: Option<Str>,
|
pub lang: Option<Str>,
|
||||||
pub subject: Option<Subject>,
|
pub subject: Option<Str>,
|
||||||
pub body: Option<Str>,
|
pub body: Str,
|
||||||
pub custom: Vec<T>,
|
pub custom: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,20 +38,6 @@ impl<T: FromXml> FromXml for Message<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
|
||||||
pub struct Subject(pub Option<Str>);
|
|
||||||
impl ToXml for Subject {
|
|
||||||
fn serialize(&self, events: &mut Vec<Event<'static>>) {
|
|
||||||
if let Some(ref s) = self.0 {
|
|
||||||
events.push(Event::Start(BytesStart::new("subject")));
|
|
||||||
events.push(Event::Text(BytesText::new(s).into_owned()));
|
|
||||||
events.push(Event::End(BytesEnd::new("subject")));
|
|
||||||
} else {
|
|
||||||
events.push(Event::Empty(BytesStart::new("subject")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(From)]
|
#[derive(From)]
|
||||||
struct MessageParser<T: FromXml>(MessageParserInner<T>);
|
struct MessageParser<T: FromXml>(MessageParserInner<T>);
|
||||||
|
|
||||||
|
@ -71,7 +57,7 @@ struct MessageParserState<T> {
|
||||||
to: Option<Jid>,
|
to: Option<Jid>,
|
||||||
r#type: MessageType,
|
r#type: MessageType,
|
||||||
lang: Option<Str>,
|
lang: Option<Str>,
|
||||||
subject: Option<Subject>,
|
subject: Option<Str>,
|
||||||
body: Option<Str>,
|
body: Option<Str>,
|
||||||
custom: Vec<T>,
|
custom: Vec<T>,
|
||||||
}
|
}
|
||||||
|
@ -144,7 +130,7 @@ impl<T: FromXml> Parser for MessageParser<T> {
|
||||||
r#type: state.r#type,
|
r#type: state.r#type,
|
||||||
lang: state.lang,
|
lang: state.lang,
|
||||||
subject: state.subject,
|
subject: state.subject,
|
||||||
body: Some(body),
|
body,
|
||||||
custom: state.custom,
|
custom: state.custom,
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
|
@ -167,7 +153,7 @@ impl<T: FromXml> Parser for MessageParser<T> {
|
||||||
InSubject(mut state) => match event {
|
InSubject(mut state) => match event {
|
||||||
Event::Text(ref bytes) => {
|
Event::Text(ref bytes) => {
|
||||||
let subject = fail_fast!(std::str::from_utf8(&*bytes));
|
let subject = fail_fast!(std::str::from_utf8(&*bytes));
|
||||||
state.subject = Some(Subject(Some(subject.into())));
|
state.subject = Some(subject.into());
|
||||||
Continuation::Continue(InSubject(state).into())
|
Continuation::Continue(InSubject(state).into())
|
||||||
}
|
}
|
||||||
Event::End(_) => Continuation::Continue(Outer(state).into()),
|
Event::End(_) => Continuation::Continue(Outer(state).into()),
|
||||||
|
@ -222,14 +208,9 @@ impl<T: ToXml> ToXml for Message<T> {
|
||||||
value: self.r#type.as_str().as_bytes().into(),
|
value: self.r#type.as_str().as_bytes().into(),
|
||||||
});
|
});
|
||||||
events.push(Event::Start(bytes));
|
events.push(Event::Start(bytes));
|
||||||
if let Some(subject) = &self.subject {
|
events.push(Event::Start(BytesStart::new("body")));
|
||||||
subject.serialize(events);
|
events.push(Event::Text(BytesText::new(&self.body).into_owned()));
|
||||||
}
|
events.push(Event::End(BytesEnd::new("body")));
|
||||||
if let Some(body) = &self.body {
|
|
||||||
events.push(Event::Start(BytesStart::new("body")));
|
|
||||||
events.push(Event::Text(BytesText::new(body).into_owned()));
|
|
||||||
events.push(Event::End(BytesEnd::new("body")));
|
|
||||||
}
|
|
||||||
events.push(Event::End(BytesEnd::new("message")));
|
events.push(Event::End(BytesEnd::new("message")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -506,7 +487,6 @@ impl<T: ToXml> ToXml for Iq<T> {
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub struct Presence<T> {
|
pub struct Presence<T> {
|
||||||
pub id: Option<String>,
|
|
||||||
pub to: Option<Jid>,
|
pub to: Option<Jid>,
|
||||||
pub from: Option<Jid>,
|
pub from: Option<Jid>,
|
||||||
pub priority: Option<PresencePriority>,
|
pub priority: Option<PresencePriority>,
|
||||||
|
@ -519,7 +499,6 @@ pub struct Presence<T> {
|
||||||
impl<T> Default for Presence<T> {
|
impl<T> Default for Presence<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: Default::default(),
|
|
||||||
to: Default::default(),
|
to: Default::default(),
|
||||||
from: Default::default(),
|
from: Default::default(),
|
||||||
priority: Default::default(),
|
priority: Default::default(),
|
||||||
|
@ -594,10 +573,6 @@ impl<T: FromXml> FromXml for Presence<T> {
|
||||||
let s = std::str::from_utf8(&attr.value)?;
|
let s = std::str::from_utf8(&attr.value)?;
|
||||||
p.r#type = Some(s.into());
|
p.r#type = Some(s.into());
|
||||||
}
|
}
|
||||||
b"id" => {
|
|
||||||
let s = std::str::from_utf8(&attr.value)?;
|
|
||||||
p.id = Option::from(s.to_string());
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -685,12 +660,6 @@ impl<T: ToXml> ToXml for Presence<T> {
|
||||||
value: from.to_string().as_bytes().into(),
|
value: from.to_string().as_bytes().into(),
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
if let Some(ref id) = self.id {
|
|
||||||
start.extend_attributes([Attribute {
|
|
||||||
key: QName(b"id"),
|
|
||||||
value: id.to_string().as_bytes().into(),
|
|
||||||
}]);
|
|
||||||
}
|
|
||||||
events.push(Event::Start(start));
|
events.push(Event::Start(start));
|
||||||
if let Some(ref priority) = self.priority {
|
if let Some(ref priority) = self.priority {
|
||||||
let s = priority.0.to_string();
|
let s = priority.0.to_string();
|
||||||
|
@ -700,9 +669,6 @@ impl<T: ToXml> ToXml for Presence<T> {
|
||||||
Event::End(BytesEnd::new("priority")),
|
Event::End(BytesEnd::new("priority")),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
for c in &self.custom {
|
|
||||||
c.serialize(events);
|
|
||||||
}
|
|
||||||
events.push(Event::End(BytesEnd::new("presence")));
|
events.push(Event::End(BytesEnd::new("presence")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
#![allow(unused_variables)]
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
use quick_xml::events::{BytesEnd, BytesStart, Event};
|
use quick_xml::events::Event;
|
||||||
use quick_xml::name::ResolveResult;
|
use quick_xml::name::ResolveResult;
|
||||||
|
|
||||||
use crate::bind::Jid;
|
|
||||||
use crate::xml::*;
|
use crate::xml::*;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
pub const XMLNS: &'static str = "http://jabber.org/protocol/muc";
|
pub const XMLNS: &'static str = "http://jabber.org/protocol/muc";
|
||||||
pub const XMLNS_USER: &'static str = "http://jabber.org/protocol/muc#user";
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Default)]
|
#[derive(PartialEq, Eq, Debug, Default)]
|
||||||
pub struct History {
|
pub struct History {
|
||||||
|
@ -145,95 +143,6 @@ impl FromXml for X {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub struct XUser {
|
|
||||||
pub item: XUserItem,
|
|
||||||
}
|
|
||||||
impl ToXml for XUser {
|
|
||||||
fn serialize(&self, output: &mut Vec<Event<'static>>) {
|
|
||||||
let mut tag = BytesStart::new("x");
|
|
||||||
tag.push_attribute(("xmlns", XMLNS_USER));
|
|
||||||
output.push(Event::Start(tag));
|
|
||||||
self.item.serialize(output);
|
|
||||||
output.push(Event::End(BytesEnd::new("x")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub struct XUserItem {
|
|
||||||
pub affiliation: Affiliation,
|
|
||||||
pub jid: Jid,
|
|
||||||
pub role: Role,
|
|
||||||
}
|
|
||||||
impl ToXml for XUserItem {
|
|
||||||
fn serialize(&self, output: &mut Vec<Event<'static>>) {
|
|
||||||
let mut meg = BytesStart::new("item");
|
|
||||||
meg.push_attribute(("affiliation", self.affiliation.to_str()));
|
|
||||||
meg.push_attribute(("role", self.role.to_str()));
|
|
||||||
meg.push_attribute(("jid", self.jid.to_string().as_str()));
|
|
||||||
output.push(Event::Empty(meg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub enum Affiliation {
|
|
||||||
Owner,
|
|
||||||
Admin,
|
|
||||||
Member,
|
|
||||||
Outcast,
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
impl Affiliation {
|
|
||||||
pub fn from_str(s: &str) -> Option<Self> {
|
|
||||||
match s {
|
|
||||||
"owner" => Some(Self::Owner),
|
|
||||||
"admin" => Some(Self::Admin),
|
|
||||||
"member" => Some(Self::Member),
|
|
||||||
"outcast" => Some(Self::Outcast),
|
|
||||||
"none" => Some(Self::None),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Owner => "owner",
|
|
||||||
Self::Admin => "admin",
|
|
||||||
Self::Member => "member",
|
|
||||||
Self::Outcast => "outcast",
|
|
||||||
Self::None => "none",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub enum Role {
|
|
||||||
Moderator,
|
|
||||||
Participant,
|
|
||||||
Visitor,
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
impl Role {
|
|
||||||
pub fn from_str(s: &str) -> Option<Self> {
|
|
||||||
match s {
|
|
||||||
"moderator" => Some(Self::Moderator),
|
|
||||||
"participant" => Some(Self::Participant),
|
|
||||||
"visitor" => Some(Self::Visitor),
|
|
||||||
"none" => Some(Self::None),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Moderator => "moderator",
|
|
||||||
Self::Participant => "participant",
|
|
||||||
Self::Visitor => "visitor",
|
|
||||||
Self::None => "none",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Reference in New Issue