spacegate-kernel 0.2.0-alpha.4

A library-first, lightweight, high-performance, cloud-native supported API gateway
Documentation
use std::{net::SocketAddr, str::FromStr, time::Duration};

use spacegate_kernel::{
    listener::SgListen,
    service::{
        http_gateway,
        http_route::{match_request::HttpPathMatchRewrite, HttpBackend, HttpRoute, HttpRouteRule},
    },
};
use tokio_rustls::rustls::ServerConfig;
use tokio_util::sync::CancellationToken;
#[tokio::test]
async fn test_https() {
    tokio::spawn(gateway());
    tokio::spawn(axum_server());
    // wait for startup
    tokio::time::sleep(Duration::from_millis(200)).await;
    let client = reqwest::Client::builder().danger_accept_invalid_certs(true).build().unwrap();
    let echo = client.post("https://[::]:9443/tls/echo").body("1").send().await.expect("fail to send").text().await.expect("fail to get text");
    println!("echo: {}", echo);
    let echo = client.get("https://[::]:9443/baidu").send().await.expect("fail to send").text().await.expect("fail to get text");
    println!("echo: {}", echo);
    let echo = client.post("http://[::]:9443/tls/echo").body("1").send().await.expect_err("should be error");
    eprintln!("echo: {}", echo);
    let echo = client.post("http://[::]:9080/tls/echo").body("1").send().await.expect("fail to send").text().await.expect("fail to get text");
    println!("echo: {}", echo);
}

async fn gateway() {
    let cancel = CancellationToken::default();
    let gateway = http_gateway::Gateway::builder("test_multi_part")
        .http_routers([(
            "test_upload".to_string(),
            HttpRoute::builder()
                .rule(HttpRouteRule::builder().match_item(HttpPathMatchRewrite::prefix("/tls")).backend(HttpBackend::builder().host("[::]").port(9003).build()).build())
                .rule(
                    HttpRouteRule::builder()
                        .match_item(HttpPathMatchRewrite::prefix("/baidu"))
                        .backend(HttpBackend::builder().schema("https").host("www.baidu.com").port(443).build())
                        .build(),
                )
                .build(),
        )])
        .build();
    let cert = include_bytes!("test_https/.cert");
    let key = include_bytes!("test_https/.key");
    let _ = tokio_rustls::rustls::crypto::ring::default_provider().install_default();
    let tls_config = ServerConfig::builder()
        .with_no_client_auth()
        .with_single_cert(
            rustls_pemfile::certs(&mut cert.as_slice()).filter_map(Result::ok).collect(),
            rustls_pemfile::private_key(&mut key.as_slice()).ok().flatten().expect("fail to get key"),
        )
        .expect("fail to build tls config");
    let http_listener = SgListen::new(SocketAddr::from_str("[::]:9080").expect("invalid host"), cancel.child_token()).with_service(gateway.as_service().http());
    let https_listener = SgListen::new(SocketAddr::from_str("[::]:9443").expect("invalid host"), cancel.child_token()).with_service(gateway.as_service().https(tls_config));
    let task = tokio::spawn(async move {
        http_listener.listen().await.expect("fail to listen");
    });
    let task_tls = tokio::spawn(async move {
        https_listener.listen().await.expect("fail to listen");
    });
    let (_, _) = tokio::join!(task, task_tls);
}

async fn axum_server() {
    use axum::{response::IntoResponse, serve, Router};
    pub async fn echo(text: String) -> impl IntoResponse {
        text
    }
    serve(
        tokio::net::TcpListener::bind("[::]:9003").await.expect("fail to bind"),
        Router::new().route("/tls/echo", axum::routing::post(echo)),
    )
    .await
    .expect("fail to serve");
}