use std::collections::HashMap;
use std::sync::Mutex;
use crate::actix_web::HttpResponse;
use crate::error::InternalError;
use crate::futures::IntoFuture;
use crate::orchestrator::OrchestratableService;
use crate::rest_api::actix_web_1::{Resource, RestResourceProvider};
use super::{ManagedService, ServiceDefinition, ServiceOrchestrator};
impl RestResourceProvider for ServiceOrchestrator {
fn resources(&self) -> Vec<Resource> {
self.service_factories
.iter()
.fold(vec![], |mut acc, factory| {
let mut resources = factory
.get_rest_endpoints()
.into_iter()
.map(|endpoint| {
let route = format!(
"/{}/{{circuit}}/{{service_id}}{}",
endpoint.service_type, endpoint.route
);
let services = self.services.clone();
let mut resource_builder = Resource::build(&route);
for request_guard in endpoint.request_guards.into_iter() {
resource_builder = resource_builder.add_request_guard(request_guard);
}
let service_type = endpoint.service_type;
let handler = endpoint.handler;
resource_builder.add_method(
endpoint.method,
#[cfg(feature = "authorization")]
endpoint.permission,
move |request, payload| {
let circuit = request
.match_info()
.get("circuit")
.unwrap_or("")
.to_string();
let service_id = request
.match_info()
.get("service_id")
.unwrap_or("")
.to_string();
let service = match lookup_service(
&*services,
&circuit,
&service_id,
&service_type,
) {
Ok(Some(s)) => s,
Ok(None) => {
return Box::new(
HttpResponse::NotFound()
.json(json!({
"message":
format!(
"{} service {} on circuit {} not found",
service_type, service_id, circuit
)
}))
.into_future(),
)
.into_future();
}
Err(err) => {
error!("{}", err);
return Box::new(
HttpResponse::InternalServerError()
.json(json!({
"message": "An internal error occurred"
}))
.into_future(),
)
.into_future();
}
};
handler(request, payload, service.as_service())
},
)
})
.collect::<Vec<_>>();
acc.append(&mut resources);
acc
})
}
}
fn lookup_service(
services: &Mutex<HashMap<ServiceDefinition, ManagedService>>,
circuit: &str,
service_id: &str,
service_type: &str,
) -> Result<Option<Box<dyn OrchestratableService>>, InternalError> {
let services = services.lock().map_err(|_| {
InternalError::with_message("Orchestrator's service lock is poisoned".into())
})?;
Ok(services.iter().find_map(|(service_def, managed_service)| {
if service_def.service_type == service_type
&& service_def.circuit == circuit
&& service_def.service_id == service_id
{
Some(managed_service.service.clone())
} else {
None
}
}))
}