tosca_controller/
response.rs

1use tosca::response::{InfoResponse, OkResponse, SerialResponse};
2
3use reqwest::Response as ReqwestResponse;
4
5use serde::{Serialize, de::DeserializeOwned};
6
7use crate::error::{Error, ErrorKind, Result};
8
9// TODO:
10// OkCollector --> Save Ok responses in order to maintain a history.
11// SerialCollector --> Save serial responses in order to maintain a history.
12// InfoCollector --> Save Info responses in order to maintain a history.
13// StreamCollector --> Save information about a Stream Response before and after
14
15async fn json_response<T>(response: ReqwestResponse) -> Result<T>
16where
17    T: Serialize + DeserializeOwned,
18{
19    response
20        .json::<T>()
21        .await
22        .map_err(|e| Error::new(ErrorKind::JsonResponse, format!("Json error caused by {e}")))
23}
24
25/// An [`OkResponse`] body parser.
26pub struct OkResponseParser(ReqwestResponse);
27
28impl OkResponseParser {
29    /// Parses the internal response body to retrieve an [`OkResponse`].
30    ///
31    /// # Errors
32    ///
33    /// If the response body does not contain a valid [`OkResponse`], a
34    /// parsing error will be raised. This may occur due to an incorrect format
35    /// or because the binary data contains syntactic or semantic errors.
36    pub async fn parse_body(self) -> Result<OkResponse> {
37        json_response::<OkResponse>(self.0).await
38    }
39
40    pub(crate) const fn new(response: ReqwestResponse) -> Self {
41        Self(response)
42    }
43}
44
45/// A [`SerialResponse`] body parser.
46pub struct SerialResponseParser(ReqwestResponse);
47
48impl SerialResponseParser {
49    /// Parses the internal response body to retrieve a [`SerialResponse`].
50    ///
51    /// # Errors
52    ///
53    /// If the response body does not contain a valid [`SerialResponse`], a
54    /// parsing error will be raised. This may occur due to an incorrect format
55    /// or because the binary data contains syntactic or semantic errors.
56    pub async fn parse_body<T: Serialize + DeserializeOwned>(self) -> Result<SerialResponse<T>> {
57        json_response::<SerialResponse<T>>(self.0).await
58    }
59
60    pub(crate) const fn new(response: ReqwestResponse) -> Self {
61        Self(response)
62    }
63}
64
65/// An [`InfoResponse`] body parser.
66pub struct InfoResponseParser(ReqwestResponse);
67
68impl InfoResponseParser {
69    /// Parses the internal response body to retrieve an [`InfoResponse`].
70    ///
71    /// # Errors
72    ///
73    /// If the response body does not contain a valid [`InfoResponse`], a
74    /// parsing error will be raised. This may occur due to an incorrect format
75    /// or because the binary data contains syntactic or semantic errors.
76    pub async fn parse_body(self) -> Result<InfoResponse> {
77        json_response::<InfoResponse>(self.0).await
78    }
79
80    pub(crate) const fn new(response: ReqwestResponse) -> Self {
81        Self(response)
82    }
83}
84
85/// A byte stream response body parser.
86#[cfg(feature = "stream")]
87pub struct StreamResponse(ReqwestResponse);
88
89#[cfg(feature = "stream")]
90impl StreamResponse {
91    /// Opens a bytes stream from the response received from a device.
92    ///
93    /// # Errors
94    ///
95    /// Byte stream parsing may fail due to network errors or data corruption.
96    pub fn open_stream(self) -> impl futures_util::Stream<Item = Result<bytes::Bytes>> {
97        use futures_util::TryStreamExt;
98        self.0.bytes_stream().map_err(|e| {
99            Error::new(
100                ErrorKind::StreamResponse,
101                format!("Stream error caused by {e}"),
102            )
103        })
104    }
105
106    pub(crate) const fn new(response: ReqwestResponse) -> Self {
107        Self(response)
108    }
109}
110
111/// All response types supported by a `tosca` device.
112///
113/// Each response includes a dedicated body parser to extract the embedded data.
114pub enum Response {
115    /// A skipped response indicates a request that is not sent due to
116    /// privacy policy rules.
117    Skipped,
118    /// An [`OkResponse`] body.
119    OkBody(OkResponseParser),
120    /// A [`SerialResponse`] body.
121    SerialBody(SerialResponseParser),
122    /// An [`InfoResponse`] body.
123    InfoBody(InfoResponseParser),
124    /// A byte stream response body.
125    #[cfg(feature = "stream")]
126    StreamBody(StreamResponse),
127}