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;
5use std::str::FromStr;
6use xmpp_parsers::jid::Jid;
7
8use crate::{
9 component::login::component_login,
10 connect::ServerConnector,
11 xmlstream::{Timeouts, XmppStream},
12 Error, Stanza,
13};
14
15#[cfg(any(feature = "starttls", feature = "insecure-tcp"))]
16use crate::connect::DnsConfig;
17#[cfg(feature = "insecure-tcp")]
18use crate::connect::TcpServerConnector;
19
20mod login;
21mod stream;
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 /// Send stanza
35 pub async fn send_stanza(&mut self, mut stanza: Stanza) -> Result<(), Error> {
36 stanza.ensure_id();
37 self.send(stanza).await
38 }
39
40 /// End connection
41 pub async fn send_end(&mut self) -> Result<(), Error> {
42 self.close().await
43 }
44}
45
46#[cfg(feature = "insecure-tcp")]
47impl Component<TcpServerConnector> {
48 /// Start a new XMPP component over plaintext TCP to localhost:5347
49 #[cfg(feature = "insecure-tcp")]
50 pub async fn new(jid: &str, password: &str) -> Result<Self, Error> {
51 Self::new_plaintext(
52 jid,
53 password,
54 DnsConfig::addr("127.0.0.1:5347"),
55 Timeouts::tight(),
56 )
57 .await
58 }
59
60 /// Start a new XMPP component over plaintext TCP
61 #[cfg(feature = "insecure-tcp")]
62 pub async fn new_plaintext(
63 jid: &str,
64 password: &str,
65 dns_config: DnsConfig,
66 timeouts: Timeouts,
67 ) -> Result<Self, Error> {
68 Component::new_with_connector(
69 jid,
70 password,
71 TcpServerConnector::from(dns_config),
72 timeouts,
73 )
74 .await
75 }
76}
77
78impl<C: ServerConnector> Component<C> {
79 /// Start a new XMPP component.
80 ///
81 /// Unfortunately [`StartTlsConnector`](crate::connect::StartTlsServerConnector) is not supported yet.
82 /// The tracking issue is [#143](https://gitlab.com/xmpp-rs/xmpp-rs/-/issues/143).
83 pub async fn new_with_connector(
84 jid: &str,
85 password: &str,
86 connector: C,
87 timeouts: Timeouts,
88 ) -> Result<Self, Error> {
89 let jid = Jid::from_str(jid)?;
90 let stream = component_login(connector, jid.clone(), password, timeouts).await?;
91 Ok(Component { jid, stream })
92 }
93}