tina-core 0.0.2

Tina platform
Documentation
//! Response扩展
use crate::app_error;
use crate::tina::data::app_error::AppError;
use crate::tina::data::http::request_ext::{ErrorMsg, SuccessFlag};
use crate::tina::data::json::ToJson;
use crate::tina::data::no_data::NoData;
use crate::tina::data::response_data::ResData;
use crate::tina::data::response_page::ResPage;
use crate::tina::data::AppResult;
use crate::tina::server::http::request::RequestExt;
use crate::tina::server::http::response::{HttpResponseExt, ResponseAttribute};
use crate::tina::server::session::Session;
use crate::tina::util::json::JsonUtil;
use futures_util::future::LocalBoxFuture;
use futures_util::FutureExt;
use http::header::HeaderName;
use http::{HeaderValue, StatusCode};
use ntex::http::body::Body;
use ntex::web::{HttpRequest, Responder, WebRequest, WebResponse};
use serde::{Serialize, Serializer};
use std::borrow::Cow;
use std::fmt::Debug;
use std::sync::Arc;

/// 响应
pub struct ResRaw {
    inner: ntex::http::Response<Body>,
}

/// 响应
pub type Response = ntex::http::Response<Body>;

impl ResponseAttribute for Response {
    fn success(&self) -> bool {
        let ext = self.extensions();
        match ext.get::<SuccessFlag>() {
            None => false,
            Some(_) => true,
        }
    }

    fn set_success(&mut self, flag: bool) {
        let mut ext = self.extensions_mut();
        match flag {
            true => {
                ext.insert(SuccessFlag);
            }
            false => {
                ext.remove::<SuccessFlag>();
            }
        }
    }

    fn get_error_message(&self) -> Option<Cow<str>> {
        let ext = self.extensions();
        match ext.get::<SuccessFlag>() {
            None => match ext.get::<ErrorMsg>() {
                None => None,
                Some(s) => Some(Cow::Owned(s.0.to_string())),
            },
            Some(_) => None,
        }
    }
}

impl ResponseAttribute for WebResponse {
    fn success(&self) -> bool {
        self.response().success()
    }

    fn set_success(&mut self, flag: bool) {
        self.response_mut().set_success(flag)
    }

    fn get_error_message(&self) -> Option<Cow<str>> {
        let res = self.response();
        let ext = res.extensions();
        match ext.get::<SuccessFlag>() {
            None => match ext.get::<ErrorMsg>() {
                None => None,
                Some(s) => Some(Cow::Owned(s.0.to_string())),
            },
            Some(_) => None,
        }
    }
}

impl ResponseAttribute for ResRaw {
    fn success(&self) -> bool {
        self.inner.success()
    }

    fn set_success(&mut self, flag: bool) {
        self.inner.set_success(flag)
    }

    fn get_error_message(&self) -> Option<Cow<str>> {
        self.inner.get_error_message()
    }
}

impl ResRaw {
    /// 构建
    pub fn new(res: ntex::http::Response<Body>) -> Self {
        Self {
            inner: res,
        }
    }
    /// 转换
    pub fn into_inner(self) -> ntex::http::Response<Body> {
        self.inner
    }
}

/// 转换成ResRaw
pub trait IntoResRaw {
    /// 转换
    fn into_ajax_response(self) -> ResRaw;
}

impl IntoResRaw for Response {
    fn into_ajax_response(self) -> ResRaw {
        ResRaw::new(self)
    }
}

impl Serialize for ResRaw {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str("[Response]")
    }
}

impl Responder<AppError> for ResRaw {
    type Future = LocalBoxFuture<'static, ntex::http::Response<Body>>;

    #[inline]
    fn respond_to(mut self, _: &HttpRequest) -> Self::Future {
        self.inner.set_success(self.success());
        async move { self.inner }.boxed_local()
    }
}

fn set_log_param_result<T: Serialize>(value: &T, req: &HttpRequest) {
    if let Ok(Some(request_param_log)) = req.get_request_log_param() {
        request_param_log.set_result(Arc::new(value.to_json_value()));
    }
}

fn set_log_param_result2<T: Serialize, E>(value: &T, req: &WebRequest<E>) {
    if let Ok(Some(request_param_log)) = req.get_request_log_param() {
        request_param_log.set_result(Arc::new(value.to_json_value()));
    }
}

fn set_log_param_error(err: &AppError, req: &HttpRequest) {
    if let Ok(Some(request_param_log)) = req.get_request_log_param() {
        request_param_log.set_err(err);
    }
}

