Skip to main content

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