polariton_server 0.6.0

Server functionality for the Photon packet system
Documentation
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 with_state<S: Send + Sync + 'static, O: Operation<C, State=S, User=U> + OperationCode + 'static>(mut self, op: O, state: S) -> Self {
        self.insert_op(O::op_code(), Box::new(SyncedOpWrapper {
            _custom_ty: Default::default(),
            state: Mutex::new(state),
            handler: op,
        }));
        self
    }*/

    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)
        }
    }
}