use crate::authenticators::Authenticate;
use crate::back::dispatcher::Dispatcher;
use derivative::Derivative;
use log::{error, info};
use parsec_interface::requests::AuthType;
use parsec_interface::requests::ResponseStatus;
use parsec_interface::requests::{Request, Response};
use std::collections::HashMap;
use std::io::{Error, ErrorKind, Result};
use std::io::{Read, Write};
#[derive(Derivative)]
#[derivative(Debug)]
pub struct FrontEndHandler {
dispatcher: Dispatcher,
#[derivative(Debug = "ignore")]
authenticators: HashMap<AuthType, Box<dyn Authenticate + Send + Sync>>,
body_len_limit: usize,
}
impl FrontEndHandler {
pub fn handle_request<T: Read + Write>(&self, mut stream: T) {
let request = match Request::read_from_stream(&mut stream, self.body_len_limit) {
Ok(request) => request,
Err(status) => {
error!("Failed to read request; status: {}", status);
let response = Response::from_status(status);
if let Err(status) = response.write_to_stream(&mut stream) {
error!("Failed to write response; status: {}", status);
}
return;
}
};
let response = if AuthType::NoAuth == request.header.auth_type {
self.dispatcher.dispatch_request(request, None)
} else if let Some(authenticator) = self.authenticators.get(&request.header.auth_type) {
match authenticator.authenticate(&request.auth) {
Ok(app_name) => self.dispatcher.dispatch_request(request, Some(app_name)),
Err(status) => Response::from_request_header(request.header, status),
}
} else {
Response::from_request_header(
request.header,
ResponseStatus::AuthenticatorNotRegistered,
)
};
match response.write_to_stream(&mut stream) {
Ok(_) => info!("Request handled successfully"),
Err(err) => error!("Failed to send response; error: {}", err),
}
}
}
#[derive(Default, Derivative)]
#[derivative(Debug)]
pub struct FrontEndHandlerBuilder {
dispatcher: Option<Dispatcher>,
#[derivative(Debug = "ignore")]
authenticators: Option<HashMap<AuthType, Box<dyn Authenticate + Send + Sync>>>,
body_len_limit: Option<usize>,
}
impl FrontEndHandlerBuilder {
pub fn new() -> Self {
FrontEndHandlerBuilder {
dispatcher: None,
authenticators: None,
body_len_limit: None,
}
}
pub fn with_dispatcher(mut self, dispatcher: Dispatcher) -> Self {
self.dispatcher = Some(dispatcher);
self
}
pub fn with_authenticator(
mut self,
auth_type: AuthType,
authenticator: Box<dyn Authenticate + Send + Sync>,
) -> Self {
match &mut self.authenticators {
Some(authenticators) => {
let _ = authenticators.insert(auth_type, authenticator);
}
None => {
let mut map = HashMap::new();
let _ = map.insert(auth_type, authenticator);
self.authenticators = Some(map);
}
};
self
}
pub fn with_body_len_limit(mut self, body_len_limit: usize) -> Self {
self.body_len_limit = Some(body_len_limit);
self
}
pub fn build(self) -> Result<FrontEndHandler> {
Ok(FrontEndHandler {
dispatcher: self
.dispatcher
.ok_or_else(|| Error::new(ErrorKind::InvalidData, "dispatcher is missing"))?,
authenticators: self
.authenticators
.ok_or_else(|| Error::new(ErrorKind::InvalidData, "authenticators is missing"))?,
body_len_limit: self
.body_len_limit
.ok_or_else(|| Error::new(ErrorKind::InvalidData, "body_len_limit is missing"))?,
})
}
}