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}