use crate::api_error::{ApiError, ApiResult}; use crate::rest_api::Context; use hyper::{Body, Request, Response, StatusCode}; use serde::Serialize; use std::sync::Arc; use types::EthSpec; /// Provides a HTTP request handler with specific functionality. pub struct Handler { req: Request<()>, body: Body, ctx: Arc>, allow_body: bool, } impl Handler { /// Start handling a new request. pub fn new(req: Request, ctx: Arc>) -> Result { let (req_parts, body) = req.into_parts(); let req = Request::from_parts(req_parts, ()); Ok(Self { req, body, ctx, allow_body: false, }) } /// Return a simple static value. /// /// Does not use the blocking executor. pub async fn static_value(self, value: V) -> Result, ApiError> { // Always check and disallow a body for a static value. let _ = Self::get_body(self.body, false).await?; Ok(HandledRequest { value }) } /// The default behaviour is to return an error if any body is supplied in the request. Calling /// this function disables that error. pub fn allow_body(mut self) -> Self { self.allow_body = true; self } /// Spawns `func` on the blocking executor. /// /// This method is suitable for handling long-running or intensive tasks. pub async fn in_blocking_task(self, func: F) -> Result, ApiError> where V: Send + Sync + 'static, F: Fn(Request>, Arc>) -> Result + Send + Sync + 'static, { let ctx = self.ctx; let executor = ctx.executor.clone(); let body = Self::get_body(self.body, self.allow_body).await?; let (req_parts, _) = self.req.into_parts(); let req = Request::from_parts(req_parts, body); let value = executor .runtime_handle() .spawn_blocking(move || func(req, ctx)) .await .map_err(|e| { ApiError::ServerError(format!( "Failed to get blocking join handle: {}", e.to_string() )) })??; Ok(HandledRequest { value }) } /// Downloads the bytes for `body`. async fn get_body(body: Body, allow_body: bool) -> Result, ApiError> { let bytes = hyper::body::to_bytes(body) .await .map_err(|e| ApiError::ServerError(format!("Unable to get request body: {:?}", e)))?; if !allow_body && !bytes[..].is_empty() { Err(ApiError::BadRequest( "The request body must be empty".to_string(), )) } else { Ok(bytes.into_iter().collect()) } } } /// A request that has been "handled" and now a result (`value`) needs to be serialized and /// returned. pub struct HandledRequest { value: V, } impl HandledRequest { /// Suitable for items which only implement `serde`. pub fn serde_encodings(self) -> ApiResult { let body = Body::from(serde_json::to_string(&self.value).map_err(|e| { ApiError::ServerError(format!( "Unable to serialize response body as JSON: {:?}", e )) })?); Response::builder() .status(StatusCode::OK) .header("content-type", "application/json") .body(body) .map_err(|e| ApiError::ServerError(format!("Failed to build response: {:?}", e))) } }