Skip to content

Commit

Permalink
fix: A bunch of compilation errors by using Arcs
Browse files Browse the repository at this point in the history
  • Loading branch information
dbanty committed Feb 10, 2021
1 parent 2d4fe51 commit 6a995b1
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 81 deletions.
14 changes: 9 additions & 5 deletions src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::config::*;
use crate::handler::{LazyClient, RocketHandler};
use crate::handler::RocketHandler;
use lamedh_http::handler;
use lamedh_runtime::run;
use rocket::local::blocking::Client;
use rocket::Rocket;
use std::sync::Arc;

/// A builder to create and configure a [RocketHandler](RocketHandler).
pub struct RocketHandlerBuilder {
Expand Down Expand Up @@ -42,9 +44,11 @@ impl RocketHandlerBuilder {
/// run(handler(rocket_handler));
/// ```
pub fn into_handler(self) -> RocketHandler {
// TODO: Change this to async Client?
let client = Arc::new(Client::untracked(self.rocket).unwrap());
RocketHandler {
client: LazyClient::Uninitialized(self.rocket),
config: self.config,
client,
config: Arc::new(self.config),
}
}

Expand All @@ -64,8 +68,8 @@ impl RocketHandlerBuilder {
///
/// rocket::ignite().lambda().launch();
/// ```
pub fn launch(self) -> ! {
run(handler(self.into_handler()));
pub async fn launch(self) -> ! {
run(handler(self.into_handler())).await.unwrap();
unreachable!("lambda! should loop forever (or panic)")
}

Expand Down
105 changes: 35 additions & 70 deletions src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,14 @@ use lamedh_http::{Handler, Request, RequestExt, Response};
use lamedh_runtime::Context;
use rocket::http::{uri::Uri, Header};
use rocket::local::blocking::{Client, LocalRequest, LocalResponse};
use rocket::{Rocket, Route};
use std::future::Future;
use std::mem;
use std::pin::Pin;
use std::sync::Arc;

/// A Lambda handler for API Gateway events that processes requests using a [Rocket](rocket::Rocket) instance.
pub struct RocketHandler {
pub(super) client: LazyClient,
pub(super) config: Config,
}

pub(super) enum LazyClient {
Placeholder,
Uninitialized(Rocket),
Ready(Client),
pub(super) client: Arc<Client>,
pub(super) config: Arc<Config>,
}

impl Handler for RocketHandler {
Expand All @@ -29,9 +22,10 @@ impl Handler for RocketHandler {
type Fut = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + 'static>>;

fn call(&mut self, req: Request, _ctx: Context) -> Self::Fut {
self.ensure_client_ready(&req);
let client = Arc::clone(&self.client);
let config = Arc::clone(&self.config);
let fut = async {
process_request(self, req)
process_request(client, config, req)
.await
.map_err(failure::Error::from)
.map_err(failure::Error::into)
Expand All @@ -40,76 +34,47 @@ impl Handler for RocketHandler {
}
}

impl RocketHandler {
fn ensure_client_ready(&mut self, req: &Request) {
match self.client {
ref mut lazy_client @ LazyClient::Uninitialized(_) => {
let uninitialized_client = mem::replace(lazy_client, LazyClient::Placeholder);
let mut rocket = match uninitialized_client {
LazyClient::Uninitialized(rocket) => rocket,
_ => unreachable!("LazyClient must be uninitialized at this point."),
};
if self.config.base_path_behaviour == BasePathBehaviour::RemountAndInclude {
let base_path = req.base_path();
if !base_path.is_empty() {
let routes: Vec<Route> = rocket.routes().cloned().collect();
rocket = rocket.mount(&base_path, routes);
}
}
let client = Client::untracked(rocket).unwrap();
self.client = LazyClient::Ready(client);
}
LazyClient::Ready(_) => {}
LazyClient::Placeholder => panic!("LazyClient has previously begun initialiation."),
}
}

fn client(&self) -> &Client {
match &self.client {
LazyClient::Ready(client) => client,
_ => panic!("Rocket client wasn't ready. ensure_client_ready should have been called!"),
}
}

fn get_path_and_query(&self, req: &Request) -> String {
let mut uri = match self.config.base_path_behaviour {
BasePathBehaviour::Include | BasePathBehaviour::RemountAndInclude => req.full_path(),
BasePathBehaviour::Exclude => req.api_path().to_owned(),
};
let query = req.query_string_parameters();
fn get_path_and_query(config: &Config, req: &Request) -> String {
// TODO: Figure out base path behavior per request since the client doesn't have it now
let mut uri = match config.base_path_behaviour {
BasePathBehaviour::Include | BasePathBehaviour::RemountAndInclude => req.full_path(),
BasePathBehaviour::Exclude => req.api_path().to_owned(),
};
let query = req.query_string_parameters();

let mut separator = '?';
for (key, _) in query.iter() {
for value in query.get_all(key).unwrap() {
uri.push_str(&format!(
"{}{}={}",
separator,
Uri::percent_encode(key),
Uri::percent_encode(value)
));
separator = '&';
}
let mut separator = '?';
for (key, _) in query.iter() {
for value in query.get_all(key).unwrap() {
uri.push_str(&format!(
"{}{}={}",
separator,
Uri::percent_encode(key),
Uri::percent_encode(value)
));
separator = '&';
}
uri
}
uri
}

async fn process_request(
handler: &RocketHandler,
client: Arc<Client>,
config: Arc<Config>,
req: Request,
) -> Result<Response<Body>, RocketLambError> {
let local_req = create_rocket_request(handler, req)?;
let local_req = create_rocket_request(&client, Arc::clone(&config), req)?;
let local_res = local_req.dispatch();
create_lambda_response(handler, local_res).await
create_lambda_response(config, local_res).await
}

fn create_rocket_request(
handler: &RocketHandler,
client: &Client,
config: Arc<Config>,
req: Request,
) -> Result<LocalRequest, RocketLambError> {
let method = to_rocket_method(req.method())?;
let uri = handler.get_path_and_query(&req);
let mut local_req = handler.client().req(method, uri);
let uri = get_path_and_query(&config, &req);
let mut local_req = client.req(method, uri);
for (name, value) in req.headers() {
match value.to_str() {
Ok(v) => local_req.add_header(Header::new(name.to_string(), v.to_string())),
Expand All @@ -121,7 +86,7 @@ fn create_rocket_request(
}

async fn create_lambda_response(
handler: &RocketHandler,
config: Arc<Config>,
local_res: LocalResponse<'_>,
) -> Result<Response<Body>, RocketLambError> {
let mut builder = Response::builder();
Expand All @@ -136,9 +101,9 @@ async fn create_lambda_response(
.unwrap_or_default()
.split(';')
.next()
.and_then(|ct| handler.config.response_types.get(&ct.to_lowercase()))
.and_then(|ct| config.response_types.get(&ct.to_lowercase()))
.copied()
.unwrap_or(handler.config.default_response_type);
.unwrap_or(config.default_response_type);
let body = match local_res.into_bytes() {
Some(b) => match response_type {
ResponseType::Auto => match String::from_utf8(b) {
Expand Down
2 changes: 1 addition & 1 deletion tests/path_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ macro_rules! test_case {
.into_handler();

let req = get_request($file)?;
let res = handler.run(req, Context::default())?;
let res = handler.call(req, Context::default())?;

assert_eq!(res.status(), $status);
assert_eq!(*res.body(), Body::Text($path.to_string()));
Expand Down
11 changes: 6 additions & 5 deletions tests/rocket_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ extern crate rocket;

use lambda_http::{Body, Handler, Request, Response};
use lambda_runtime::Context;
use lamedh_http::Handler;
use rocket_lamb::{ResponseType, RocketExt};
use std::error::Error;
use std::fs::File;
Expand Down Expand Up @@ -43,7 +44,7 @@ fn ok_auto_text() -> Result<(), Box<dyn Error>> {
let mut handler = make_rocket().lambda().into_handler();

let req = get_request("upper")?;
let res = handler.run(req, Context::default())?;
let res = handler.call(req, Context::default())?;

assert_eq!(res.status(), 200);
assert_header(&res, "content-type", "text/plain; charset=utf-8");
Expand All @@ -56,7 +57,7 @@ fn ok_auto_binary() -> Result<(), Box<dyn Error>> {
let mut handler = make_rocket().lambda().into_handler();

let req = get_request("binary")?;
let res = handler.run(req, Context::default())?;
let res = handler.call(req, Context::default())?;

assert_eq!(res.status(), 200);
assert_header(&res, "content-type", "application/octet-stream");
Expand All @@ -72,7 +73,7 @@ fn ok_default_binary() -> Result<(), Box<dyn Error>> {
.into_handler();

let req = get_request("upper")?;
let res = handler.run(req, Context::default())?;
let res = handler.call(req, Context::default())?;

assert_eq!(res.status(), 200);
assert_header(&res, "content-type", "text/plain; charset=utf-8");
Expand All @@ -91,7 +92,7 @@ fn ok_type_binary() -> Result<(), Box<dyn Error>> {
.into_handler();

let req = get_request("upper")?;
let res = handler.run(req, Context::default())?;
let res = handler.call(req, Context::default())?;

assert_eq!(res.status(), 200);
assert_header(&res, "content-type", "text/plain; charset=utf-8");
Expand All @@ -107,7 +108,7 @@ fn request_not_found() -> Result<(), Box<dyn Error>> {
let mut handler = make_rocket().lambda().into_handler();

let req = get_request("not_found")?;
let res = handler.run(req, Context::default())?;
let res = handler.call(req, Context::default())?;

assert_eq!(res.status(), 404);
assert_eq!(res.headers().contains_key("content-type"), false);
Expand Down

0 comments on commit 6a995b1

Please sign in to comment.