Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
ethe authored and bobozhengsir committed Oct 25, 2023
1 parent b6fbb8d commit e06b9fc
Show file tree
Hide file tree
Showing 11 changed files with 957 additions and 9 deletions.
109 changes: 102 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ path = "src/unknown/thrift_server.rs"
name = "unknown-thrift-client"
path = "src/unknown/thrift_client.rs"

[[bin]]
name = "http"
path = "src/http/http.rs"


[dependencies]
anyhow.workspace = true
Expand All @@ -77,5 +81,11 @@ pilota.workspace = true
volo = { path = "../volo" }
volo-grpc = { path = "../volo-grpc" }
volo-thrift = { path = "../volo-thrift" }
volo-http = { path = "../volo-http" }

volo-gen = { path = "./volo-gen" }
bytes.workspace = true
http.workspace = true
hyper = { version = "1.0.0-rc.4", features = ["server", "http1", "http2"] }
motore.workspace = true
serde.workspace = true
63 changes: 63 additions & 0 deletions examples/src/http/http.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use std::{convert::Infallible, net::SocketAddr};

use bytes::Bytes;
use http::{Response, StatusCode};
use hyper::body::Incoming;
use motore::service::service_fn;
use serde::{Deserialize, Serialize};
use volo_http::{
request::Json,
route::{Route, Router},
HttpContext,
};

async fn hello(
_cx: &mut HttpContext,
_request: Incoming,
) -> Result<Response<&'static str>, Infallible> {
Ok(Response::new("hello, world"))
}

async fn echo(cx: &mut HttpContext, _request: Incoming) -> Result<Response<Bytes>, Infallible> {
if let Some(echo) = cx.params.get("echo") {
return Ok(Response::new(echo.clone()));
}
Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Bytes::new())
.unwrap())
}

#[derive(Serialize, Deserialize, Debug)]
struct Person {
name: String,
age: u8,
phones: Vec<String>,
}

async fn json(
_cx: &mut HttpContext,
Json(request): Json<Person>,
) -> Result<Response<()>, Infallible> {
let first_phone = request
.phones
.get(0)
.map(|p| p.as_str())
.unwrap_or("no number");
println!(
"{} is {} years old, {}'s first phone number is {}",
request.name, request.age, request.name, first_phone
);
Ok(Response::new(()))
}

#[tokio::main(flavor = "multi_thread")]
async fn main() {
Router::build()
.route("/", Route::builder().get(service_fn(hello)).build())
.route("/:echo", Route::builder().get(service_fn(echo)).build())
.route("/user", Route::builder().post(service_fn(json)).build())
.serve(SocketAddr::from(([127, 0, 0, 1], 3000)))
.await
.unwrap();
}
20 changes: 18 additions & 2 deletions volo-http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@ readme = "README.md"
categories = ["asynchronous", "network-programming", "web-programming"]
keywords = ["async", "http"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
hyper = { version = "1.0.0-rc.4", features = ["server", "http1", "http2"] }
tokio = { version = "1", features = ["full"] }
http-body-util = "0.1.0-rc.3"
http = { version = "0.2" }
hyper-util = { git = "https://github.com/hyperium/hyper-util.git" }
matchit = { version = "0.7" }
motore = { version = "0.3" }
tracing.workspace = true
futures-util.workspace = true
pin-project-lite = "0.2"
bytes.workspace = true
serde_json = "1"
thiserror.workspace = true
mime = "0.3"
serde = "1"

[dev-dependencies]
serde = { version = "1", features = ["derive"] }
74 changes: 74 additions & 0 deletions volo-http/src/dispatch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use std::{future::Future, marker::PhantomData};

use http::Response;
use hyper::body::Incoming;

use crate::{request::FromRequest, response::RespBody, DynError, HttpContext};

pub(crate) struct DispatchService<S, IB, OB> {
inner: S,
_marker: PhantomData<(IB, OB)>,
}

impl<S, IB, OB> DispatchService<S, IB, OB> {
pub(crate) fn new(service: S) -> Self {
Self {
inner: service,
_marker: PhantomData,
}
}
}

impl<S, IB, OB> Clone for DispatchService<S, IB, OB>
where
S: Clone,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
_marker: PhantomData,
}
}
}

unsafe impl<S, IB, OB> Send for DispatchService<S, IB, OB> where S: Send {}

unsafe impl<S, IB, OB> Sync for DispatchService<S, IB, OB> where S: Sync {}

impl<S, IB, OB> motore::Service<HttpContext, Incoming> for DispatchService<S, IB, OB>
where
S: motore::Service<HttpContext, IB, Response = Response<OB>> + Send + Sync + 'static,
S::Error: std::error::Error + Send + Sync + 'static,
OB: Into<RespBody>,
IB: FromRequest + Send,
for<'cx> <IB as FromRequest>::FromFut<'cx>: std::marker::Send,
{
type Response = Response<RespBody>;

type Error = DynError;

type Future<'cx> = impl Future<Output = Result<Self::Response, Self::Error>> + Send + 'cx
where
HttpContext: 'cx,
Self: 'cx;

fn call<'cx, 's>(&'s self, cx: &'cx mut HttpContext, req: Incoming) -> Self::Future<'cx>
where
's: 'cx,
{
async move {
match IB::from(&*cx, req).await {
Ok(body) => self
.inner
.call(cx, body)
.await
.map(|resp| {
let (parts, body) = resp.into_parts();
Response::from_parts(parts, body.into())
})
.map_err(|e| Box::new(e) as DynError),
Err(response) => Ok(response),
}
}
}
}
Loading

0 comments on commit e06b9fc

Please sign in to comment.