use std::collections::HashMap;
use polariton::operation::{OperationResponse, ParameterTable, OperationRequest};
use super::{Operation, OperationCode, OperationModifier};
use crate::HandlingError;
pub struct OperationsHandler<U: Send + Sync, C: Send + Sync = ()> {
op_map: HashMap<u8, Box<dyn Operation<C, User=U>>>,
modifiers: Vec<Box<dyn OperationModifier<C>>>,
}
impl <C: Send + Sync + Clone + std::fmt::Debug + 'static, U: Send + Sync> OperationsHandler<U, C> {
pub fn new() -> Self {
Self {
op_map: Default::default(),
modifiers: Default::default(),
}
}
pub fn add<O: Operation<C, User=U> + OperationCode + 'static>(mut self, op: O) -> Self {
self.insert_op(O::op_code(), Box::new(op));
self
}
pub fn modify<OM: OperationModifier<C> + 'static>(mut self, op_mod: OM) -> Self {
self.modifiers.push(Box::new(op_mod));
self
}
fn insert_op(&mut self, code: u8, handler: Box<dyn Operation<C, User=U>>) {
if self.op_map.insert(code, handler).is_some() {
log::warn!("Replacing operation for code {}", code);
}
}
fn try_pass_to_handler(&self, code: u8, params: ParameterTable<C>, user:&U) -> OperationResponse<C> {
if let Some(handler) = self.op_map.get(&code) {
handler.handle(params, user)
} else {
#[cfg(debug_assertions)]
panic!("No handler for op code {}, pls fix!! params: {:?}", code, params.clone().to_dict());
#[cfg(not(debug_assertions))]
{
log::warn!("No handler for op code {}", code);
log::debug!("Unhandled op code {}, params {:?}", code, params.clone().to_dict());
OperationResponse {
code,
return_code: 0,
message: polariton::operation::Typed::Null,
params,
}
}
}
}
#[cfg(feature = "async")]
async fn try_pass_to_handler_async(&self, code: u8, params: ParameterTable<C>, user:&U) -> OperationResponse<C> {
if let Some(handler) = self.op_map.get(&code) {
handler.handle_async(params, user).await
} else {
#[cfg(debug_assertions)]
panic!("No handler for op code {}, pls fix!! params: {:?}", code, params.clone().to_dict());
#[cfg(not(debug_assertions))]
{
log::warn!("No handler for op code {}", code);
log::debug!("Unhandled op code {}, params {:?}", code, params.clone().to_dict());
OperationResponse {
code,
return_code: 0,
message: polariton::operation::Typed::Null,
params,
}
}
}
}
fn modify_op_before(&self, req: &mut OperationRequest<C>, flags: &mut u8) -> bool {
let mut is_ok = true;
for op_mod in self.modifiers.iter() {
is_ok |= op_mod.before(req, flags);
}
is_ok
}
fn modify_op_after(&self, req: &mut OperationRequest<C>, resp: &mut OperationResponse<C>, flags: &mut u8) {
for op_mod in self.modifiers.iter() {
op_mod.after(req, resp, flags);
}
}
pub fn handle_op(&self, user: &U, mut req: OperationRequest<C>, flags: &mut u8) -> Result<OperationResponse<C>, HandlingError> {
let is_ok = self.modify_op_before(&mut req, flags);
if is_ok {
let mut op_resp = self.try_pass_to_handler(req.code, req.params.clone(), user);
self.modify_op_after(&mut req, &mut op_resp, flags);
Ok(op_resp)
} else {
Err(HandlingError::Rejected)
}
}
#[cfg(feature = "async")]
pub async fn handle_op_async(&self, user: &U, mut req: OperationRequest<C>, flags: &mut u8) -> Result<OperationResponse<C>, HandlingError> {
let is_ok = self.modify_op_before(&mut req, flags);
if is_ok {
let mut op_resp = self.try_pass_to_handler_async(req.code, req.params.clone(), user).await;
self.modify_op_after(&mut req, &mut op_resp, flags);
Ok(op_resp)
} else {
Err(HandlingError::Rejected)
}
}
}