1use bytes::Bytes;
2use futures::{Stream, StreamExt};
3use leptos::server_fn::error::{
4 ServerFnError, ServerFnErrorErr, ServerFnErrorSerde, SERVER_FN_ERROR_HEADER,
5};
6use leptos::server_fn::response::Res;
7use spin_sdk::http::Headers;
8use std::pin::Pin;
9use std::{
10 fmt::{Debug, Display},
11 str::FromStr,
12};
13use typed_builder::TypedBuilder;
14pub struct SpinResponse(pub SpinResponseParts);
17
18#[derive(TypedBuilder)]
19pub struct SpinResponseParts {
20 pub status_code: u16,
21 pub headers: Headers,
22 pub body: SpinBody,
23}
24
25pub enum SpinBody {
28 Plain(Vec<u8>),
29 Streaming(Pin<Box<dyn Stream<Item = Result<Bytes, Box<dyn std::error::Error>>> + Send>>),
30}
31impl<CustErr> Res<CustErr> for SpinResponse
32where
33 CustErr: Send + Sync + Debug + FromStr + Display + 'static,
34{
35 fn try_from_string(content_type: &str, data: String) -> Result<Self, ServerFnError<CustErr>> {
36 let headers =
37 Headers::from_list(&[("Content-Type".to_string(), content_type.as_bytes().to_vec())])
38 .expect("Failed to create Headers from String Response Input");
39 let parts = SpinResponseParts::builder()
40 .status_code(200)
41 .headers(headers)
42 .body(SpinBody::Plain(data.into()))
43 .build();
44 Ok(SpinResponse(parts))
45 }
46
47 fn try_from_bytes(content_type: &str, data: Bytes) -> Result<Self, ServerFnError<CustErr>> {
48 let headers = Headers::from_list(&[("Content-Type".to_string(), content_type.into())])
49 .expect("Failed to create Headers from Bytes Response Input");
50 let parts = SpinResponseParts::builder()
51 .status_code(200)
52 .headers(headers)
53 .body(SpinBody::Plain(data.into()))
54 .build();
55 Ok(SpinResponse(parts))
56 }
57
58 fn try_from_stream(
59 content_type: &str,
60 data: impl Stream<Item = Result<Bytes, ServerFnError<CustErr>>> + Send + 'static,
61 ) -> Result<Self, ServerFnError<CustErr>> {
62 let body = data.map(|n| {
63 n.map_err(ServerFnErrorErr::from)
64 .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
65 });
66
67 let headers = Headers::from_list(&[("Content-Type".to_string(), content_type.into())])
68 .expect("Failed to create Headers from Stream Response Input");
69 let parts = SpinResponseParts::builder()
70 .status_code(200)
71 .headers(headers)
72 .body(SpinBody::Streaming(Box::pin(body)))
73 .build();
74 Ok(SpinResponse(parts))
75 }
76
77 fn error_response(path: &str, err: &ServerFnError<CustErr>) -> Self {
78 let headers = Headers::from_list(&[(SERVER_FN_ERROR_HEADER.to_string(), path.into())])
79 .expect("Failed to create Error Response. This should be impossible");
80 let parts = SpinResponseParts::builder()
81 .status_code(500)
82 .headers(headers)
83 .body(SpinBody::Plain(
84 err.ser().unwrap_or_else(|_| err.to_string()).into(),
85 ))
86 .build();
87 SpinResponse(parts)
88 }
89
90 fn redirect(&mut self, _path: &str) {
91 }
97}