1use commands_module::CommandRequest;
2use tokio::sync::mpsc;
3
4pub mod commands_module;
5pub mod common;
6pub mod credentials_module;
7pub mod locations_module;
8pub mod sessions_module;
9pub mod types;
10pub mod versions_module;
11
12mod client;
13mod context;
14mod error;
15mod party;
16mod party_store;
17mod sessions_store;
18mod versions_store;
19
20pub use {
21 client::Client,
22 commands_module::{CommandsModule, ResponsePromise, ResultPromise},
23 common::*,
24 context::{Context, ContextResult, IntoContextResult},
25 credentials_module::CredentialsModule,
26 error::{ClientError, Error, HubError, ServerError},
27 party::Party,
28 party_store::PartyStore,
29 sessions_module::SessionsModule,
30 sessions_store::SessionsStore,
31 types::*,
32 versions_module::VersionsModule,
33 versions_store::{SimpleVersionsStore, VersionsStore},
34};
35
36use std::borrow::Cow;
37
38#[cfg(feature = "warp")]
39pub mod warp {
40 pub use super::context::warp_extensions::*;
41}
42
43pub type Result<T> = std::result::Result<T, Error>;
46
47#[derive(serde::Serialize)]
49pub struct Response {
50 #[serde(skip)]
51 pub http_status: http::StatusCode,
52
53 #[serde(rename = "status_code")]
54 pub code: u32,
55
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub data: Option<serde_json::Value>,
58
59 #[serde(rename = "status_message", skip_serializing_if = "Option::is_none")]
60 pub message: Option<Cow<'static, str>>,
61
62 pub timestamp: types::DateTime,
63
64 #[serde(skip)]
65 pub request_id: Option<String>,
66
67 #[serde(skip)]
68 pub correlation_id: Option<String>,
69}
70
71impl Response {
72 pub fn into_http<B>(self) -> http::Response<B>
73 where
74 B: From<Vec<u8>>,
75 {
76 let http_status = self.http_status;
77 let body = serde_json::to_vec(&self).expect("Serializing reply");
78
79 let mut b = http::Response::builder()
80 .status(http_status)
81 .header("content-type", "application/json");
82
83 if let Some(request_id) = self.request_id {
84 b = b.header("X-Request-ID", request_id);
85 }
86
87 if let Some(correlation_id) = self.correlation_id {
88 b = b.header("X-Correlation-ID", correlation_id);
89 }
90
91 b.body(body.into()).expect("Creating OCPI Response")
92 }
93
94 pub fn from_err(err: Error) -> Self {
95 Self {
96 http_status: err.http_status_code(),
97 code: err.code(),
98 data: None,
99 message: Some(Cow::Owned(err.to_string())),
100 timestamp: types::DateTime::now(),
101 request_id: None,
102 correlation_id: None,
103 }
104 }
105}
106
107impl<T> From<ContextResult<T>> for Response
108where
109 T: serde::Serialize,
110{
111 fn from(
112 ContextResult {
113 result,
114 context:
115 Context {
116 correlation_id,
117 request_id,
118 ..
119 },
120 }: ContextResult<T>,
121 ) -> Self {
122 match result {
123 Ok(data) => Response {
124 http_status: http::StatusCode::OK,
125 code: 1000,
126 data: Some(serde_json::to_value(&data).expect("Serializing data")),
127 message: Some(Cow::Borrowed("Success")),
128 timestamp: types::DateTime::now(),
129 request_id: Some(request_id),
130 correlation_id: Some(correlation_id),
131 },
132
133 Err(err) => Response::from_err(err),
134 }
135 }
136}
137
138impl<T> From<Result<T>> for Response
139where
140 T: serde::Serialize,
141{
142 fn from(res: Result<T>) -> Self {
143 match res {
144 Ok(data) => Response {
145 http_status: http::StatusCode::OK,
146 code: 1000,
147 data: Some(serde_json::to_value(&data).expect("Serializing response")),
148 message: Some(Cow::Borrowed("Success")),
149 timestamp: types::DateTime::now(),
150 request_id: None,
151 correlation_id: None,
152 },
153
154 Err(err) => Response::from_err(err),
155 }
156 }
157}
158
159impl<T> From<Result<Paginated<T>>> for Response
160where
161 T: serde::Serialize,
162{
163 fn from(res: Result<Paginated<T>>) -> Self {
164 match res {
165 Ok(paginated) => Response {
166 http_status: http::StatusCode::OK,
167 code: 1000,
168 data: Some(serde_json::to_value(&paginated.items).expect("Serializing data")),
169 message: Some(Cow::Borrowed("Success")),
170 timestamp: types::DateTime::now(),
171 request_id: None,
172 correlation_id: None,
173 },
174
175 Err(err) => Response::from_err(err),
176 }
177 }
178}
179
180trait CommandsHandler
181where
182 Self: Clone + Send + Sync + 'static,
183{
184}
185
186#[derive(Clone)]
187pub struct MpscCommandsHandler<P>(mpsc::Sender<CommandRequest<P>>);
188
189#[derive(Clone)]
190pub struct NoCommandsHandler;
191
192impl<P> CommandsHandler for MpscCommandsHandler<P> where P: Party {}
193impl CommandsHandler for NoCommandsHandler {}
194
195#[derive(Clone)]
200pub struct Cpo<DB, CH>
201where
202 DB: Store,
203{
204 db: DB,
205 client: Client,
206 commands_handler: CH,
207}
208
209impl<DB> Cpo<DB, NoCommandsHandler>
210where
211 DB: Store,
212{
213 pub fn new(db: DB, client: Client) -> Self {
220 Self {
221 db,
222 client,
223 commands_handler: NoCommandsHandler,
224 }
225 }
226}
227impl<DB> Cpo<DB, NoCommandsHandler>
228where
229 DB: Store,
230{
231 pub fn with_mpsc_commands_handler(
232 self,
233 tx: mpsc::Sender<CommandRequest<DB::PartyModel>>,
234 ) -> Cpo<DB, MpscCommandsHandler<DB::PartyModel>> {
235 Cpo {
236 db: self.db,
237 client: self.client,
238 commands_handler: MpscCommandsHandler(tx),
239 }
240 }
241}
242
243pub enum Authorized<P, R> {
244 Party(P),
245 Registration(R),
246}
247
248impl<P, R> Authorized<P, R>
249where
250 P: Party,
251{
252 pub fn party(self) -> Result<P> {
253 match self {
254 Self::Party(party) => Ok(party),
255 _ => Err(Error::unauthorized("Invalid Token")),
256 }
257 }
258
259 pub fn registration(self) -> Result<R> {
260 match self {
261 Self::Registration(temp) => Ok(temp),
262 _ => Err(Error::unauthorized("Invalid Token")),
263 }
264 }
265}
266
267#[async_trait::async_trait]
268pub trait Store
269where
270 Self: Clone + Send + Sync + 'static,
271{
272 type PartyModel: Party;
273 type RegistrationModel: Send + Sync + 'static;
274
275 async fn get_authorized(
276 &self,
277 token: types::CredentialsToken,
278 ) -> Result<Authorized<Self::PartyModel, Self::RegistrationModel>>;
279}