1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use bytes::Bytes;
use futures::{Stream, StreamExt};
use leptos::server_fn::{error::ServerFnError, request::Req};
use spin_sdk::http::IncomingRequest;
use std::borrow::Cow;

/// This is here because the orphan rule does not allow us to implement it on IncomingRequest with
/// the generic error. So we have to wrap it to make it happy
#[derive(Debug)]
pub struct SpinRequest {
    pub req: IncomingRequest,
    pub path_with_query: Option<String>,
}
impl SpinRequest {
    pub fn new_from_req(req: IncomingRequest) -> Self {
        SpinRequest {
            path_with_query: req.path_with_query(),
            req,
        }
    }
}

impl<CustErr> Req<CustErr> for SpinRequest
where
    CustErr: 'static,
{
    fn as_query(&self) -> Option<&str> {
        self.path_with_query
            .as_ref()
            .and_then(|n| n.split_once('?').map(|(_, query)| query))
    }

    fn to_content_type(&self) -> Option<Cow<'_, str>> {
        self.req
            .headers()
            .get(&"Content-Type".to_string())
            .first()
            .map(|h| String::from_utf8_lossy(h))
            .map(Cow::into_owned)
            .map(Cow::<'static, str>::Owned)
    }

    fn accepts(&self) -> Option<Cow<'_, str>> {
        self.req
            .headers()
            .get(&"Accept".to_string())
            .first()
            .map(|h| String::from_utf8_lossy(h))
            .map(Cow::into_owned)
            .map(Cow::<'static, str>::Owned)
    }

    fn referer(&self) -> Option<Cow<'_, str>> {
        self.req
            .headers()
            .get(&"Referer".to_string())
            .first()
            .map(|h| String::from_utf8_lossy(h))
            .map(Cow::into_owned)
            .map(Cow::<'static, str>::Owned)
    }

    async fn try_into_bytes(self) -> Result<Bytes, ServerFnError<CustErr>> {
        let buf = self
            .req
            .into_body()
            .await
            .map_err(|e| ServerFnError::Deserialization(e.to_string()))?;
        Ok(Bytes::copy_from_slice(&buf))
    }

    async fn try_into_string(self) -> Result<String, ServerFnError<CustErr>> {
        let bytes = self.try_into_bytes().await?;
        String::from_utf8(bytes.to_vec()).map_err(|e| ServerFnError::Deserialization(e.to_string()))
    }

    fn try_into_stream(
        self,
    ) -> Result<
        impl Stream<Item = Result<Bytes, ServerFnError>> + Send + 'static,
        ServerFnError<CustErr>,
    > {
        Ok(self.req.into_body_stream().map(|chunk| {
            chunk
                .map(|c| Bytes::copy_from_slice(&c))
                .map_err(|e| ServerFnError::Deserialization(e.to_string()))
        }))
    }
}