dce-router 1.8.0

A router for all type programming api route.
Documentation
use std::any::Any;
use std::fmt::Debug;
use bytes::{Bytes, BytesMut};
use dce_util::result::{DceError, DceResult};
use log::{error, warn};
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use crate::api::{Api};

#[cfg(feature = "async")]
use async_trait::async_trait;


pub const CTX_KEY_SESSION: &str = "$#session#";
pub const CTX_KEY_RESP_SID: &str = "$#response-sid#";

#[derive(Debug)]
pub struct RpMeta<Req> {
    req: Req,
    resp_buffer: BytesMut,
    ctx_data: HashMap<String, Box<dyn Any + Send>>,
}

impl<Req> RpMeta<Req> {
    pub fn new(req: Req, ctx_data: Option<HashMap<String, Box<dyn Any + Send>>>) -> Self {
        Self { req, resp_buffer: Default::default(), ctx_data: ctx_data.unwrap_or_default() }
    }

    pub fn raw(&self) -> &Req {
        &self.req
    }

    pub fn raw_mut(&mut self) -> &mut Req {
        &mut self.req
    }

    pub fn clear_buffer(&mut self) -> Vec<u8> {
        self.resp_buffer.split().to_vec()
    }

    pub fn is_resp_empty(&self) -> bool {
        self.resp_buffer.is_empty()
    }

    pub fn write(&mut self, bytes: Bytes) {
        self.resp_buffer.extend(bytes);
    }

    pub fn write_string(&mut self, str: String) {
        self.resp_buffer.extend(str.as_bytes());
    }

    pub fn set_ctx_data(&mut self, key: String, value: Box<dyn Any + Send>) {
        self.ctx_data.insert(key, value);
    }
    
    pub fn ctx_data(&self, key: &str) -> Option<&Box<dyn Any + Send>> {
        return self.ctx_data.get(key)
    }
    
    pub fn ctx_data_remove(&mut self, key: &str) -> Option<Box<dyn Any + Send>> {
        return self.ctx_data.remove(key)
    }

    pub fn sid(&self) -> Option<&str> {
        None
    }

    pub fn set_session(&mut self) {
        // todo
    }
    
    pub fn session(&self) {
        // todo
    }
    
    pub fn set_resp_sid(&mut self, sid: String) {
        self.ctx_data.insert(CTX_KEY_RESP_SID.to_string(), Box::new(sid));
    }
    
    pub fn resp_sid(&self) -> Option<&str> {
        self.ctx_data.get(CTX_KEY_RESP_SID).map(
            | boxed | boxed.downcast_ref::<String>().map(
                | resp_sid | resp_sid.as_str())

        ).flatten()
    }
}


#[cfg_attr(feature = "async", async_trait)]
pub trait RoutableProtocol: Sized + Deref<Target = RpMeta<Self::Req>> + DerefMut + Send {
    type Req;

    fn id(&self) -> isize { 0 }

    fn path(&self) -> &str;

    fn sync_body(&mut self) -> DceResult<Bytes> {
        unreachable!("Not implemented yet")
    }

    fn sync_body_string(&mut self) -> DceResult<String> {
        self.sync_body().map(|bts| String::from_utf8_lossy(&bts).into_owned())
    }

    #[cfg(feature = "async")]
    async fn body(&mut self) -> DceResult<Bytes> {
        unreachable!("Not implemented yet")
    }

    #[cfg(feature = "async")]
    async fn body_string(&mut self) -> DceResult<String> {
        self.body().await.map(|bts| String::from_utf8_lossy(&bts).into_owned())
    }

    fn match_api(&self, apis: &Vec<&'static Api<Self>>) -> Option<&'static Api<Self>> {
        apis.last().map(|a| *a)
    }

    fn try_print_err(&self, err: &Option<DceError>) {
        if let Some(err) = err {
            if err.public {
                warn!("{}", err);
            } else {
                error!("{}", err);
            }
        }        
    }
}