mod.rs

  1//! Components in XMPP are services/gateways that are logged into an
  2//! XMPP server under a JID consisting of just a domain name. They are
  3//! allowed to use any user and resource identifiers in their stanzas.
  4use futures::{sink::SinkExt, task::Poll, Sink, Stream};
  5use minidom::Element;
  6use std::pin::Pin;
  7use std::str::FromStr;
  8use std::task::Context;
  9use xmpp_parsers::{jid::Jid, ns};
 10
 11use self::connect::component_login;
 12
 13use super::xmpp_codec::Packet;
 14use super::Error;
 15use crate::connect::ServerConnector;
 16use crate::xmpp_stream::add_stanza_id;
 17use crate::xmpp_stream::XMPPStream;
 18
 19mod auth;
 20
 21pub(crate) mod connect;
 22
 23/// Component connection to an XMPP server
 24///
 25/// This simplifies the `XMPPStream` to a `Stream`/`Sink` of `Element`
 26/// (stanzas). Connection handling however is up to the user.
 27pub struct Component<C: ServerConnector> {
 28    /// The component's Jabber-Id
 29    pub jid: Jid,
 30    stream: XMPPStream<C::Stream>,
 31}
 32
 33impl<C: ServerConnector> Component<C> {
 34    /// Start a new XMPP component
 35    pub async fn new_with_connector(
 36        jid: &str,
 37        password: &str,
 38        connector: C,
 39    ) -> Result<Self, Error> {
 40        let jid = Jid::from_str(jid)?;
 41        let password = password.to_owned();
 42        let stream = component_login(connector, jid.clone(), password).await?;
 43        Ok(Component { jid, stream })
 44    }
 45
 46    /// Send stanza
 47    pub async fn send_stanza(&mut self, stanza: Element) -> Result<(), Error> {
 48        self.send(add_stanza_id(stanza, ns::COMPONENT_ACCEPT)).await
 49    }
 50
 51    /// End connection
 52    pub async fn send_end(&mut self) -> Result<(), Error> {
 53        self.close().await
 54    }
 55}
 56
 57impl<C: ServerConnector> Stream for Component<C> {
 58    type Item = Element;
 59
 60    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
 61        loop {
 62            match Pin::new(&mut self.stream).poll_next(cx) {
 63                Poll::Ready(Some(Ok(Packet::Stanza(stanza)))) => return Poll::Ready(Some(stanza)),
 64                Poll::Ready(Some(Ok(Packet::Text(_)))) => {
 65                    // retry
 66                }
 67                Poll::Ready(Some(Ok(_))) =>
 68                // unexpected
 69                {
 70                    return Poll::Ready(None)
 71                }
 72                Poll::Ready(Some(Err(_))) => return Poll::Ready(None),
 73                Poll::Ready(None) => return Poll::Ready(None),
 74                Poll::Pending => return Poll::Pending,
 75            }
 76        }
 77    }
 78}
 79
 80impl<C: ServerConnector> Sink<Element> for Component<C> {
 81    type Error = Error;
 82
 83    fn start_send(mut self: Pin<&mut Self>, item: Element) -> Result<(), Self::Error> {
 84        Pin::new(&mut self.stream)
 85            .start_send(Packet::Stanza(item))
 86            .map_err(|e| e.into())
 87    }
 88
 89    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
 90        Pin::new(&mut self.stream)
 91            .poll_ready(cx)
 92            .map_err(|e| e.into())
 93    }
 94
 95    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
 96        Pin::new(&mut self.stream)
 97            .poll_flush(cx)
 98            .map_err(|e| e.into())
 99    }
100
101    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
102        Pin::new(&mut self.stream)
103            .poll_close(cx)
104            .map_err(|e| e.into())
105    }
106}