use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use actix_web::{web, HttpResponse};
use futures::IntoFuture;
use splinter::{
rest_api::{ErrorResponse, Method, ProtocolVersionRangeGuard},
service::rest_api::ServiceEndpoint,
};
use crate::protocol;
#[cfg(feature = "authorization")]
use crate::service::rest_api::SCABBARD_READ_PERMISSION;
use crate::service::{
rest_api::resources::batch_statuses::BatchInfoResponse, Scabbard, SERVICE_TYPE,
};
const DEFAULT_BATCH_STATUS_WAIT_SECS: u64 = 300;
pub fn make_get_batch_status_endpoint() -> ServiceEndpoint {
ServiceEndpoint {
service_type: SERVICE_TYPE.into(),
route: "/batch_statuses".into(),
method: Method::Get,
handler: Arc::new(move |req, _, service| {
let scabbard = match service.as_any().downcast_ref::<Scabbard>() {
Some(s) => s,
None => {
error!("Failed to downcast to scabbard service");
return Box::new(
HttpResponse::InternalServerError()
.json(ErrorResponse::internal_error())
.into_future(),
);
}
}
.clone();
let query: web::Query<HashMap<String, String>> =
if let Ok(q) = web::Query::from_query(req.query_string()) {
q
} else {
return Box::new(
HttpResponse::BadRequest()
.json(ErrorResponse::bad_request("Invalid query"))
.into_future(),
);
};
let ids = if let Some(ids) = query.get("ids") {
ids.split(',').map(String::from).collect()
} else {
return Box::new(
HttpResponse::BadRequest()
.json(ErrorResponse::bad_request("No batch IDs specified"))
.into_future(),
);
};
let wait = query
.get("wait")
.and_then(|wait_str| {
if wait_str.as_str() == "false" {
None
} else {
wait_str
.parse()
.ok()
.or(Some(DEFAULT_BATCH_STATUS_WAIT_SECS))
}
})
.map(Duration::from_secs);
let batch_info_iter = match scabbard.get_batch_info(ids, wait) {
Ok(iter) => iter,
Err(err) => {
error!("Failed to get batch statuses iterator: {}", err);
return Box::new(
HttpResponse::InternalServerError()
.json(ErrorResponse::internal_error())
.into_future(),
);
}
};
match batch_info_iter.collect::<Result<Vec<_>, _>>() {
Ok(batch_infos) => Box::new(
HttpResponse::Ok()
.json(
batch_infos
.iter()
.map(BatchInfoResponse::from)
.collect::<Vec<_>>(),
)
.into_future(),
),
Err(err) => Box::new(
HttpResponse::RequestTimeout()
.json(ErrorResponse::request_timeout(&format!(
"Failed to get batch statuses before timeout: {}",
err
)))
.into_future(),
),
}
}),
request_guards: vec![Box::new(ProtocolVersionRangeGuard::new(
protocol::SCABBARD_BATCH_STATUSES_PROTOCOL_MIN,
protocol::SCABBARD_PROTOCOL_VERSION,
))],
#[cfg(feature = "authorization")]
permission: SCABBARD_READ_PERMISSION,
}
}