use std::fmt;
use std::fmt::{Display, Formatter};
use bytes::Bytes;
#[cfg(feature = "cookie")]
use cookie::{Cookie, CookieJar};
use http::{Extensions, Version};
use http_body::{Body, SizeHint};
use serde::Serialize;
use serde_json::Value;
use crate::core::res_body::{full, ResBody};
use crate::headers::{ContentType, Header, HeaderMap, HeaderMapExt};
use crate::{header, Configs, Result, SilentError, StatusCode};
pub struct Response<B: Body = ResBody> {
pub(crate) status: StatusCode,
pub(crate) version: Version,
pub(crate) headers: HeaderMap,
pub(crate) body: B,
#[cfg(feature = "cookie")]
pub(crate) cookies: CookieJar,
pub(crate) extensions: Extensions,
pub(crate) configs: Configs,
}
impl fmt::Debug for Response {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
writeln!(f, "{:?} {}\n{:?}", self.version, self.status, self.headers)
}
}
impl Display for Response {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl Response {
pub fn empty() -> Self {
Self {
status: StatusCode::OK,
headers: HeaderMap::new(),
version: Version::default(),
body: ResBody::None,
#[cfg(feature = "cookie")]
cookies: CookieJar::default(),
extensions: Extensions::default(),
configs: Configs::default(),
}
}
#[inline]
pub fn redirect(url: &str) -> Result<Self> {
let mut res = Self::empty();
res.status = StatusCode::MOVED_PERMANENTLY;
res.headers.insert(
header::LOCATION,
url.parse().map_err(|e| {
SilentError::business_error(
StatusCode::INTERNAL_SERVER_ERROR,
format!("redirect error: {}", e),
)
})?,
);
Ok(res)
}
}
impl<B: Body> Response<B> {
#[inline]
pub fn set_status(&mut self, status: StatusCode) {
self.status = status;
}
#[inline]
pub fn with_status(mut self, status: StatusCode) -> Self {
self.status = status;
self
}
#[inline]
pub fn set_body(&mut self, body: B) {
self.body = body;
}
#[inline]
pub fn with_body(mut self, body: B) -> Self {
self.body = body;
self
}
#[inline]
pub fn body(&self) -> &B {
&self.body
}
#[inline]
pub fn set_header(&mut self, key: header::HeaderName, value: header::HeaderValue) {
self.headers.insert(key, value);
}
#[inline]
pub fn with_header(mut self, key: header::HeaderName, value: header::HeaderValue) -> Self {
self.headers.insert(key, value);
self
}
#[inline]
pub fn extensions(&self) -> &Extensions {
&self.extensions
}
#[inline]
pub fn extensions_mut(&mut self) -> &mut Extensions {
&mut self.extensions
}
#[inline]
pub fn get_config<T: Send + Sync + 'static>(&self) -> Result<&T> {
self.configs.get::<T>().ok_or(SilentError::ConfigNotFound)
}
#[inline]
pub fn get_config_uncheck<T: Send + Sync + 'static>(&self) -> &T {
self.configs.get::<T>().unwrap()
}
#[inline]
pub fn configs(&self) -> &Configs {
&self.configs
}
#[inline]
pub fn configs_mut(&mut self) -> &mut Configs {
&mut self.configs
}
#[inline]
pub fn headers(&self) -> &HeaderMap {
&self.headers
}
#[inline]
pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.headers
}
#[inline]
pub fn content_length(&self) -> SizeHint {
self.body.size_hint()
}
#[inline]
pub fn set_typed_header<H>(&mut self, header: H)
where
H: Header,
{
self.headers.typed_insert(header);
}
#[inline]
pub fn with_typed_header<H>(mut self, header: H) -> Self
where
H: Header,
{
self.headers.typed_insert(header);
self
}
#[cfg(feature = "cookie")]
#[inline]
pub fn cookies(&self) -> &CookieJar {
&self.cookies
}
#[cfg(feature = "cookie")]
#[inline]
pub fn cookies_mut(&mut self) -> &mut CookieJar {
&mut self.cookies
}
#[cfg(feature = "cookie")]
#[inline]
pub fn cookie<T>(&self, name: T) -> Option<&Cookie<'static>>
where
T: AsRef<str>,
{
self.cookies.get(name.as_ref())
}
#[cfg(feature = "cookie")]
pub fn copy_from_response(&mut self, res: Response<B>) {
self.headers.extend(res.headers);
res.cookies.delta().for_each(|cookie| {
self.cookies.add(cookie.clone());
});
self.status = res.status;
self.extensions.extend(res.extensions);
self.set_body(res.body);
}
#[cfg(not(feature = "cookie"))]
pub fn copy_from_response(&mut self, res: Response<B>) {
self.headers.extend(res.headers);
self.status = res.status;
self.extensions.extend(res.extensions);
self.set_body(res.body);
}
}
impl<S: Serialize> From<S> for Response {
fn from(value: S) -> Self {
let mut res = Response::empty();
let result: Bytes = match serde_json::to_value(&value).unwrap() {
Value::String(value) => {
if value.contains("html") {
res.set_typed_header(ContentType::html());
} else {
res.set_typed_header(ContentType::text_utf8());
}
value.into_bytes().into()
}
_ => {
res.set_typed_header(ContentType::json());
serde_json::to_vec(&value).unwrap().into()
}
};
res.set_body(full(result));
res
}
}