-
Notifications
You must be signed in to change notification settings - Fork 258
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(shuttle-next): first edition of axum-wasm router (#472)
* feat(shuttle-next): POC of axum wasm router * feat: use std mutex * feat: serialize/deserialize http requests to rmp this serializes/deserializes http requests across the ffi to the axum-wasm router, using the rust messagepack dataformat. sending the body is still a wip * feat: serialize the full HTTP req/res to rmp * fix: comment typo * feat: start hyper with tonic and serve wasm router * feat: clone inner router arc * feat: send request body without serialization * docs: todo comment * feat: write response body * fix: serialize response parts * feat: deserialize parts directly from reader this also adds a new fd to separate streaming of body and parts * feat: add axum-wasm to runtime cli * refactor: remove unused method * refactor: typo Co-authored-by: Pieter <[email protected]> * refactor: comments, clean up wrappers * refactor: move axum-wasm utils to shuttle-common * refactor: fmt * refactor: clippy Co-authored-by: Pieter <[email protected]>
- Loading branch information
Showing
13 changed files
with
767 additions
and
65 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
use hyper::http::{HeaderMap, Method, Request, Response, StatusCode, Uri, Version}; | ||
use rmps::Serializer; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
extern crate rmp_serde as rmps; | ||
|
||
// todo: add http extensions field | ||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct RequestWrapper { | ||
#[serde(with = "http_serde::method")] | ||
pub method: Method, | ||
|
||
#[serde(with = "http_serde::uri")] | ||
pub uri: Uri, | ||
|
||
#[serde(with = "http_serde::version")] | ||
pub version: Version, | ||
|
||
#[serde(with = "http_serde::header_map")] | ||
pub headers: HeaderMap, | ||
} | ||
|
||
impl From<hyper::http::request::Parts> for RequestWrapper { | ||
fn from(parts: hyper::http::request::Parts) -> Self { | ||
RequestWrapper { | ||
method: parts.method, | ||
uri: parts.uri, | ||
version: parts.version, | ||
headers: parts.headers, | ||
} | ||
} | ||
} | ||
|
||
impl RequestWrapper { | ||
/// Serialize a RequestWrapper to the Rust MessagePack data format | ||
pub fn into_rmp(self) -> Vec<u8> { | ||
let mut buf = Vec::new(); | ||
self.serialize(&mut Serializer::new(&mut buf)).unwrap(); | ||
|
||
buf | ||
} | ||
|
||
/// Consume the wrapper and return a request builder with `Parts` set | ||
pub fn into_request_builder(self) -> hyper::http::request::Builder { | ||
let mut request = Request::builder() | ||
.method(self.method) | ||
.version(self.version) | ||
.uri(self.uri); | ||
|
||
request | ||
.headers_mut() | ||
.unwrap() | ||
.extend(self.headers.into_iter()); | ||
|
||
request | ||
} | ||
} | ||
|
||
// todo: add http extensions field | ||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct ResponseWrapper { | ||
#[serde(with = "http_serde::status_code")] | ||
pub status: StatusCode, | ||
|
||
#[serde(with = "http_serde::version")] | ||
pub version: Version, | ||
|
||
#[serde(with = "http_serde::header_map")] | ||
pub headers: HeaderMap, | ||
} | ||
|
||
impl From<hyper::http::response::Parts> for ResponseWrapper { | ||
fn from(parts: hyper::http::response::Parts) -> Self { | ||
ResponseWrapper { | ||
status: parts.status, | ||
version: parts.version, | ||
headers: parts.headers, | ||
} | ||
} | ||
} | ||
|
||
impl ResponseWrapper { | ||
/// Serialize a ResponseWrapper into the Rust MessagePack data format | ||
pub fn into_rmp(self) -> Vec<u8> { | ||
let mut buf = Vec::new(); | ||
self.serialize(&mut Serializer::new(&mut buf)).unwrap(); | ||
|
||
buf | ||
} | ||
|
||
/// Consume the wrapper and return a response builder with `Parts` set | ||
pub fn into_response_builder(self) -> hyper::http::response::Builder { | ||
let mut response = Response::builder() | ||
.status(self.status) | ||
.version(self.version); | ||
|
||
response | ||
.headers_mut() | ||
.unwrap() | ||
.extend(self.headers.into_iter()); | ||
|
||
response | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
use hyper::body::Body; | ||
use hyper::http::HeaderValue; | ||
|
||
#[test] | ||
fn request_roundtrip() { | ||
let request: Request<Body> = Request::builder() | ||
.method(Method::PUT) | ||
.version(Version::HTTP_11) | ||
.header("test", HeaderValue::from_static("request")) | ||
.uri(format!("https://axum-wasm.example/hello")) | ||
.body(Body::empty()) | ||
.unwrap(); | ||
|
||
let (parts, _) = request.into_parts(); | ||
let rmp = RequestWrapper::from(parts).into_rmp(); | ||
|
||
let back: RequestWrapper = rmps::from_slice(&rmp).unwrap(); | ||
|
||
assert_eq!( | ||
back.headers.get("test").unwrap(), | ||
HeaderValue::from_static("request") | ||
); | ||
assert_eq!(back.method, Method::PUT); | ||
assert_eq!(back.version, Version::HTTP_11); | ||
assert_eq!( | ||
back.uri.to_string(), | ||
"https://axum-wasm.example/hello".to_string() | ||
); | ||
} | ||
|
||
#[test] | ||
fn response_roundtrip() { | ||
let response: Response<Body> = Response::builder() | ||
.version(Version::HTTP_11) | ||
.header("test", HeaderValue::from_static("response")) | ||
.status(StatusCode::NOT_MODIFIED) | ||
.body(Body::empty()) | ||
.unwrap(); | ||
|
||
let (parts, _) = response.into_parts(); | ||
let rmp = ResponseWrapper::from(parts).into_rmp(); | ||
|
||
let back: ResponseWrapper = rmps::from_slice(&rmp).unwrap(); | ||
|
||
assert_eq!( | ||
back.headers.get("test").unwrap(), | ||
HeaderValue::from_static("response") | ||
); | ||
assert_eq!(back.status, StatusCode::NOT_MODIFIED); | ||
assert_eq!(back.version, Version::HTTP_11); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.