xmpp-rs/tokio-xmpp/examples/echo_bot.rs
Jonas Schäfer fc8b581593 Clean up tls-related feature flags
This provides a clear and consistent interface for selecting TLS-related
features on both (xmpp and tokio-xmpp) crates. All feature checks have
been revamped. All working combinations have been tested (including a
connectivity test + --all-features docs build) using:

```
set -xeuo pipefail
features=(aws_lc_rs ring ktls,aws_lc_rs ktls,ring aws_lc_rs,ring aws_lc_rs,ring,ktls native-tls rustls-any-backend)
export RUSTFLAGS=" -D warnings"
cargo test --no-default-features
cargo test
for feature in ${features[@]}; do
  echo ">>> BUILDING with $feature" 2>&1
  # Running code or building examples cannot succeed with rustls-any-backend.
  features="starttls,$feature"
  if [ "$feature" != 'rustls-any-backend' ]; then
    if ! cargo test --no-default-features --features="$features"; then
      echo ">>> BUILD FAILED for tls feature set: $features" >&2
      exit 1
    fi
    set +e
    timeout -sINT -p -k 2 3 cargo run --no-default-features --features="$features" --example keep_connection -- test@hub.sotecware.net "$(pass xmpp/test@hub.sotecware.net)"
    status="$?"
    set -e
    if [ $status -ne 0 ]; then
      echo ">>> keep_connection did not shut down cleanly! (status: $status)" >&2
      exit 1
    fi
  else
    if ! cargo build --no-default-features --features="$feature"; then
      echo ">>> BUILD FAILED for tls feature set: $features" >&2
      exit 1
    fi
  fi
done
RUSTDOCFLAGS="--cfg docsrs" RUSTFLAGS="--cfg xmpprs_doc_build" cargo +nightly doc -Zrustdoc-map --all-features
```
2025-05-10 22:02:39 +02:00

94 lines
3.1 KiB
Rust

use futures::stream::StreamExt;
use std::env::args;
use std::process::exit;
use std::str::FromStr;
#[cfg(feature = "rustls-any-backend")]
use tokio_xmpp::rustls;
use tokio_xmpp::Client;
use xmpp_parsers::jid::{BareJid, Jid};
use xmpp_parsers::message::{Lang, Message, MessageType};
use xmpp_parsers::presence::{Presence, Show as PresenceShow, Type as PresenceType};
#[cfg(all(
feature = "rustls-any-backend",
not(any(feature = "aws_lc_rs", feature = "ring"))
))]
compile_error!("using rustls (e.g. via the ktls feature) needs an enabled rustls backend feature (either aws_lc_rs or ring).");
#[tokio::main]
async fn main() {
env_logger::init();
#[cfg(all(feature = "aws_lc_rs", not(feature = "ring")))]
rustls::crypto::aws_lc_rs::default_provider()
.install_default()
.expect("failed to install rustls crypto provider");
#[cfg(all(feature = "ring"))]
rustls::crypto::ring::default_provider()
.install_default()
.expect("failed to install rustls crypto provider");
let args: Vec<String> = args().collect();
if args.len() != 3 {
println!("Usage: {} <jid> <password>", args[0]);
exit(1);
}
let jid = BareJid::from_str(&args[1]).expect(&format!("Invalid JID: {}", &args[1]));
let password = &args[2];
// Client instance
let mut client = Client::new(jid, password.to_owned());
// Main loop, processes events
while let Some(event) = client.next().await {
println!("event: {:?}", event);
if event.is_online() {
let jid = event
.get_jid()
.map(|jid| format!("{}", jid))
.unwrap_or("unknown".to_owned());
println!("Online at {}", jid);
let presence = make_presence();
client.send_stanza(presence.into()).await.unwrap();
} else if let Some(message) = event
.into_stanza()
.and_then(|stanza| Message::try_from(stanza).ok())
{
match (message.from, message.bodies.get("")) {
(Some(ref from), Some(body)) if body == "die" => {
println!("Secret die command triggered by {}", from);
break;
}
(Some(ref from), Some(body)) => {
if message.type_ != MessageType::Error {
// This is a message we'll echo
let reply = make_reply(from.clone(), body.to_owned());
client.send_stanza(reply.into()).await.unwrap();
}
}
_ => {}
}
}
}
client.send_end().await.unwrap();
}
// Construct a <presence/>
fn make_presence() -> Presence {
let mut presence = Presence::new(PresenceType::None);
presence.show = Some(PresenceShow::Chat);
presence
.statuses
.insert(Lang::from("en"), String::from("Echoing messages."));
presence
}
// Construct a chat <message/>
fn make_reply(to: Jid, body: String) -> Message {
let mut message = Message::new(Some(to));
message.bodies.insert(Lang::default(), body);
message
}