watermelon_mini/
lib.rs

1#![forbid(unsafe_code)]
2
3use std::sync::Arc;
4
5use rustls_platform_verifier::Verifier;
6use tokio::net::TcpStream;
7use tokio_rustls::{
8    rustls::{self, crypto::CryptoProvider, version::TLS13, ClientConfig},
9    TlsConnector,
10};
11use watermelon_net::Connection;
12use watermelon_proto::{ServerAddr, ServerInfo};
13
14#[cfg(feature = "non-standard-zstd")]
15pub use self::non_standard_zstd::ZstdStream;
16use self::proto::connect;
17pub use self::proto::{
18    AuthenticationMethod, ConnectError, ConnectionCompression, ConnectionSecurity,
19};
20
21#[cfg(feature = "non-standard-zstd")]
22pub(crate) mod non_standard_zstd;
23mod proto;
24mod util;
25
26#[derive(Debug, Clone, Default)]
27#[non_exhaustive]
28pub struct ConnectFlags {
29    pub echo: bool,
30    #[cfg(feature = "non-standard-zstd")]
31    pub zstd_compression_level: Option<u8>,
32}
33
34/// Connect to a given address with some reasonable presets.
35///
36/// The function is going to establish a TLS 1.3 connection, without the support of the client
37/// authorization.
38///
39/// # Errors
40///
41/// This returns an error in case the connection fails.
42#[expect(
43    clippy::missing_panics_doc,
44    reason = "the crypto_provider function always returns a provider that supports TLS 1.3"
45)]
46pub async fn easy_connect(
47    addr: &ServerAddr,
48    auth: Option<&AuthenticationMethod>,
49    flags: ConnectFlags,
50) -> Result<
51    (
52        Connection<
53            ConnectionCompression<ConnectionSecurity<TcpStream>>,
54            ConnectionSecurity<TcpStream>,
55        >,
56        Box<ServerInfo>,
57    ),
58    ConnectError,
59> {
60    let provider = Arc::new(crypto_provider());
61    let connector = TlsConnector::from(Arc::new(
62        ClientConfig::builder_with_provider(Arc::clone(&provider))
63            .with_protocol_versions(&[&TLS13])
64            .unwrap()
65            .dangerous()
66            .with_custom_certificate_verifier(Arc::new(Verifier::new().with_provider(provider)))
67            .with_no_client_auth(),
68    ));
69
70    let (conn, info) = connect(&connector, addr, "watermelon".to_owned(), auth, flags).await?;
71    Ok((conn, info))
72}
73
74fn crypto_provider() -> CryptoProvider {
75    #[cfg(feature = "aws-lc-rs")]
76    return rustls::crypto::aws_lc_rs::default_provider();
77    #[cfg(all(not(feature = "aws-lc-rs"), feature = "ring"))]
78    return rustls::crypto::ring::default_provider();
79    #[cfg(not(any(feature = "aws-lc-rs", feature = "ring")))]
80    compile_error!("Please enable the `aws-lc-rs` or the `ring` feature")
81}