1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
mod app;
mod context;
mod cookie;
mod error;
mod http_method;
mod middleware;
mod middleware_handler;
mod request;
mod response;
//mod headers;
#[cfg(feature = "render")]
mod renderer;

pub mod default_middlewares;

pub use app::App;
pub use context::{default_context_generator, Context, DefaultContext};
pub use cookie::{Cookie, CookieOptions, SameSite};
pub use error::Error;
pub use http_method::HttpMethod;
pub use middleware::{DefaultMiddleware, Middleware, NextHandler};
pub use renderer::RenderEngine;
pub use request::Request;
pub use response::Response;

pub use handlebars;

use futures::Future;
use hyper::{
	server::conn::AddrStream,
	service::{make_service_fn, service_fn},
	Body,
	Error as HyperError,
	Request as HyperRequest,
	Response as HyperResponse,
	Server,
};
use std::{fmt::Debug, net::SocketAddr, sync::Arc};

pub async fn listen<TContext, TMiddleware, TState, TShutdownSignal>(
	app: App<TContext, TMiddleware, TState>,
	bind_addr: ([u8; 4], u16),
	shutdown_signal: Option<TShutdownSignal>,
) where
	TContext: 'static + Context + Debug + Send + Sync,
	TMiddleware: 'static + Middleware<TContext> + Clone + Send + Sync,
	TState: 'static + Send + Sync,
	TShutdownSignal: Future<Output = ()>,
{
	let bind_addr = SocketAddr::from(bind_addr);

	let app_arc = Arc::new(app);

	async move {
		let service = make_service_fn(|conn: &AddrStream| {
			let app = app_arc.clone();
			let remote_addr = conn.remote_addr();

			async move {
				Ok::<_, HyperError>(service_fn(move |req: HyperRequest<Body>| {
					let app = app.clone();
					async move {
						let request = Request::from_hyper(remote_addr, req).await;
						let mut context = app.generate_context(request);
						context.header("Server", "Eve");

						// execute app's middlewares
						let result = app.resolve(context).await;
						let response = match result {
							Ok(context) => context.take_response(),
							Err(err) => {
								// return a proper formatted error, if an error handler exists
								if app.error_handler.is_none() {
									return Ok::<_, HyperError>(HyperResponse::new(Body::from(
										err.message,
									)));
								} else {
									let response = Response::new();
									(app.error_handler.as_ref().unwrap())(response, err.error)
								}
							}
						};

						let mut hyper_response = HyperResponse::builder();

						// Set the appropriate headers
						for (key, values) in &response.headers {
							for value in values {
								hyper_response = hyper_response.header(key, value);
							}
						}

						Ok::<HyperResponse<Body>, HyperError>(
							hyper_response
								.status(response.status)
								.body(Body::from(response.body))
								.unwrap(),
						)
					}
				}))
			}
		});

		let server = Server::bind(&bind_addr).serve(service);

		if let Some(shutdown_signal) = shutdown_signal {
			server
				.with_graceful_shutdown(shutdown_signal)
				.await
				.unwrap();
		} else {
			server.await.unwrap();
		}
	}
	.await
}