teo_runtime/response/
response.rs

1use std::fmt::{Debug, Formatter};
2use std::path::PathBuf;
3use std::sync::{Arc, Mutex};
4use hyper::header::CONTENT_TYPE;
5use crate::value::Value;
6use crate::teon;
7use teo_result::{Result, Error};
8use crate::cookies::Cookies;
9use crate::headers::headers::Headers;
10use crate::response::body::Body;
11
12#[derive(Clone)]
13pub struct Response {
14    inner: Arc<Mutex<Inner>>
15}
16
17pub struct Inner {
18    code: u16,
19    headers: Headers,
20    body: Body,
21    cookies: Cookies,
22}
23
24impl Response {
25
26    pub fn empty() -> Response {
27        Self {
28            inner: Arc::new(Mutex::new(Inner::new())),
29        }
30    }
31
32    pub fn string(content: impl Into<String>, content_type: &str) -> Result<Response> {
33        let mut inner = Inner::new();
34        inner.body = Body::string(content.into());
35        inner.headers.insert(CONTENT_TYPE.as_str(), content_type)?;
36        Ok(Self {
37            inner: Arc::new(Mutex::new(inner)),
38        })
39    }
40
41    pub fn teon(value: Value) -> Response {
42        let mut inner = Inner::new();
43        inner.body = Body::teon(value);
44        Self {
45            inner: Arc::new(Mutex::new(inner))
46        }
47    }
48
49    pub fn text(content: impl Into<String>) -> Result<Response> {
50        Ok(Self::string(content.into(), "text/plain")?)
51    }
52
53    pub fn html(content: impl Into<String>) -> Result<Response> {
54        Ok(Self::string(content.into(), "text/html")?)
55    }
56
57    pub fn data(value: Value) -> Response {
58        Self::teon(teon!({"data": value}))
59    }
60
61    pub fn data_meta(data: Value, meta: Value) -> Response {
62        Self::teon(teon!({"data": data, "meta": meta}))
63    }
64
65    pub fn file(path: PathBuf) -> Response {
66        let res = Self::empty();
67        res.inner.lock().unwrap().body = Body::file(path);
68        res
69    }
70
71    pub fn send_file(base: impl AsRef<str>, path: impl AsRef<str>) -> Result<Response> {
72        let base_str = base.as_ref();
73        let path_str = path.as_ref();
74        let combined_path = PathBuf::from(base_str).join(path_str);
75        if combined_path.is_file() {
76            Ok(Response::file(combined_path))
77        } else {
78            Err(Error::not_found())
79        }
80    }
81
82    pub fn redirect(path: impl Into<String>) -> Result<Response> {
83        let res = Self::empty();
84        res.set_code(301);
85        res.headers().insert("location", path.into())?;
86        Ok(res)
87    }
88
89    pub fn set_code(&self, code: u16) {
90        self.inner.lock().unwrap().code = code;
91    }
92
93    pub fn code(&self) -> u16 {
94        self.inner.lock().unwrap().code
95    }
96
97    pub fn headers(&self) -> Headers {
98        self.inner.lock().unwrap().headers.clone()
99    }
100
101    pub fn set_headers(&self, headers: Headers) {
102        self.inner.lock().unwrap().headers = headers;
103    }
104
105    pub fn body(&self) -> Body {
106        self.inner.lock().unwrap().body.clone()
107    }
108
109    pub fn set_body(&self, body: Body) {
110        self.inner.lock().unwrap().body = body;
111    }
112
113    pub fn cookies(&self) -> Cookies {
114        self.inner.lock().unwrap().cookies.clone()
115    }
116
117    pub fn set_cookies(&self, cookies: Cookies) {
118        self.inner.lock().unwrap().cookies = cookies;
119    }
120}
121
122impl Inner {
123
124    fn new() -> Self {
125        Self {
126            code: 200,
127            headers: Headers::new(),
128            body: Body::empty(),
129            cookies: Cookies::new(),
130        }
131    }
132}
133
134impl Debug for Response {
135
136    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
137        let mut debug_struct = f.debug_struct("Response");
138        debug_struct.field("code", &self.inner.lock().unwrap().code);
139        debug_struct.field("headers", &self.inner.lock().unwrap().headers);
140        debug_struct.finish()
141    }
142}