teo_runtime/response/
response.rs1use 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}