use crate::tina::data::app_error::AppError;
use crate::tina::data::http::response_data::HttpResData;
use crate::tina::data::http::response_page::HttpResPage;
use crate::tina::data::http::response_stream::{AjaxStreamInner, BinaryContentStreamAdapter, ResStream};
use crate::tina::data::http::{ErrorMsg, ErrorResponse, JsonResponse, StreamResponse, SuccessFlag};
use crate::tina::data::json::ToJson;
use crate::tina::data::no_data::NoData;
use crate::tina::data::AppResult;
use crate::tina::server::http::response::{HttpResponseExt, ResponseAttribute};
use crate::tina::server::session::Session;
use crate::tina::util::json::JsonUtil;
use axum::body::{boxed, BoxBody, StreamBody};
use axum::response::IntoResponse;
use http::header::{HeaderName, CONTENT_DISPOSITION, CONTENT_LENGTH, CONTENT_TYPE, LAST_MODIFIED};
use http::response::Builder;
use http::{HeaderValue, StatusCode};
use http_body::Empty;
use serde::{Serialize, Serializer};
use std::borrow::Cow;
use std::fmt::Debug;
pub struct ResRaw {
inner: axum::response::Response,
}
pub type Response<T = BoxBody> = axum::response::Response<T>;
impl<T> ResponseAttribute for Response<T> {
fn success(&self) -> bool {
let ext = self.extensions();
ext.get::<SuccessFlag>().is_some()
}
fn set_success(&mut self, flag: bool) {
let 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 => ext.get::<ErrorMsg>().map(|s| 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: axum::response::Response) -> Self {
Self {
inner: res,
}
}
pub fn into_inner(self) -> axum::response::Response {
self.inner
}
}
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 IntoResponse for ResRaw {
#[inline]
fn into_response(mut self) -> axum::response::Response {
self.inner.set_success(self.success());
self.inner
}
}
pub trait IntoResponse2 {
fn into_response2(self, locale: &str, print_err_log: bool) -> Response;
}
impl<D, Ext> IntoResponse2 for HttpResData<D, Ext>
where
D: Serialize + Debug,
Ext: Serialize + Debug,
{
fn into_response2(self, _locale: &str, print_err_log: bool) -> Response {
let body = JsonUtil::to_json_string(&self);
if print_err_log {
match self.is_success() {
true => {}
false => {
tracing::error!("{}", body);
}
}
}
Builder::new().status(StatusCode::OK).header(CONTENT_TYPE, "application/json").body(boxed(body)).expect("build response failed")
}
}
impl<D> IntoResponse2 for HttpResPage<D>
where
D: Serialize + Debug,
{
fn into_response2(self, _locale: &str, print_err_log: bool) -> Response {
let body = JsonUtil::to_json_string(&self);
if print_err_log {
match self.is_success() {
true => {}
false => {
tracing::error!("{}", body);
}
}
}
Builder::new().status(StatusCode::OK).header(CONTENT_TYPE, "application/json").body(boxed(body)).expect("build response failed")
}
}
impl IntoResponse2 for ResStream {
fn into_response2(self, locale: &str, print_err_log: bool) -> Response {
match self.inner {
AjaxStreamInner::Success(stream_data) => {
let data = stream_data.data;
let content_type = stream_data.content_type;
let name = stream_data.name;
let download = stream_data.download;
let mut builder = Builder::new().status(StatusCode::OK).header(CONTENT_TYPE, content_type.as_ref());
if download {
builder = builder.header(CONTENT_DISPOSITION, format!("attachment;filename={}", name));
}
if let Some(last_modified) = stream_data.last_modified.as_ref() {
builder = builder.header(LAST_MODIFIED, last_modified.to_string());
}
for (k, v) in self.headers.into_iter() {
if let Some(k) = k {
builder = builder.header(k, v);
}
}
let mut res = match stream_data.size {
None => {
let body = StreamBody::new(BinaryContentStreamAdapter(data));
builder.body(boxed(body)).expect("build stream response body failed...")
}
Some(size) => {
builder = builder.header(CONTENT_LENGTH, size);
let body = StreamBody::new(BinaryContentStreamAdapter(data));
builder.body(boxed(body)).expect("build stream response body failed...")
}
};
res.set_success(true);
res
}
AjaxStreamInner::AppError(err) => {
let mut res = err.into_response2(locale, print_err_log);
res.set_success(false);
res
}
AjaxStreamInner::HttpStatus(status_code) => {
Builder::new().status(status_code).body(boxed(Empty::default())).expect("build stream response body failed...")
}
}
}
}
impl IntoResponse2 for JsonResponse {
fn into_response2(self, _locale: &str, _print_err_log: bool) -> Response {
let body = self.0.to_json_string();
Builder::new().status(StatusCode::OK).header(CONTENT_TYPE, "application/json").body(boxed(body)).expect("build response failed")
}
}
impl IntoResponse2 for AppError {
fn into_response2(self, locale: &str, print_err_log: bool) -> Response {
let msg = format!("{:?}", self);
let vo: HttpResData<NoData> = HttpResData {
code: self.get_return_code(),
msg: Some(self.get_return_msg().get_string(locale)),
data: None,
extension: Default::default(),
session: Session::default(),
};
let body = vo.to_json_string();
if print_err_log {
match vo.is_success() {
true => {}
false => {
tracing::error!("{}, 异常信息: {}", body, msg);
}
}
}
Builder::new().status(StatusCode::OK).header(CONTENT_TYPE, "application/json").body(boxed(body)).expect("build response failed")
}
}
impl IntoResponse2 for ErrorResponse {
fn into_response2(self, locale: &str, print_err_log: bool) -> Response {
self.0.into_response2(locale, print_err_log)
}
}
impl IntoResponse2 for StreamResponse {
fn into_response2(self, locale: &str, print_err_log: bool) -> Response {
self.0.into_response2(locale, print_err_log)
}
}
impl<T> HttpResponseExt for Response<T> {
fn add_response_header(&mut self, header_name: HeaderName, header_value: HeaderValue) -> AppResult<()> {
let headers = self.headers_mut();
headers.insert(header_name, header_value);
Ok(())
}
}