xnode_manager_sdk/utils/
session.rs

1use reqwest::{
2    Body, Client, Response,
3    header::{CONTENT_TYPE, HeaderValue},
4};
5use serde::{Serialize, de::DeserializeOwned};
6use serde_json::to_value;
7
8#[derive(Debug)]
9pub struct Session {
10    pub reqwest_client: Client,
11    pub base_url: String,
12}
13
14pub trait ResponseData<T: Sized> {
15    fn from_response(response: Response) -> impl Future<Output = Result<T, Error>>;
16}
17impl<Data: DeserializeOwned> ResponseData<Data> for Data {
18    async fn from_response(response: Response) -> Result<Self, Error> {
19        serde_json::from_slice(&response.bytes().await.map_err(Error::ReqwestError)?)
20            .map_err(Error::SerdeJsonError)
21    }
22}
23
24pub trait QueryData {
25    fn create_query(&self) -> Result<Vec<(String, String)>, Error>;
26}
27impl<Data: Serialize> QueryData for Data {
28    fn create_query(&self) -> Result<Vec<(String, String)>, Error> {
29        Ok(to_value(self)
30            .map_err(Error::SerdeJsonError)?
31            .as_object()
32            .map(|x| {
33                x.into_iter()
34                    .filter_map(|(key, value)| match value {
35                        serde_json::Value::String(s) => Some((key.clone(), s.clone())),
36                        serde_json::Value::Number(n) => Some((key.clone(), n.to_string())),
37                        _ => None,
38                    })
39                    .collect()
40            })
41            .unwrap_or(vec![]))
42    }
43}
44
45pub trait BodyData {
46    fn create_body(&self) -> Result<Body, Error>;
47}
48impl<Data: Serialize> BodyData for Data {
49    fn create_body(&self) -> Result<Body, Error> {
50        Ok(serde_json::to_vec(&self)
51            .map_err(Error::SerdeJsonError)?
52            .into())
53    }
54}
55
56#[derive(Default)]
57pub struct Empty {}
58impl ResponseData<Empty> for Empty {
59    async fn from_response(_response: Response) -> Result<Self, Error> {
60        Ok(Self {})
61    }
62}
63impl QueryData for Empty {
64    fn create_query(&self) -> Result<Vec<(String, String)>, Error> {
65        Ok(vec![])
66    }
67}
68impl BodyData for Empty {
69    fn create_body(&self) -> Result<Body, Error> {
70        Ok(Body::default())
71    }
72}
73
74#[derive(Debug)]
75pub struct SessionGetInput<'a, Path, Query: QueryData> {
76    pub session: &'a Session,
77    pub path: Path,
78    pub query: Query,
79}
80pub type SessionGetOutput<Output> = Result<Output, Error>;
81#[derive(Debug)]
82pub struct SessionPostInput<'a, Path, Data: BodyData> {
83    pub session: &'a Session,
84    pub path: Path,
85    pub data: Data,
86}
87pub type SessionPostOutput<Output> = Result<Output, Error>;
88#[derive(Debug)]
89pub enum Error {
90    XnodeManagerSDKError,
91    ReqwestError(reqwest::Error),
92    SerdeJsonError(serde_json::Error),
93}
94
95impl<'a> SessionGetInput<'a, Empty, Empty> {
96    pub fn new(session: &'a Session) -> Self {
97        Self {
98            session,
99            path: Empty::default(),
100            query: Empty::default(),
101        }
102    }
103}
104impl<'a, Path> SessionGetInput<'a, Path, Empty> {
105    pub fn new_with_path(session: &'a Session, path: Path) -> Self {
106        Self {
107            session,
108            path,
109            query: Empty::default(),
110        }
111    }
112}
113impl<'a, Query: Serialize> SessionGetInput<'a, Empty, Query> {
114    pub fn new_with_query(session: &'a Session, query: Query) -> Self {
115        Self {
116            session,
117            path: Empty::default(),
118            query,
119        }
120    }
121}
122
123impl<'a> SessionPostInput<'a, Empty, Empty> {
124    pub fn new(session: &'a Session) -> Self {
125        Self {
126            session,
127            path: Empty::default(),
128            data: Empty::default(),
129        }
130    }
131}
132impl<'a, Path> SessionPostInput<'a, Path, Empty> {
133    pub fn new_with_path(session: &'a Session, path: Path) -> Self {
134        Self {
135            session,
136            path,
137            data: Empty::default(),
138        }
139    }
140}
141impl<'a, Data: Serialize> SessionPostInput<'a, Empty, Data> {
142    pub fn new_with_data(session: &'a Session, data: Data) -> Self {
143        Self {
144            session,
145            path: Empty::default(),
146            data,
147        }
148    }
149}
150
151pub async fn session_get<
152    Output: ResponseData<Output>,
153    Path,
154    Query: QueryData,
155    PathOutput: Into<String>,
156>(
157    input: SessionGetInput<'_, Path, Query>,
158    scope: String,
159    path: fn(Path) -> PathOutput,
160) -> SessionGetOutput<Output> {
161    let session = input.session;
162    Output::from_response(
163        session
164            .reqwest_client
165            .get(format!(
166                "{}{}{}",
167                session.base_url,
168                scope,
169                path(input.path).into()
170            ))
171            .query(&input.query.create_query()?)
172            .send()
173            .await
174            .map_err(Error::ReqwestError)?,
175    )
176    .await
177}
178
179pub async fn session_post<
180    Output: ResponseData<Output>,
181    Path,
182    Data: BodyData,
183    PathOutput: Into<String>,
184>(
185    input: SessionPostInput<'_, Path, Data>,
186    scope: String,
187    path: fn(Path) -> PathOutput,
188) -> SessionPostOutput<Output> {
189    let session = input.session;
190    Output::from_response(
191        session
192            .reqwest_client
193            .post(format!(
194                "{}{}{}",
195                session.base_url,
196                scope,
197                path(input.path).into()
198            ))
199            .header(CONTENT_TYPE, HeaderValue::from_static("application/json"))
200            .body(input.data.create_body()?)
201            .send()
202            .await
203            .map_err(Error::ReqwestError)?,
204    )
205    .await
206}