support axum instead of hyper

This commit is contained in:
Aiden McClelland
2024-01-04 13:12:08 -07:00
parent b873ef37d2
commit b2bb376853
4 changed files with 158 additions and 43 deletions

127
Cargo.lock generated
View File

@@ -123,6 +123,61 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "axum"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d09dbe0e490df5da9d69b36dca48a76635288a82f92eca90024883a56202026d"
dependencies = [
"async-trait",
"axum-core",
"bytes",
"futures-util",
"http 1.0.0",
"http-body 1.0.0",
"http-body-util",
"hyper 1.1.0",
"hyper-util",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"rustversion",
"serde",
"serde_json",
"serde_path_to_error",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "axum-core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e87c8503f93e6d144ee5690907ba22db7ba79ab001a932ab99034f0fe836b3df"
dependencies = [
"async-trait",
"bytes",
"futures-util",
"http 1.0.0",
"http-body 1.0.0",
"http-body-util",
"mime",
"pin-project-lite",
"rustversion",
"sync_wrapper",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "backtrace"
version = "0.3.69"
@@ -604,7 +659,6 @@ dependencies = [
"itoa",
"pin-project-lite",
"tokio",
"want",
]
[[package]]
@@ -620,6 +674,24 @@ dependencies = [
"tokio-native-tls",
]
[[package]]
name = "hyper-util"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdea9aac0dbe5a9240d68cfd9501e2db94222c6dc06843e06640b9e07f0fdc67"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http 1.0.0",
"http-body 1.0.0",
"hyper 1.1.0",
"pin-project-lite",
"socket2",
"tokio",
"tracing",
]
[[package]]
name = "idna"
version = "0.5.0"
@@ -744,6 +816,12 @@ version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "matchit"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
[[package]]
name = "memchr"
version = "2.7.1"
@@ -1026,11 +1104,11 @@ version = "0.2.3"
dependencies = [
"async-stream",
"async-trait",
"axum",
"clap",
"futures",
"http 1.0.0",
"http-body-util",
"hyper 1.1.0",
"imbl-value",
"itertools",
"lazy_format",
@@ -1087,6 +1165,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rustversion"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "ryu"
version = "1.0.16"
@@ -1172,6 +1256,16 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_path_to_error"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c"
dependencies = [
"itoa",
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@@ -1246,6 +1340,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "system-configuration"
version = "0.5.1"
@@ -1380,6 +1480,28 @@ dependencies = [
"tracing",
]
[[package]]
name = "tower"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
"pin-project",
"pin-project-lite",
"tokio",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
[[package]]
name = "tower-service"
version = "0.3.2"
@@ -1392,6 +1514,7 @@ version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
"log",
"pin-project-lite",
"tracing-core",
]

View File

@@ -16,13 +16,14 @@ cbor = ["serde_cbor"]
default = ["cbor"]
[dependencies]
axum = "0.7.3"
async-stream = "0.3"
async-trait = "0.1"
clap = { version = "4", features = ["derive"] }
futures = "0.3"
http = "1"
http-body-util = "0.1"
hyper = { version = "1", features = ["server", "http1", "http2", "client"] }
# hyper = { version = "1", features = ["server", "http1", "http2", "client"] }
itertools = "0.12"
imbl-value = { git = "https://github.com/Start9Labs/imbl-value.git" }
lazy_format = "2"

View File

@@ -25,7 +25,7 @@ pub use handler::*;
/// See also: [arg](rpc_toolkit_macro::arg), [context](rpc_toolkit_macro::context)
pub use rpc_toolkit_macro::command;
pub use server::*;
pub use {clap, futures, hyper, reqwest, serde, serde_json, tokio, url, yajrc};
pub use {clap, futures, reqwest, serde, serde_json, tokio, url, yajrc};
mod cli;
pub mod command_helpers;

View File

@@ -1,12 +1,14 @@
use std::any::TypeId;
use axum::body::Body;
use axum::extract::Request;
use axum::handler::Handler;
use axum::response::Response;
use futures::future::{join_all, BoxFuture};
use futures::FutureExt;
use http::header::{CONTENT_LENGTH, CONTENT_TYPE};
use http_body_util::BodyExt;
use hyper::body::{Bytes, Incoming};
use hyper::service::Service;
use hyper::{Request, Response};
use imbl_value::imbl::Vector;
use imbl_value::Value;
use serde::de::DeserializeOwned;
use serde::Serialize;
@@ -18,15 +20,15 @@ use crate::{HandleAny, Server};
const FALLBACK_ERROR: &str = "{\"error\":{\"code\":-32603,\"message\":\"Internal error\",\"data\":\"Failed to serialize rpc response\"}}";
pub fn fallback_rpc_error_response() -> Response<Bytes> {
pub fn fallback_rpc_error_response() -> Response {
Response::builder()
.header(CONTENT_TYPE, "application/json")
.header(CONTENT_LENGTH, FALLBACK_ERROR.len())
.body(Bytes::from_static(FALLBACK_ERROR.as_bytes()))
.body(Body::from(FALLBACK_ERROR.as_bytes()))
.unwrap()
}
pub fn json_http_response<T: Serialize>(t: &T) -> Response<Bytes> {
pub fn json_http_response<T: Serialize>(t: &T) -> Response {
let body = match serde_json::to_vec(t) {
Ok(a) => a,
Err(_) => return fallback_rpc_error_response(),
@@ -34,12 +36,10 @@ pub fn json_http_response<T: Serialize>(t: &T) -> Response<Bytes> {
Response::builder()
.header(CONTENT_TYPE, "application/json")
.header(CONTENT_LENGTH, body.len())
.body(Bytes::from(body))
.body(Body::from(body))
.unwrap_or_else(|_| fallback_rpc_error_response())
}
pub type BoxBody = http_body_util::combinators::BoxBody<Bytes, hyper::Error>;
#[async_trait::async_trait]
pub trait Middleware<Context: Send + 'static>: Clone + Send + Sync + 'static {
type Metadata: DeserializeOwned + Send + 'static;
@@ -47,8 +47,8 @@ pub trait Middleware<Context: Send + 'static>: Clone + Send + Sync + 'static {
async fn process_http_request(
&mut self,
context: &Context,
request: &mut Request<BoxBody>,
) -> Result<(), Response<Bytes>> {
request: &mut Request,
) -> Result<(), Response> {
Ok(())
}
#[allow(unused_variables)]
@@ -63,7 +63,7 @@ pub trait Middleware<Context: Send + 'static>: Clone + Send + Sync + 'static {
#[allow(unused_variables)]
async fn process_rpc_response(&mut self, context: &Context, response: &mut RpcResponse) {}
#[allow(unused_variables)]
async fn process_http_response(&mut self, context: &Context, response: &mut Response<Bytes>) {}
async fn process_http_response(&mut self, context: &Context, response: &mut Response) {}
}
#[allow(private_bounds)]
@@ -72,8 +72,8 @@ trait _Middleware<Context>: Send + Sync {
fn process_http_request<'a>(
&'a mut self,
context: &'a Context,
request: &'a mut Request<BoxBody>,
) -> BoxFuture<'a, Result<(), Response<Bytes>>>;
request: &'a mut Request,
) -> BoxFuture<'a, Result<(), Response>>;
fn process_rpc_request<'a>(
&'a mut self,
context: &'a Context,
@@ -89,7 +89,7 @@ trait _Middleware<Context>: Send + Sync {
fn process_http_response<'a>(
&'a mut self,
context: &'a Context,
response: &'a mut Response<Bytes>,
response: &'a mut Response,
) -> BoxFuture<'a, ()>;
}
impl<Context: Send + 'static, T: Middleware<Context> + Send + Sync> _Middleware<Context> for T {
@@ -99,8 +99,8 @@ impl<Context: Send + 'static, T: Middleware<Context> + Send + Sync> _Middleware<
fn process_http_request<'a>(
&'a mut self,
context: &'a Context,
request: &'a mut Request<BoxBody>,
) -> BoxFuture<'a, Result<(), Response<Bytes>>> {
request: &'a mut Request,
) -> BoxFuture<'a, Result<(), Response>> {
<Self as Middleware<Context>>::process_http_request(self, context, request)
}
fn process_rpc_request<'a>(
@@ -129,7 +129,7 @@ impl<Context: Send + 'static, T: Middleware<Context> + Send + Sync> _Middleware<
fn process_http_response<'a>(
&'a mut self,
context: &'a Context,
response: &'a mut Response<Bytes>,
response: &'a mut Response,
) -> BoxFuture<'a, ()> {
<Self as Middleware<Context>>::process_http_response(self, context, response)
}
@@ -144,7 +144,7 @@ impl<Context> Clone for DynMiddleware<Context> {
pub struct HttpServer<Context: crate::Context> {
inner: Server<Context>,
middleware: Vec<DynMiddleware<Context>>,
middleware: Vector<DynMiddleware<Context>>,
}
impl<Context: crate::Context> Clone for HttpServer<Context> {
fn clone(&self) -> Self {
@@ -158,7 +158,7 @@ impl<Context: crate::Context> Server<Context> {
pub fn for_http(self) -> HttpServer<Context> {
HttpServer {
inner: self,
middleware: Vec::new(),
middleware: Vector::new(),
}
}
pub fn middleware<T: Middleware<Context>>(self, middleware: T) -> HttpServer<Context> {
@@ -167,10 +167,11 @@ impl<Context: crate::Context> Server<Context> {
}
impl<Context: crate::Context> HttpServer<Context> {
pub fn middleware<T: Middleware<Context>>(mut self, middleware: T) -> Self {
self.middleware.push(DynMiddleware(Box::new(middleware)));
self.middleware
.push_back(DynMiddleware(Box::new(middleware)));
self
}
async fn process_http_request(&self, mut req: Request<BoxBody>) -> Response<Bytes> {
async fn process_http_request(&self, mut req: Request) -> Response {
let mut mid = self.middleware.clone();
match async {
let ctx = (self.inner.make_ctx)().await?;
@@ -234,7 +235,7 @@ impl<Context: crate::Context> HttpServer<Context> {
async fn process_rpc_request(
&self,
ctx: &Context,
mid: &mut Vec<DynMiddleware<Context>>,
mid: &mut Vector<DynMiddleware<Context>>,
mut req: RpcRequest,
) -> RpcResponse {
let metadata = Value::Object(
@@ -278,25 +279,15 @@ impl<Context: crate::Context> HttpServer<Context> {
}
res
}
pub fn handle(&self, req: Request<Incoming>) -> BoxFuture<'static, Response<Bytes>> {
pub fn handle(&self, req: Request) -> BoxFuture<'static, Response> {
let server = self.clone();
async move {
server
.process_http_request(req.map(|b| BoxBody::new(b)))
.await
}
.boxed()
async move { server.process_http_request(req).await }.boxed()
}
}
impl<Context: crate::Context> Service<Request<Incoming>> for HttpServer<Context> {
type Response = Response<Bytes>;
type Error = hyper::Error;
type Future = futures::future::Map<
BoxFuture<'static, Self::Response>,
fn(Self::Response) -> Result<Self::Response, Self::Error>,
>;
fn call(&self, req: Request<Incoming>) -> Self::Future {
self.handle(req).map(Ok)
impl<Context: crate::Context> Handler<(), ()> for HttpServer<Context> {
type Future = BoxFuture<'static, Response>;
fn call(self, req: Request, _: ()) -> Self::Future {
self.handle(req)
}
}