edenapi_server: factor out handler boilerplate

Summary: Factor out logic that will be common to many handlers into new functions in the `util` module.

Reviewed By: krallin

Differential Revision: D21489469

fbshipit-source-id: 9aff4e5182748ab0a0bedd6038852692b8e721a7
This commit is contained in:
Arun Kulshreshtha 2020-05-12 16:20:20 -07:00 committed by Facebook GitHub Bot
parent 3ac2032c07
commit 48a0b33093
2 changed files with 44 additions and 27 deletions

View File

@ -10,12 +10,9 @@ use bytes::Bytes;
use futures::{stream::FuturesUnordered, TryStreamExt};
use gotham::state::{FromState, State};
use gotham_derive::{StateData, StaticResponseExtender};
use http::HeaderMap;
use hyper::Body;
use serde::Deserialize;
use gotham_ext::{body_ext::BodyExt, error::HttpError, response::BytesBody};
use gotham_ext::{error::HttpError, response::BytesBody};
use mercurial_types::HgNodeHash;
use mononoke_api::hg::{HgDataContext, HgDataId, HgRepoContext};
use types::{
@ -26,7 +23,7 @@ use types::{
use crate::context::ServerContext;
use crate::middleware::RequestContext;
use super::util::cbor_mime;
use super::util::{cbor_mime, get_repo, get_request_body};
#[derive(Debug, Deserialize, StateData, StaticResponseExtender)]
pub struct DataParams {
@ -38,25 +35,11 @@ pub async fn data<ID: HgDataId>(state: &mut State) -> Result<BytesBody<Bytes>, H
let sctx = ServerContext::borrow_from(state);
let params = DataParams::borrow_from(state);
let repo = sctx
.mononoke_api()
.repo(rctx.core_context().clone(), &params.repo)
.await
.map_err(HttpError::e403)?
.ok_or_else(|| HttpError::e404(anyhow!("repo does not exist: {:?}", &params.repo)))?;
let repo = get_repo(&sctx, &rctx, &params.repo).await?;
let body = get_request_body(state).await?;
let hg_repo = repo.hg();
let body = Body::take_from(state);
let headers = HeaderMap::try_borrow_from(state);
let payload: Bytes = body
.try_concat_body_opt(headers)
.map_err(HttpError::e400)?
.await
.map_err(HttpError::e400)?;
let request = serde_cbor::from_slice(&payload).map_err(HttpError::e400)?;
let response = get_all_entries::<ID>(&hg_repo, request).await?;
let request = serde_cbor::from_slice(&body).map_err(HttpError::e400)?;
let response = get_all_entries::<ID>(&repo, request).await?;
let bytes: Bytes = serde_cbor::to_vec(&response)
.map_err(HttpError::e500)?
.into();
@ -66,12 +49,12 @@ pub async fn data<ID: HgDataId>(state: &mut State) -> Result<BytesBody<Bytes>, H
/// Fetch data for all of the requested keys concurrently.
async fn get_all_entries<ID: HgDataId>(
hg_repo: &HgRepoContext,
repo: &HgRepoContext,
request: DataRequest,
) -> Result<DataResponse, HttpError> {
let fetches = FuturesUnordered::new();
for key in request.keys {
fetches.push(get_data_entry::<ID>(hg_repo.clone(), key));
fetches.push(get_data_entry::<ID>(repo.clone(), key));
}
let entries = fetches.try_collect::<Vec<_>>().await?;
@ -82,13 +65,13 @@ async fn get_all_entries<ID: HgDataId>(
/// Note that this function consumes the repo context in order
/// to construct a file/tree context for the requested blob.
async fn get_data_entry<ID: HgDataId>(
hg_repo: HgRepoContext,
repo: HgRepoContext,
key: Key,
) -> Result<DataEntry, HttpError> {
let id = ID::from_node_hash(HgNodeHash::from(key.hgid));
let ctx = id
.context(hg_repo)
.context(repo)
.await
.map_err(HttpError::e500)?
.ok_or_else(|| HttpError::e404(anyhow!("key not found: {:?}", &key)))?;

View File

@ -5,11 +5,45 @@
* GNU General Public License version 2.
*/
use anyhow::anyhow;
use bytes::Bytes;
use gotham::state::{FromState, State};
use http::HeaderMap;
use hyper::Body;
use mime::Mime;
use once_cell::sync::Lazy;
use gotham_ext::{body_ext::BodyExt, error::HttpError};
use mononoke_api::hg::HgRepoContext;
use crate::context::ServerContext;
use crate::middleware::RequestContext;
static CBOR_MIME: Lazy<Mime> = Lazy::new(|| "application/cbor".parse().unwrap());
pub fn cbor_mime() -> Mime {
CBOR_MIME.clone()
}
pub async fn get_repo(
sctx: &ServerContext,
rctx: &RequestContext,
name: impl AsRef<str>,
) -> Result<HgRepoContext, HttpError> {
let name = name.as_ref();
sctx.mononoke_api()
.repo(rctx.core_context().clone(), name)
.await
.map_err(HttpError::e403)?
.map(|repo| repo.hg())
.ok_or_else(|| HttpError::e404(anyhow!("repo does not exist: {:?}", name)))
}
pub async fn get_request_body(state: &mut State) -> Result<Bytes, HttpError> {
let body = Body::take_from(state);
let headers = HeaderMap::try_borrow_from(state);
body.try_concat_body_opt(headers)
.map_err(HttpError::e400)?
.await
.map_err(HttpError::e400)
}