use std::str::FromStr; use std::convert::TryFrom; use futures::{SinkExt, StreamExt}; use tokio::sync::mpsc; use tokio_xmpp::{AsyncClient, Packet, Event}; use xmpp_parsers::{Jid, BareJid, FullJid, Element}; use xmpp_parsers::message::{Body, Message, MessageType}; use xmpp_parsers::presence::{Presence, Show as PresenceShow, Type as PresenceType}; use xmpp_parsers::muc::Muc; #[derive(Clone)] pub struct Handle { room_jid: BareJid, tx: mpsc::Sender, } impl Handle { pub async fn send_message(&self, msg: String) { let stanza = make_room_message(self.room_jid.clone(), msg); self.tx.send(Packet::Stanza(stanza)).await.unwrap(); } } pub async fn run(jid: String, password: String, muc_jid: String) -> Handle { let muc_jid: FullJid = match FullJid::from_str(&muc_jid) { Ok(jid) => jid, Err(err) => panic!("MUC Jid invalid: {:?}", err), }; let (tx, mut rx) = mpsc::channel(1); let handle = Handle { room_jid: muc_jid.clone().into(), tx: tx.clone(), }; let mut client = AsyncClient::new(&jid, &password).unwrap(); loop { match client.next().await { Some(Event::Online { .. }) => { println!("XMPP client now online at {}", jid); let packet = Packet::Stanza(make_join_presence(muc_jid.clone())); client.send(packet).await .unwrap(); break; } Some(_) => {} None => panic!("XMPP cannot connect"), } } let (mut sink, mut stream) = client.split(); tokio::task::spawn_local(async move { while let Some(event) = stream.next().await { match event { Event::Stanza(el) => { if el.is("presence", "jabber:client") { match Presence::try_from(el) { Ok(presence) => { if presence.from == Some(Jid::Full(muc_jid.clone())) { if presence.type_ == PresenceType::Error { println!("Failed to enter MUC {:?}", muc_jid); } else { println!("Entered MUC {:?}", muc_jid); } } }, Err(err) => println!("Received invalid presence: {:?}", err), } } } _ => {} } } panic!("XMPP end") }); tokio::task::spawn_local(async move { while let Some(packet) = rx.recv().await { sink.send(packet).await.unwrap(); } panic!("channel end") }); handle } pub fn make_room_message(room_jid: BareJid, text: String) -> Element { let mut message = Message::new(Some(Jid::Bare(room_jid))); message.type_ = MessageType::Groupchat; message.bodies.insert("de".to_string(), Body(text)); message.into() } fn make_join_presence(muc_jid: FullJid) -> Element { let mut presence = Presence::new(PresenceType::None) .with_to(Jid::Full(muc_jid)) .with_show(PresenceShow::Dnd); presence.set_status("de".to_string(), "Augen und Ohren nach oben".to_string()); presence.add_payload(Muc::new()); presence.into() }