#![allow(clippy::manual_async_fn)]
use std::future::Future;
use std::net::ToSocketAddrs;
use std::pin::Pin;
use std::sync::{Arc, OnceLock};
use ringline::{AsyncEventHandler, ConfigBuilder, ConnCtx, RinglineBuilder, TlsClientConfig};
#[derive(Debug)]
struct Target {
addr: std::net::SocketAddr,
host: String,
path: String,
}
static TARGET: OnceLock<Target> = OnceLock::new();
struct HttpHandler;
impl AsyncEventHandler for HttpHandler {
fn on_accept(&self, _conn: ConnCtx) -> impl Future<Output = ()> + 'static {
async {}
}
fn on_start(&self) -> Option<Pin<Box<dyn Future<Output = ()> + 'static>>> {
Some(Box::pin(async move {
let target = TARGET.get().unwrap();
eprintln!("connecting to {} (HTTP/2)...", target.host);
let result = async {
let mut client =
ringline_http::HttpClient::connect_h2(target.addr, &target.host).await?;
let resp = client
.get(&target.path)
.header("user-agent", "ringline-http/example")
.send()
.await?;
Ok::<_, ringline_http::HttpError>(resp)
}
.await;
match result {
Ok(resp) => {
eprintln!("HTTP/2 {} — {} bytes", resp.status(), resp.body().len());
}
Err(e) => {
eprintln!("error: {e}");
}
}
ringline::request_shutdown().ok();
}))
}
fn create_for_worker(_id: usize) -> Self {
HttpHandler
}
}
fn main() {
let url = std::env::args()
.nth(1)
.unwrap_or_else(|| "https://www.example.com/".to_string());
let without_scheme = url
.strip_prefix("https://")
.expect("only https:// URLs supported");
let (host_port, path) = without_scheme
.split_once('/')
.map(|(h, p)| (h, format!("/{p}")))
.unwrap_or((without_scheme, "/".to_string()));
let host = host_port.split(':').next().unwrap().to_string();
let port: u16 = host_port
.split(':')
.nth(1)
.and_then(|p| p.parse().ok())
.unwrap_or(443);
let addr = format!("{host}:{port}")
.to_socket_addrs()
.expect("DNS resolution failed")
.next()
.expect("no addresses found");
TARGET.set(Target { addr, host, path }).unwrap();
let mut roots = rustls::RootCertStore::empty();
roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
let mut tls = rustls::ClientConfig::builder()
.with_root_certificates(roots)
.with_no_client_auth();
tls.alpn_protocols = vec![b"h2".to_vec()];
let config = ConfigBuilder::new()
.workers(1)
.pin_to_core(false)
.tls_client(TlsClientConfig::new(Arc::new(tls)))
.build()
.expect("valid config");
let (_shutdown, handles) = RinglineBuilder::new(config)
.launch::<HttpHandler>()
.expect("launch failed");
for h in handles {
h.join().unwrap().unwrap();
}
}