#[cfg(feature = "server")]
mod admin;
use std::sync::atomic::Ordering;
#[cfg(feature = "server")]
pub use admin::{ADMIN_API, admin_service_config};
use actix_web::{
HttpRequest, HttpResponse, HttpResponseBuilder,
http::StatusCode,
web::{Bytes, Data},
};
use crate::{
ApateState, RequestContext, ResourceRef,
deceit::{DEFAULT_RESPONSE_CODE, create_response_context},
processors::apply_processors,
};
pub async fn apate_server_handler(
req: HttpRequest,
body: Bytes,
state: Data<ApateState>,
) -> HttpResponse {
deceit_handler(req, body, state).await
}
async fn deceit_handler(req: HttpRequest, body: Bytes, state: Data<ApateState>) -> HttpResponse {
let deceit = &state.specs.read().await.deceit;
let mut ctx = RequestContext::new(req, body);
for (deceit_idx, d) in deceit.iter().enumerate() {
let Some(path) = d.match_againtst_uris(&ctx.request_path) else {
continue;
};
let args_path = path
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();
ctx.update_paths(path.as_str().to_string(), args_path);
log::trace!("Request context is: {ctx:?}");
let deceit_ref = ResourceRef::new(deceit_idx);
let Some(idx) = d.match_response(&deceit_ref, &ctx, &state.rhai) else {
continue;
};
log::debug!("Deceit {deceit_ref} matched (^_^). Processing response: {idx}");
let Some(dresp) = d.responses.get(idx) else {
log::error!("Wow we definitely must have response for this index {idx}");
continue;
};
let drctx = match create_response_context(ctx.clone(), state.counters.clone()) {
Ok(ctx) => ctx,
Err(e) => {
return HttpResponse::InternalServerError()
.body(format!("Cant create deceit context! {e}"));
}
};
let output_body = crate::output::output_response_body(
&deceit_ref,
&dresp.output_type,
&dresp.output,
&drctx,
&state.minijinja,
&state.rhai,
);
return match output_body {
Ok(body) => {
let mut prcs = Vec::with_capacity(d.processors.len() + dresp.processors.len());
prcs.extend(d.processors.iter());
prcs.extend(dresp.processors.iter());
match apply_processors(
&deceit_ref,
&state.processors,
&prcs,
&drctx,
&body,
&state.rhai,
) {
Ok(new_body) => {
let mut hrb = HttpResponseBuilder::new(DEFAULT_RESPONSE_CODE);
insert_response_headers(&mut hrb, &d.headers, &dresp.headers);
if let Ok(code) =
StatusCode::from_u16(drctx.response_code.load(Ordering::Relaxed))
{
hrb.status(code);
}
if let Some(bts) = new_body {
hrb.body(bts)
} else {
hrb.body(body)
}
}
Err(e) => HttpResponse::InternalServerError()
.body(format!("Can't apply post processors! {e}\n")),
}
}
Err(e) => HttpResponse::InternalServerError().body(format!("It happened! {e}\n")),
};
}
HttpResponse::NotFound().body(format!(
"Nothing can handle your requiest with path: {}\n",
ctx.request_path
))
}
fn insert_response_headers(
rbuilder: &mut HttpResponseBuilder,
parent_headers: &[(String, String)],
headers: &[(String, String)],
) {
for (k, v) in parent_headers {
rbuilder.insert_header((k.as_str(), v.as_str()));
}
for (k, v) in headers {
rbuilder.insert_header((k.as_str(), v.as_str()));
}
}