synd_client/client/
session.rs1use std::fmt::Debug;
2
3use reqwest::StatusCode;
4use serde::{Serialize, de::DeserializeOwned};
5use synd_protocol::session::{
6 CloseSessionErrorResponse, CloseSessionRequest, CloseSessionResponse, OpenSessionErrorResponse,
7 OpenSessionRequest, OpenSessionResponse, RenewSessionErrorResponse, RenewSessionRequest,
8 RenewSessionResponse,
9};
10
11use super::Client;
12use crate::SyndApiError;
13
14enum SessionOutcome<T, E> {
15 Accepted(T),
16 Rejected(E),
17}
18
19trait SessionRequest: Serialize + Debug {
20 type Response: DeserializeOwned;
21 type Rejection: DeserializeOwned;
22
23 const PATH: &'static str;
24 const REJECTION_STATUS: StatusCode;
25 const UNEXPECTED_RESPONSE_CONTEXT: &'static str;
26
27 fn rejected(response: Self::Rejection) -> SyndApiError;
28
29 async fn decode_response(
30 response: reqwest::Response,
31 ) -> Result<SessionOutcome<Self::Response, Self::Rejection>, SyndApiError> {
32 let status = response.status();
33
34 if status.is_success() {
35 return response
36 .json()
37 .await
38 .map(SessionOutcome::Accepted)
39 .map_err(SyndApiError::DecodeResponse);
40 }
41 if status == Self::REJECTION_STATUS {
42 return response
43 .json()
44 .await
45 .map(SessionOutcome::Rejected)
46 .map_err(SyndApiError::DecodeResponse);
47 }
48
49 response
50 .error_for_status()
51 .map_err(SyndApiError::from_status_error)?;
52 Err(SyndApiError::UnexpectedResponse {
53 context: Self::UNEXPECTED_RESPONSE_CONTEXT,
54 })
55 }
56}
57
58impl SessionRequest for OpenSessionRequest {
59 type Response = OpenSessionResponse;
60 type Rejection = OpenSessionErrorResponse;
61
62 const PATH: &'static str = "/session/open";
63 const REJECTION_STATUS: StatusCode = StatusCode::CONFLICT;
64 const UNEXPECTED_RESPONSE_CONTEXT: &'static str = "session open";
65
66 fn rejected(response: Self::Rejection) -> SyndApiError {
67 SyndApiError::OpenSession(response)
68 }
69}
70
71impl SessionRequest for RenewSessionRequest {
72 type Response = RenewSessionResponse;
73 type Rejection = RenewSessionErrorResponse;
74
75 const PATH: &'static str = "/session/renew";
76 const REJECTION_STATUS: StatusCode = StatusCode::NOT_FOUND;
77 const UNEXPECTED_RESPONSE_CONTEXT: &'static str = "session renew";
78
79 fn rejected(response: Self::Rejection) -> SyndApiError {
80 SyndApiError::RenewSession(response)
81 }
82}
83
84impl SessionRequest for CloseSessionRequest {
85 type Response = CloseSessionResponse;
86 type Rejection = CloseSessionErrorResponse;
87
88 const PATH: &'static str = "/session/close";
89 const REJECTION_STATUS: StatusCode = StatusCode::NOT_FOUND;
90 const UNEXPECTED_RESPONSE_CONTEXT: &'static str = "session close";
91
92 fn rejected(response: Self::Rejection) -> SyndApiError {
93 SyndApiError::CloseSession(response)
94 }
95}
96
97impl Client {
98 pub async fn open_session(
99 &self,
100 request: OpenSessionRequest,
101 ) -> Result<OpenSessionResponse, SyndApiError> {
102 self.execute_session(request).await
103 }
104
105 pub async fn close_session(
106 &self,
107 request: CloseSessionRequest,
108 ) -> Result<CloseSessionResponse, SyndApiError> {
109 self.execute_session(request).await
110 }
111
112 pub async fn renew_session(
113 &self,
114 request: RenewSessionRequest,
115 ) -> Result<RenewSessionResponse, SyndApiError> {
116 self.execute_session(request).await
117 }
118
119 async fn execute_session<R>(&self, request: R) -> Result<R::Response, SyndApiError>
120 where
121 R: SessionRequest,
122 {
123 let response = self.send_session_request(&request).await?;
124 let outcome = R::decode_response(response).await?;
125
126 match outcome {
127 SessionOutcome::Accepted(response) => Ok(response),
128 SessionOutcome::Rejected(rejection) => Err(R::rejected(rejection)),
129 }
130 }
131
132 async fn send_session_request<R>(&self, request: &R) -> Result<reqwest::Response, SyndApiError>
133 where
134 R: SessionRequest,
135 {
136 let mut request = self
137 .client
138 .post(self.endpoint.join(R::PATH)?)
139 .json(request)
140 .build()
141 .map_err(SyndApiError::BuildRequest)?;
142 self.authentication
143 .apply_authorization_header(request.headers_mut())?;
144 self.client
145 .execute(request)
146 .await
147 .map_err(SyndApiError::from_send_error)
148 }
149}