fn set_log_param_error2<E>(err: &AppError, req: &WebRequest<E>) {
    if let Ok(Some(request_param_log)) = req.get_request_log_param() {
        request_param_log.set_err(err);
    }
}

/// 转换成Response
pub trait IntoToResponse {
    /// 转换
    fn into_response(self, req: &HttpRequest, print_err_log: bool) -> Response;
    /// 转换
    fn into_response2<E>(self, req: &WebRequest<E>, print_err_log: bool) -> Response;
}

impl<D, Ext> IntoToResponse for ResData<D, Ext>
where
    D: Serialize + Debug,
    Ext: Serialize + Debug,
{
    fn into_response(self, req: &HttpRequest, print_err_log: bool) -> Response {
        set_log_param_result(&self, req);
        let body = JsonUtil::to_json_string(&self);

        if print_err_log {
            match self.is_success() {
                true => {}
                false => {
                    tracing::error!("{}", body);
                    set_log_param_error(&app_error!(self.code.clone(), self.code.clone().get_code_description()), req);
                }
            }
        }
        Response::build(StatusCode::OK).content_type("application/json").body(body)
    }

    fn into_response2<E>(self, req: &WebRequest<E>, print_err_log: bool) -> Response {
        set_log_param_result2(&self, req);
        let body = JsonUtil::to_json_string(&self);

        if print_err_log {
            match self.is_success() {
                true => {}
                false => {
                    tracing::error!("{}", body);
                    set_log_param_error2(&app_error!(self.code.clone(), self.code.clone().get_code_description()), req);
                }
            }
        }
        Response::build(StatusCode::OK).content_type("application/json").body(body)
    }
}

impl<D> IntoToResponse for ResPage<D>
where
    D: Serialize + Debug,
{
    fn into_response(self, req: &HttpRequest, print_err_log: bool) -> Response {
        set_log_param_result(&self, req);
        let body = JsonUtil::to_json_string(&self);

        if print_err_log {
            match self.is_success() {
                true => {}
                false => {
                    tracing::error!("{}", body);
                    set_log_param_error(&app_error!(self.code.clone(), self.code.clone().get_code_description()), req);
                }
            }
        }
        Response::build(StatusCode::OK).content_type("application/json").body(body)
    }

    fn into_response2<E>(self, req: &WebRequest<E>, print_err_log: bool) -> Response {
        set_log_param_result2(&self, req);
        let body = JsonUtil::to_json_string(&self);

        if print_err_log {
            match self.is_success() {
                true => {}
                false => {
                    tracing::error!("{}", body);
                    set_log_param_error2(&app_error!(self.code.clone(), self.code.clone().get_code_description()), req);
                }
            }
        }
        Response::build(StatusCode::OK).content_type("application/json").body(body)
    }
}

impl IntoToResponse for AppError {
    fn into_response(self, req: &HttpRequest, print_err_log: bool) -> Response {
        let locale = req.get_locale();
        let msg = format!("{:?}", self);
        set_log_param_error(&self, req);
        let vo: ResData<NoData> = ResData {
            code: self.get_return_code(),
            msg: Some(self.get_return_msg().get_string(&locale)),
            data: None,
            extension: Default::default(),
            session: Session::default(),
        };
        set_log_param_result(&vo, req);

        let body = vo.to_json_string();
        if print_err_log {
            match vo.is_success() {
                true => {}
                false => {
                    tracing::error!("{}, 异常信息: {}", body, msg);
                }
            }
        }
        Response::build(StatusCode::OK).content_type("application/json").body(body)
    }

    fn into_response2<E>(self, req: &WebRequest<E>, print_err_log: bool) -> Response {
        let locale = req.get_locale();
        let msg = format!("{:?}", self);
        set_log_param_error2(&self, req);
        let vo: ResData<NoData> = ResData {
            code: self.get_return_code(),
            msg: Some(self.get_return_msg().get_string(&locale)),
            data: None,
            extension: Default::default(),
            session: Session::default(),
        };
        set_log_param_result2(&vo, req);

        let body = vo.to_json_string();
        if print_err_log {
            match vo.is_success() {
                true => {}
                false => {
                    tracing::error!("{}, 异常信息: {}", body, msg);
                }
            }
        }
        Response::build(StatusCode::OK).content_type("application/json").body(body)
    }
}

impl HttpResponseExt for WebResponse {
    fn add_response_header(&mut self, header_name: HeaderName, header_value: HeaderValue) -> AppResult<()> {
        let headers = self.headers_mut();
        headers.insert(header_name, header_value.into());
        Ok(())
    }
}