server_fn/response/
generic.rs1use super::{Res, TryRes};
16use crate::error::{
17 FromServerFnError, IntoAppError, ServerFnErrorErr, ServerFnErrorWrapper,
18 SERVER_FN_ERROR_HEADER,
19};
20use bytes::Bytes;
21use futures::{Stream, TryStreamExt};
22use http::{header, HeaderValue, Response, StatusCode};
23use std::pin::Pin;
24use throw_error::Error;
25
26pub enum Body {
29 Sync(Bytes),
31
32 Async(Pin<Box<dyn Stream<Item = Result<Bytes, Error>> + Send + 'static>>),
36}
37
38impl From<String> for Body {
39 fn from(value: String) -> Self {
40 Body::Sync(Bytes::from(value))
41 }
42}
43
44impl<E> TryRes<E> for Response<Body>
45where
46 E: Send + Sync + FromServerFnError,
47{
48 fn try_from_string(content_type: &str, data: String) -> Result<Self, E> {
49 let builder = http::Response::builder();
50 builder
51 .status(200)
52 .header(http::header::CONTENT_TYPE, content_type)
53 .body(data.into())
54 .map_err(|e| {
55 ServerFnErrorErr::Response(e.to_string()).into_app_error()
56 })
57 }
58
59 fn try_from_bytes(content_type: &str, data: Bytes) -> Result<Self, E> {
60 let builder = http::Response::builder();
61 builder
62 .status(200)
63 .header(http::header::CONTENT_TYPE, content_type)
64 .body(Body::Sync(data))
65 .map_err(|e| {
66 ServerFnErrorErr::Response(e.to_string()).into_app_error()
67 })
68 }
69
70 fn try_from_stream(
71 content_type: &str,
72 data: impl Stream<Item = Result<Bytes, E>> + Send + 'static,
73 ) -> Result<Self, E> {
74 let builder = http::Response::builder();
75 builder
76 .status(200)
77 .header(http::header::CONTENT_TYPE, content_type)
78 .body(Body::Async(Box::pin(
79 data.map_err(ServerFnErrorWrapper).map_err(Error::from),
80 )))
81 .map_err(|e| {
82 ServerFnErrorErr::Response(e.to_string()).into_app_error()
83 })
84 }
85}
86
87impl Res for Response<Body> {
88 fn error_response(path: &str, err: String) -> Self {
89 Response::builder()
90 .status(http::StatusCode::INTERNAL_SERVER_ERROR)
91 .header(SERVER_FN_ERROR_HEADER, path)
92 .body(err.into())
93 .unwrap()
94 }
95
96 fn redirect(&mut self, path: &str) {
97 if let Ok(path) = HeaderValue::from_str(path) {
98 self.headers_mut().insert(header::LOCATION, path);
99 *self.status_mut() = StatusCode::FOUND;
100 }
101 }
102}