flyer 3.0.7

HTTP framework for rust
Documentation
use std::net::SocketAddr;
use std::sync::{Arc, LazyLock};

use anyhow::{Context, Result};
use bytes::Bytes;
use h3_quinn::quinn::crypto::rustls::QuicServerConfig;
use quinn::{Endpoint, Incoming};
use rustls::ServerConfig;

use crate::server::protocol::udp::http3::Http3;
use crate::server::protocol::{ServerHandler, UdpHandler};
use crate::server::Server;
use crate::utils::mem::Instance;

pub mod http3;

pub struct Udp;

static ALPN_PROTOCOLS: LazyLock<Vec<Vec<u8>>> = LazyLock::new(|| {
    vec![
        b"h3".to_vec(),
        b"h3-29".to_vec(),
        b"h3-32".to_vec(),
        b"h3-34".to_vec(),
    ]
});

impl ServerHandler for Udp {
    async fn listen(instance: Instance<Server>) {
        let (addr_str, server_config) = {
            let server = instance.as_ref();
            let config = match &server.server_config {
                Some(config) => config.clone(),
                None => return,
            };
            (server.address().to_string(), config)
        };

        let endpoint = match Self::get_endpoint(&addr_str, server_config) {
            Ok(ep) => ep,
            Err(err) => {
                eprintln!("Failed to bind QUIC/HTTP3 endpoint on {addr_str}: {err}");
                return;
            }
        };

        while let Some(incoming) = endpoint.accept().await {
            let instance = instance.clone();

            tokio::spawn(async move {
                if let Err(err) = Self::on_incoming(instance, incoming).await {
                    eprintln!("HTTP/3 connection error: {err}");
                }
            });
        }
    }
}

impl Udp {
    fn get_endpoint(address: &str, mut server_config: ServerConfig) -> Result<Endpoint> {
        server_config.alpn_protocols = ALPN_PROTOCOLS.clone();

        let quic_config = QuicServerConfig::try_from(server_config)
            .map_err(|e| anyhow::anyhow!("Invalid QUIC TLS config: {e}"))?;

        let quinn_config = quinn::ServerConfig::with_crypto(Arc::new(quic_config));

        let socket_addr: SocketAddr = address
            .parse()
            .with_context(|| format!("Invalid socket address: {address}"))?;

        Endpoint::server(quinn_config, socket_addr)
            .with_context(|| format!("Failed to bind UDP endpoint on {socket_addr}"))
    }

    async fn on_incoming(server: Instance<Server>, incoming: Incoming) -> Result<()> {
        let conn = incoming.await?;
        let addr = conn.remote_address();

        match h3::server::Connection::<h3_quinn::Connection, Bytes>::new(h3_quinn::Connection::new(conn)).await {
            Ok(connection) => Http3::new(server.clone(), addr).handle(connection).await,
            Err(err) => Err(err.into()),
        }
    }
}