1use http::Method;
16use serde::Serialize;
17use serde::de::DeserializeOwned;
18
19use crate::convert::wire::{BridgeError, ObjectKind};
20use crate::transport::{
21 OcpiError, OcpiRequest, Page, PageQuery, Patch, ReceiverEndpoint, RequestIds, RoutingHeaders,
22 SenderEndpoint,
23};
24use crate::types::{PartyRef, Url, Validate};
25use crate::v2_3_0::tokens::TokenType;
26use crate::{InterfaceRole, ModuleId};
27
28use super::http::{Transport, check_outgoing};
29use super::paging::PageStream;
30use super::peer::Peer;
31
32#[derive(Clone, Debug)]
34pub struct ModuleClient<'a> {
35 transport: &'a Transport,
36 peer: &'a Peer,
37 module: ModuleId,
38 from: PartyRef,
39 to: Option<PartyRef>,
40}
41
42impl<'a> ModuleClient<'a> {
43 #[must_use]
48 pub fn new(transport: &'a Transport, peer: &'a Peer, module: ModuleId, from: PartyRef) -> Self {
49 let to = peer.default_party().cloned();
50 Self { transport, peer, module, from, to }
51 }
52
53 #[must_use]
55 pub fn to(mut self, party: PartyRef) -> Self {
56 self.to = Some(party);
57 self
58 }
59
60 #[must_use]
65 pub fn open_routing(mut self) -> Self {
66 self.to = None;
67 self
68 }
69
70 #[must_use]
72 pub const fn peer(&self) -> &Peer {
73 self.peer
74 }
75
76 #[must_use]
78 pub fn sender_endpoint(&self) -> Option<SenderEndpoint> {
79 self.peer.sender(&self.module)
80 }
81
82 #[must_use]
84 pub fn receiver_endpoint(&self) -> Option<ReceiverEndpoint> {
85 self.peer.receiver(&self.module)
86 }
87
88 fn routing(&self) -> RoutingHeaders {
89 RoutingHeaders { to: self.to.clone(), from: self.from.clone() }
90 }
91
92 fn request(&self, method: Method, url: Url) -> OcpiRequest {
93 OcpiRequest::new(method, url, self.module.clone()).routed(self.routing())
94 }
95
96 fn missing(&self, role: InterfaceRole) -> OcpiError {
97 OcpiError::NotFound(format!(
98 "the peer does not implement the {} interface of the {} module",
99 role, self.module
100 ))
101 }
102
103 pub async fn get<T: DeserializeOwned>(&self, url: Url) -> Result<T, OcpiError> {
109 let request = self.request(Method::GET, url);
110 self.transport.send(&request, self.peer.token(), self.peer.quirks()).await
111 }
112
113 pub async fn get_page<T: DeserializeOwned>(&self, url: Url) -> Result<Page<T>, OcpiError> {
119 let request = self.request(Method::GET, url);
120 self.transport.send_page(&request, self.peer.token(), self.peer.quirks()).await
121 }
122
123 pub async fn put<T: Serialize + Validate>(&self, url: Url, body: &T) -> Result<(), OcpiError> {
130 check_outgoing(body, self.transport.config())?;
131 let request = self.request(Method::PUT, url).with_body(body)?;
132 let (response, _) = self
133 .transport
134 .send_with_headers::<serde_json::Value>(&request, self.peer.token(), self.peer.quirks())
135 .await?;
136 if response.is_success() { Ok(()) } else { Err(response.into_result().unwrap_err()) }
137 }
138
139 pub async fn post<B: Serialize + Validate, T: DeserializeOwned>(
145 &self,
146 url: Url,
147 body: &B,
148 ) -> Result<T, OcpiError> {
149 check_outgoing(body, self.transport.config())?;
150 let request = self.request(Method::POST, url).with_body(body)?;
151 self.transport.send(&request, self.peer.token(), self.peer.quirks()).await
152 }
153
154 pub async fn patch<T>(&self, url: Url, patch: &Patch<T>) -> Result<(), OcpiError> {
164 if patch.last_updated().is_none() {
165 return Err(OcpiError::Decode {
166 path: "/last_updated".to_owned(),
167 message: "a PATCH must carry `last_updated`".to_owned(),
168 });
169 }
170 let request = self.request(Method::PATCH, url).with_body(patch.as_value())?;
171 let (response, _) = self
172 .transport
173 .send_with_headers::<serde_json::Value>(&request, self.peer.token(), self.peer.quirks())
174 .await?;
175 if response.is_success() { Ok(()) } else { Err(response.into_result().unwrap_err()) }
176 }
177
178 pub async fn delete(&self, url: Url) -> Result<(), OcpiError> {
184 let request = self.request(Method::DELETE, url);
185 let (response, _) = self
186 .transport
187 .send_with_headers::<serde_json::Value>(&request, self.peer.token(), self.peer.quirks())
188 .await?;
189 if response.is_success() { Ok(()) } else { Err(response.into_result().unwrap_err()) }
190 }
191
192 fn foreign_version(&self) -> Option<&crate::VersionNumber> {
195 let version = self.peer.version();
196 (*version != crate::CANONICAL_VERSION).then_some(version)
197 }
198
199 pub async fn get_bridged<T: DeserializeOwned>(&self, url: Url, kind: ObjectKind) -> Result<T, OcpiError> {
207 let Some(theirs) = self.foreign_version() else { return self.get(url).await };
208 let value: serde_json::Value = self.get(url).await?;
209 let converted =
210 kind.bridge(theirs, &crate::CANONICAL_VERSION, value).map_err(|e| bridge_error(e, kind))?;
211 decode(converted.value)
212 }
213
214 pub async fn put_bridged<T: Serialize + Validate>(
221 &self,
222 url: Url,
223 body: &T,
224 kind: ObjectKind,
225 ) -> Result<(), OcpiError> {
226 check_outgoing(body, self.transport.config())?;
227 let Some(value) = self.for_peer(body, kind)? else { return self.put(url, body).await };
228 let request = self.request(Method::PUT, url).with_body(&value)?;
229 self.expect_success(request).await
230 }
231
232 pub async fn post_bridged<B: Serialize + Validate, T: DeserializeOwned>(
243 &self,
244 url: Url,
245 body: &B,
246 request_kind: Option<ObjectKind>,
247 response_kind: Option<ObjectKind>,
248 ) -> Result<T, OcpiError> {
249 check_outgoing(body, self.transport.config())?;
250 let Some(theirs) = self.foreign_version().cloned() else {
251 return self.post(url, body).await;
252 };
253 let request = match request_kind.and_then(|k| self.for_peer(body, k).transpose()) {
254 Some(value) => self.request(Method::POST, url).with_body(&value?)?,
255 None => self.request(Method::POST, url).with_body(body)?,
256 };
257 let answer: serde_json::Value =
258 self.transport.send(&request, self.peer.token(), self.peer.quirks()).await?;
259 let Some(kind) = response_kind else { return decode(answer) };
260 let converted =
261 kind.bridge(&theirs, &crate::CANONICAL_VERSION, answer).map_err(|e| bridge_error(e, kind))?;
262 decode(converted.value)
263 }
264
265 pub async fn patch_bridged<T>(
277 &self,
278 url: Url,
279 patch: &Patch<T>,
280 kind: ObjectKind,
281 ) -> Result<(), OcpiError> {
282 if let Some(theirs) = self.foreign_version()
283 && !kind.patch_crosses_unchanged(&patch.fields())
284 {
285 return Err(OcpiError::Unsupported(format!(
286 "this PATCH writes {:?}, and a {kind} does not carry {} the same way in OCPI \
287 {theirs} as in OCPI {}; a merge patch is not an object, so it cannot be \
288 translated. GET the object and PUT it back instead, which is the recovery the \
289 specification prescribes for a refused PATCH",
290 patch.fields(),
291 kind.divergent_fields().join(", "),
292 crate::CANONICAL_VERSION,
293 )));
294 }
295 self.patch(url, patch).await
296 }
297
298 pub fn list_bridged<T: DeserializeOwned + Send + 'static>(
304 &self,
305 query: PageQuery,
306 kind: ObjectKind,
307 ) -> Result<PageStream<'a, T>, OcpiError> {
308 Ok(self.list(query)?.bridging(kind))
309 }
310
311 fn for_peer<T: Serialize>(
313 &self,
314 body: &T,
315 kind: ObjectKind,
316 ) -> Result<Option<serde_json::Value>, OcpiError> {
317 let Some(theirs) = self.foreign_version() else { return Ok(None) };
318 let value = serde_json::to_value(body)
319 .map_err(|e| OcpiError::Decode { path: "/".to_owned(), message: e.to_string() })?;
320 let converted =
321 kind.bridge(&crate::CANONICAL_VERSION, theirs, value).map_err(|e| bridge_error(e, kind))?;
322 if let Some(note) = converted.lossy.to_status_message() {
323 tracing::warn!(
324 ocpi.peer_version = %theirs,
325 ocpi.object = %kind,
326 "{note}",
327 );
328 }
329 Ok(Some(converted.value))
330 }
331
332 async fn expect_success(&self, request: OcpiRequest) -> Result<(), OcpiError> {
333 let (response, _) = self
334 .transport
335 .send_with_headers::<serde_json::Value>(&request, self.peer.token(), self.peer.quirks())
336 .await?;
337 if response.is_success() { Ok(()) } else { Err(response.into_result().unwrap_err()) }
338 }
339
340 pub fn list<T: DeserializeOwned + Send + 'static>(
349 &self,
350 query: PageQuery,
351 ) -> Result<PageStream<'a, T>, OcpiError> {
352 let endpoint = self.sender_endpoint().ok_or_else(|| self.missing(InterfaceRole::Sender))?;
353 let query = match self.peer.quirks().peer_max_page_limit {
354 Some(max) => query.clamped_to(max),
355 None => query,
356 };
357 Ok(PageStream::new(
358 self.transport,
359 self.peer,
360 self.module.clone(),
361 self.routing(),
362 endpoint.list(&query),
363 ))
364 }
365}
366
367impl<'a> ModuleClient<'a> {
368 #[must_use]
377 pub fn list_from<T: DeserializeOwned + Send + 'static>(
378 &self,
379 base: &Url,
380 query: &PageQuery,
381 ) -> PageStream<'a, T> {
382 PageStream::new(self.transport, self.peer, self.module.clone(), self.routing(), query.apply_to(base))
383 }
384}
385
386#[derive(Clone, Debug)]
390pub struct LocationsSender<'a>(ModuleClient<'a>);
391
392impl<'a> LocationsSender<'a> {
393 #[must_use]
395 pub const fn new(client: ModuleClient<'a>) -> Self {
396 Self(client)
397 }
398
399 pub fn list(
405 &self,
406 query: PageQuery,
407 ) -> Result<PageStream<'a, crate::v2_3_0::locations::Location>, OcpiError> {
408 self.0.list_bridged(query, ObjectKind::Location)
409 }
410
411 pub async fn location(&self, location_id: &str) -> Result<crate::v2_3_0::locations::Location, OcpiError> {
417 let endpoint = self.0.sender_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Sender))?;
418 self.0.get_bridged(endpoint.location(location_id, None, None), ObjectKind::Location).await
419 }
420
421 pub async fn evse(
427 &self,
428 location_id: &str,
429 evse_uid: &str,
430 ) -> Result<crate::v2_3_0::locations::Evse, OcpiError> {
431 let endpoint = self.0.sender_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Sender))?;
432 self.0.get_bridged(endpoint.location(location_id, Some(evse_uid), None), ObjectKind::Evse).await
433 }
434
435 pub async fn connector(
441 &self,
442 location_id: &str,
443 evse_uid: &str,
444 connector_id: &str,
445 ) -> Result<crate::v2_3_0::locations::Connector, OcpiError> {
446 let endpoint = self.0.sender_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Sender))?;
447 self.0
448 .get_bridged(
449 endpoint.location(location_id, Some(evse_uid), Some(connector_id)),
450 ObjectKind::Connector,
451 )
452 .await
453 }
454}
455
456#[derive(Clone, Debug)]
465pub struct LocationsReceiver<'a>(ModuleClient<'a>);
466
467impl<'a> LocationsReceiver<'a> {
468 #[must_use]
470 pub const fn new(client: ModuleClient<'a>) -> Self {
471 Self(client)
472 }
473
474 pub async fn put_location(
480 &self,
481 owner: &PartyRef,
482 location: &crate::v2_3_0::locations::Location,
483 ) -> Result<(), OcpiError> {
484 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
485 self.0
486 .put_bridged(
487 endpoint.location(owner, location.id.as_str(), None, None),
488 location,
489 ObjectKind::Location,
490 )
491 .await
492 }
493
494 pub async fn put_evse(
500 &self,
501 owner: &PartyRef,
502 location_id: &str,
503 evse: &crate::v2_3_0::locations::Evse,
504 ) -> Result<(), OcpiError> {
505 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
506 self.0
507 .put_bridged(
508 endpoint.location(owner, location_id, Some(evse.uid.as_str()), None),
509 evse,
510 ObjectKind::Evse,
511 )
512 .await
513 }
514
515 pub async fn patch<T>(
523 &self,
524 owner: &PartyRef,
525 location_id: &str,
526 evse_uid: Option<&str>,
527 connector_id: Option<&str>,
528 patch: &Patch<T>,
529 ) -> Result<(), OcpiError> {
530 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
531 let kind = match (evse_uid, connector_id) {
532 (None, _) => ObjectKind::Location,
533 (Some(_), None) => ObjectKind::Evse,
534 (Some(_), Some(_)) => ObjectKind::Connector,
535 };
536 self.0.patch_bridged(endpoint.location(owner, location_id, evse_uid, connector_id), patch, kind).await
537 }
538}
539
540#[derive(Clone, Debug)]
544pub struct TokensSender<'a>(ModuleClient<'a>);
545
546impl<'a> TokensSender<'a> {
547 #[must_use]
549 pub const fn new(client: ModuleClient<'a>) -> Self {
550 Self(client)
551 }
552
553 pub fn list(&self, query: PageQuery) -> Result<PageStream<'a, crate::v2_3_0::tokens::Token>, OcpiError> {
559 self.0.list_bridged(query, ObjectKind::Token)
560 }
561
562 pub async fn authorize(
571 &self,
572 token_uid: &str,
573 token_type: Option<crate::v2_3_0::tokens::TokenType>,
574 location: Option<&crate::v2_3_0::tokens::LocationReferences>,
575 ) -> Result<crate::v2_3_0::tokens::AuthorizationInfo, OcpiError> {
576 let endpoint = self.0.sender_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Sender))?;
577 let url = endpoint.token_authorize(
578 token_uid,
579 token_type.as_ref().map(super::super::v2_3_0::tokens::TokenType::as_str),
580 );
581 match location {
584 Some(references) => {
585 self.0.post_bridged(url, references, None, Some(ObjectKind::AuthorizationInfo)).await
586 }
587 None => {
589 self.0
590 .post_bridged(url, &serde_json::json!({}), None, Some(ObjectKind::AuthorizationInfo))
591 .await
592 }
593 }
594 }
595}
596
597#[derive(Clone, Debug)]
605pub struct CdrsClient<'a>(ModuleClient<'a>);
606
607impl<'a> CdrsClient<'a> {
608 #[must_use]
610 pub const fn new(client: ModuleClient<'a>) -> Self {
611 Self(client)
612 }
613
614 pub fn list(&self, query: PageQuery) -> Result<PageStream<'a, crate::v2_3_0::cdrs::Cdr>, OcpiError> {
620 self.0.list_bridged(query, ObjectKind::Cdr)
621 }
622
623 pub async fn post(&self, cdr: &crate::v2_3_0::cdrs::Cdr) -> Result<Option<Url>, OcpiError> {
629 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
630 check_outgoing(cdr, self.0.transport.config())?;
631 let request = match self.0.for_peer(cdr, ObjectKind::Cdr)? {
632 Some(value) => self.0.request(Method::POST, endpoint.base().clone()).with_body(&value)?,
633 None => self.0.request(Method::POST, endpoint.base().clone()).with_body(cdr)?,
634 };
635 let (response, headers) = self
636 .0
637 .transport
638 .send_with_headers::<serde_json::Value>(&request, self.0.peer.token(), self.0.peer.quirks())
639 .await?;
640 if !response.is_success() {
641 return Err(response.into_result().unwrap_err());
642 }
643 Ok(crate::transport::header_str(&headers, &crate::transport::headers::LOCATION).map(Url::new_lenient))
644 }
645}
646
647#[derive(Clone, Debug)]
651pub struct CommandsClient<'a>(ModuleClient<'a>);
652
653impl<'a> CommandsClient<'a> {
654 #[must_use]
656 pub const fn new(client: ModuleClient<'a>) -> Self {
657 Self(client)
658 }
659
660 pub async fn send(
670 &self,
671 command: &crate::v2_3_0::commands::Command,
672 ) -> Result<crate::v2_3_0::commands::CommandResponse, OcpiError> {
673 use crate::v2_3_0::commands::Command;
674 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
675 let url = endpoint.base().join(command.command_type().as_str());
678 match command {
679 Command::CancelReservation(c) => self.0.post_bridged(url, c, None, None).await,
682 Command::ReserveNow(c) => {
683 self.0.post_bridged(url, c.as_ref(), Some(ObjectKind::ReserveNow), None).await
684 }
685 Command::StartSession(c) => {
686 self.0.post_bridged(url, c.as_ref(), Some(ObjectKind::StartSession), None).await
687 }
688 Command::StopSession(c) => self.0.post_bridged(url, c, None, None).await,
689 Command::UnlockConnector(c) => self.0.post_bridged(url, c, None, None).await,
690 }
691 }
692}
693
694#[derive(Clone, Debug)]
698pub struct SessionsSender<'a>(ModuleClient<'a>);
699
700impl<'a> SessionsSender<'a> {
701 #[must_use]
703 pub const fn new(client: ModuleClient<'a>) -> Self {
704 Self(client)
705 }
706
707 pub fn list(
713 &self,
714 query: PageQuery,
715 ) -> Result<PageStream<'a, crate::v2_3_0::sessions::Session>, OcpiError> {
716 self.0.list_bridged(query, ObjectKind::Session)
717 }
718
719 pub async fn set_charging_preferences(
730 &self,
731 session_id: &str,
732 preferences: &crate::v2_3_0::sessions::ChargingPreferences,
733 ) -> Result<crate::v2_3_0::sessions::ChargingPreferencesResponse, OcpiError> {
734 let endpoint = self.0.sender_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Sender))?;
735 check_outgoing(preferences, self.0.transport.config())?;
736 let request =
737 self.0.request(Method::PUT, endpoint.charging_preferences(session_id)).with_body(preferences)?;
738 self.0.transport.send(&request, self.0.peer.token(), self.0.peer.quirks()).await
739 }
740}
741
742#[derive(Clone, Debug)]
746pub struct SessionsReceiver<'a>(ModuleClient<'a>);
747
748impl<'a> SessionsReceiver<'a> {
749 #[must_use]
751 pub const fn new(client: ModuleClient<'a>) -> Self {
752 Self(client)
753 }
754
755 pub async fn session(
761 &self,
762 owner: &PartyRef,
763 session_id: &str,
764 ) -> Result<crate::v2_3_0::sessions::Session, OcpiError> {
765 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
766 self.0.get_bridged(endpoint.object(owner, session_id), ObjectKind::Session).await
767 }
768
769 pub async fn put_session(
775 &self,
776 owner: &PartyRef,
777 session: &crate::v2_3_0::sessions::Session,
778 ) -> Result<(), OcpiError> {
779 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
780 self.0.put_bridged(endpoint.object(owner, session.id.as_str()), session, ObjectKind::Session).await
781 }
782
783 pub async fn patch<T>(
789 &self,
790 owner: &PartyRef,
791 session_id: &str,
792 patch: &Patch<T>,
793 ) -> Result<(), OcpiError> {
794 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
795 self.0.patch_bridged(endpoint.object(owner, session_id), patch, ObjectKind::Session).await
796 }
797}
798
799#[derive(Clone, Debug)]
803pub struct TariffsSender<'a>(ModuleClient<'a>);
804
805impl<'a> TariffsSender<'a> {
806 #[must_use]
808 pub const fn new(client: ModuleClient<'a>) -> Self {
809 Self(client)
810 }
811
812 pub fn list(
818 &self,
819 query: PageQuery,
820 ) -> Result<PageStream<'a, crate::v2_3_0::tariffs::Tariff>, OcpiError> {
821 self.0.list_bridged(query, ObjectKind::Tariff)
822 }
823}
824
825#[derive(Clone, Debug)]
832pub struct TariffsReceiver<'a>(ModuleClient<'a>);
833
834impl<'a> TariffsReceiver<'a> {
835 #[must_use]
837 pub const fn new(client: ModuleClient<'a>) -> Self {
838 Self(client)
839 }
840
841 pub async fn tariff(
847 &self,
848 owner: &PartyRef,
849 tariff_id: &str,
850 ) -> Result<crate::v2_3_0::tariffs::Tariff, OcpiError> {
851 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
852 self.0.get_bridged(endpoint.object(owner, tariff_id), ObjectKind::Tariff).await
853 }
854
855 pub async fn put_tariff(
861 &self,
862 owner: &PartyRef,
863 tariff: &crate::v2_3_0::tariffs::Tariff,
864 ) -> Result<(), OcpiError> {
865 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
866 self.0.put_bridged(endpoint.object(owner, tariff.id.as_str()), tariff, ObjectKind::Tariff).await
867 }
868
869 pub async fn delete_tariff(&self, owner: &PartyRef, tariff_id: &str) -> Result<(), OcpiError> {
875 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
876 self.0.delete(endpoint.object(owner, tariff_id)).await
877 }
878}
879
880#[derive(Clone, Debug)]
884pub struct TokensReceiver<'a>(ModuleClient<'a>);
885
886impl<'a> TokensReceiver<'a> {
887 #[must_use]
889 pub const fn new(client: ModuleClient<'a>) -> Self {
890 Self(client)
891 }
892
893 pub async fn token(
899 &self,
900 owner: &PartyRef,
901 token_uid: &str,
902 token_type: Option<crate::v2_3_0::tokens::TokenType>,
903 ) -> Result<crate::v2_3_0::tokens::Token, OcpiError> {
904 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
905 self.0
906 .get_bridged(
907 endpoint.token(owner, token_uid, token_type.as_ref().map(TokenType::as_str)),
908 ObjectKind::Token,
909 )
910 .await
911 }
912
913 pub async fn put_token(
921 &self,
922 owner: &PartyRef,
923 token: &crate::v2_3_0::tokens::Token,
924 ) -> Result<(), OcpiError> {
925 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
926 let url = endpoint.token(owner, token.uid.as_str(), Some(token.token_type.as_str()));
927 self.0.put_bridged(url, token, ObjectKind::Token).await
928 }
929
930 pub async fn patch<T>(
936 &self,
937 owner: &PartyRef,
938 token_uid: &str,
939 token_type: Option<crate::v2_3_0::tokens::TokenType>,
940 patch: &Patch<T>,
941 ) -> Result<(), OcpiError> {
942 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
943 let url = endpoint.token(owner, token_uid, token_type.as_ref().map(TokenType::as_str));
944 self.0.patch_bridged(url, patch, ObjectKind::Token).await
945 }
946}
947
948#[derive(Clone, Debug)]
959pub struct ChargingProfilesClient<'a>(ModuleClient<'a>);
960
961impl<'a> ChargingProfilesClient<'a> {
962 #[must_use]
964 pub const fn new(client: ModuleClient<'a>) -> Self {
965 Self(client)
966 }
967
968 pub async fn active_charging_profile(
974 &self,
975 session_id: &str,
976 duration_seconds: u64,
977 response_url: &Url,
978 ) -> Result<crate::v2_3_0::charging_profiles::ChargingProfileResponse, OcpiError> {
979 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
980 self.0.get(endpoint.active_charging_profile(session_id, duration_seconds, response_url)).await
981 }
982
983 pub async fn set_charging_profile(
989 &self,
990 session_id: &str,
991 request: &crate::v2_3_0::charging_profiles::SetChargingProfile,
992 ) -> Result<crate::v2_3_0::charging_profiles::ChargingProfileResponse, OcpiError> {
993 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
994 check_outgoing(request, self.0.transport.config())?;
995 let outgoing =
996 self.0.request(Method::PUT, endpoint.charging_profile(session_id)).with_body(request)?;
997 self.0.transport.send(&outgoing, self.0.peer.token(), self.0.peer.quirks()).await
998 }
999
1000 pub async fn clear_charging_profile(
1006 &self,
1007 session_id: &str,
1008 response_url: &Url,
1009 ) -> Result<crate::v2_3_0::charging_profiles::ChargingProfileResponse, OcpiError> {
1010 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
1011 let outgoing =
1012 self.0.request(Method::DELETE, endpoint.clear_charging_profile(session_id, response_url));
1013 self.0.transport.send(&outgoing, self.0.peer.token(), self.0.peer.quirks()).await
1014 }
1015
1016 pub async fn push_active_charging_profile(
1023 &self,
1024 session_id: &str,
1025 profile: &crate::v2_3_0::charging_profiles::ActiveChargingProfile,
1026 ) -> Result<(), OcpiError> {
1027 let endpoint = self.0.sender_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Sender))?;
1028 self.0.put(endpoint.object(session_id), profile).await
1029 }
1030}
1031
1032#[derive(Clone, Debug)]
1039pub struct HubClientInfoClient<'a>(ModuleClient<'a>);
1040
1041impl<'a> HubClientInfoClient<'a> {
1042 #[must_use]
1044 pub const fn new(client: ModuleClient<'a>) -> Self {
1045 Self(client)
1046 }
1047
1048 pub fn list(
1054 &self,
1055 query: PageQuery,
1056 ) -> Result<PageStream<'a, crate::v2_3_0::hub_client_info::ClientInfo>, OcpiError> {
1057 self.0.list_bridged(query, ObjectKind::ClientInfo)
1058 }
1059
1060 pub async fn client_info(
1066 &self,
1067 party: &PartyRef,
1068 ) -> Result<crate::v2_3_0::hub_client_info::ClientInfo, OcpiError> {
1069 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
1070 let url = endpoint.base().join(party.country_code.as_str()).join(party.party_id.as_str());
1071 self.0.get_bridged(url, ObjectKind::ClientInfo).await
1072 }
1073
1074 pub async fn put_client_info(
1080 &self,
1081 info: &crate::v2_3_0::hub_client_info::ClientInfo,
1082 ) -> Result<(), OcpiError> {
1083 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
1084 let url = endpoint.base().join(info.country_code.as_str()).join(info.party_id.as_str());
1085 self.0.put_bridged(url, info, ObjectKind::ClientInfo).await
1086 }
1087}
1088
1089#[derive(Clone, Debug)]
1098pub struct PaymentsClient<'a>(ModuleClient<'a>);
1099
1100impl<'a> PaymentsClient<'a> {
1101 #[must_use]
1103 pub const fn new(client: ModuleClient<'a>) -> Self {
1104 Self(client)
1105 }
1106
1107 fn terminals(&self) -> Result<SenderEndpoint, OcpiError> {
1108 Ok(self
1109 .0
1110 .sender_endpoint()
1111 .ok_or_else(|| self.0.missing(InterfaceRole::Sender))?
1112 .payments_terminals())
1113 }
1114
1115 fn confirmations(&self) -> Result<SenderEndpoint, OcpiError> {
1116 Ok(self
1117 .0
1118 .sender_endpoint()
1119 .ok_or_else(|| self.0.missing(InterfaceRole::Sender))?
1120 .payments_financial_advice_confirmations())
1121 }
1122
1123 pub fn list_terminals(
1129 &self,
1130 query: PageQuery,
1131 ) -> Result<PageStream<'a, crate::v2_3_0::payments::Terminal>, OcpiError> {
1132 let endpoint = self.terminals()?;
1133 Ok(PageStream::new(
1134 self.0.transport,
1135 self.0.peer,
1136 self.0.module.clone(),
1137 self.0.routing(),
1138 endpoint.list(&query),
1139 ))
1140 }
1141
1142 pub async fn terminal(&self, terminal_id: &str) -> Result<crate::v2_3_0::payments::Terminal, OcpiError> {
1148 self.0.get(self.terminals()?.terminal(terminal_id)).await
1149 }
1150
1151 pub async fn put_terminal(
1157 &self,
1158 terminal: &crate::v2_3_0::payments::Terminal,
1159 ) -> Result<crate::v2_3_0::payments::Terminal, OcpiError> {
1160 check_outgoing(terminal, self.0.transport.config())?;
1161 let url = self.terminals()?.terminal(terminal.terminal_id.as_str());
1162 let request = self.0.request(Method::PUT, url).with_body(terminal)?;
1163 self.0.transport.send(&request, self.0.peer.token(), self.0.peer.quirks()).await
1164 }
1165
1166 pub async fn patch_terminal<T>(
1172 &self,
1173 terminal_id: &str,
1174 patch: &Patch<T>,
1175 ) -> Result<crate::v2_3_0::payments::Terminal, OcpiError> {
1176 let url = self.terminals()?.terminal(terminal_id);
1177 let request = self.0.request(Method::PATCH, url).with_body(patch.as_value())?;
1178 self.0.transport.send(&request, self.0.peer.token(), self.0.peer.quirks()).await
1179 }
1180
1181 pub async fn activate_terminal<T>(
1191 &self,
1192 terminal: &Patch<T>,
1193 ) -> Result<crate::v2_3_0::payments::Terminal, OcpiError> {
1194 let request = self
1195 .0
1196 .request(Method::POST, self.terminals()?.terminal_activate())
1197 .with_body(terminal.as_value())?;
1198 self.0.transport.send(&request, self.0.peer.token(), self.0.peer.quirks()).await
1199 }
1200
1201 pub async fn deactivate_terminal(
1207 &self,
1208 terminal_id: &str,
1209 ) -> Result<crate::v2_3_0::payments::Terminal, OcpiError> {
1210 let url = self.terminals()?.terminal_deactivate(terminal_id);
1211 let request = self.0.request(Method::POST, url).with_body(&serde_json::json!({}))?;
1212 self.0.transport.send(&request, self.0.peer.token(), self.0.peer.quirks()).await
1213 }
1214
1215 pub fn list_financial_advice_confirmations(
1221 &self,
1222 query: PageQuery,
1223 ) -> Result<PageStream<'a, crate::v2_3_0::payments::FinancialAdviceConfirmation>, OcpiError> {
1224 let endpoint = self.confirmations()?;
1225 Ok(PageStream::new(
1226 self.0.transport,
1227 self.0.peer,
1228 self.0.module.clone(),
1229 self.0.routing(),
1230 endpoint.list(&query),
1231 ))
1232 }
1233
1234 pub async fn financial_advice_confirmation(
1240 &self,
1241 id: &str,
1242 ) -> Result<crate::v2_3_0::payments::FinancialAdviceConfirmation, OcpiError> {
1243 self.0.get(self.confirmations()?.object(id)).await
1244 }
1245
1246 pub async fn post_terminal_to_receiver(
1253 &self,
1254 terminal: &crate::v2_3_0::payments::Terminal,
1255 ) -> Result<crate::v2_3_0::payments::Terminal, OcpiError> {
1256 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
1257 check_outgoing(terminal, self.0.transport.config())?;
1258 let url = endpoint.payments_terminals().base().clone();
1259 let request = self.0.request(Method::POST, url).with_body(terminal)?;
1260 self.0.transport.send(&request, self.0.peer.token(), self.0.peer.quirks()).await
1261 }
1262
1263 pub async fn post_financial_advice_confirmation(
1269 &self,
1270 confirmation: &crate::v2_3_0::payments::FinancialAdviceConfirmation,
1271 ) -> Result<crate::v2_3_0::payments::FinancialAdviceConfirmation, OcpiError> {
1272 let endpoint = self.0.receiver_endpoint().ok_or_else(|| self.0.missing(InterfaceRole::Receiver))?;
1273 check_outgoing(confirmation, self.0.transport.config())?;
1274 let url = endpoint.payments_financial_advice_confirmations().base().clone();
1275 let request = self.0.request(Method::POST, url).with_body(confirmation)?;
1276 self.0.transport.send(&request, self.0.peer.token(), self.0.peer.quirks()).await
1277 }
1278}
1279
1280impl Peer {
1282 #[must_use]
1284 pub fn module<'a>(
1285 &'a self,
1286 transport: &'a Transport,
1287 module: ModuleId,
1288 from: PartyRef,
1289 ) -> ModuleClient<'a> {
1290 ModuleClient::new(transport, self, module, from)
1291 }
1292
1293 #[must_use]
1295 pub fn locations<'a>(&'a self, transport: &'a Transport, from: PartyRef) -> LocationsSender<'a> {
1296 LocationsSender::new(self.module(transport, ModuleId::Locations, from))
1297 }
1298
1299 #[must_use]
1301 pub fn locations_receiver<'a>(
1302 &'a self,
1303 transport: &'a Transport,
1304 from: PartyRef,
1305 ) -> LocationsReceiver<'a> {
1306 LocationsReceiver::new(self.module(transport, ModuleId::Locations, from))
1307 }
1308
1309 #[must_use]
1311 pub fn tokens<'a>(&'a self, transport: &'a Transport, from: PartyRef) -> TokensSender<'a> {
1312 TokensSender::new(self.module(transport, ModuleId::Tokens, from))
1313 }
1314
1315 #[must_use]
1317 pub fn cdrs<'a>(&'a self, transport: &'a Transport, from: PartyRef) -> CdrsClient<'a> {
1318 CdrsClient::new(self.module(transport, ModuleId::Cdrs, from))
1319 }
1320
1321 #[must_use]
1323 pub fn tokens_receiver<'a>(&'a self, transport: &'a Transport, from: PartyRef) -> TokensReceiver<'a> {
1324 TokensReceiver::new(self.module(transport, ModuleId::Tokens, from))
1325 }
1326
1327 #[must_use]
1329 pub fn sessions<'a>(&'a self, transport: &'a Transport, from: PartyRef) -> SessionsSender<'a> {
1330 SessionsSender::new(self.module(transport, ModuleId::Sessions, from))
1331 }
1332
1333 #[must_use]
1335 pub fn sessions_receiver<'a>(&'a self, transport: &'a Transport, from: PartyRef) -> SessionsReceiver<'a> {
1336 SessionsReceiver::new(self.module(transport, ModuleId::Sessions, from))
1337 }
1338
1339 #[must_use]
1341 pub fn tariffs<'a>(&'a self, transport: &'a Transport, from: PartyRef) -> TariffsSender<'a> {
1342 TariffsSender::new(self.module(transport, ModuleId::Tariffs, from))
1343 }
1344
1345 #[must_use]
1347 pub fn tariffs_receiver<'a>(&'a self, transport: &'a Transport, from: PartyRef) -> TariffsReceiver<'a> {
1348 TariffsReceiver::new(self.module(transport, ModuleId::Tariffs, from))
1349 }
1350
1351 #[must_use]
1353 pub fn commands<'a>(&'a self, transport: &'a Transport, from: PartyRef) -> CommandsClient<'a> {
1354 CommandsClient::new(self.module(transport, ModuleId::Commands, from))
1355 }
1356
1357 #[must_use]
1359 pub fn charging_profiles<'a>(
1360 &'a self,
1361 transport: &'a Transport,
1362 from: PartyRef,
1363 ) -> ChargingProfilesClient<'a> {
1364 ChargingProfilesClient::new(self.module(transport, ModuleId::ChargingProfiles, from))
1365 }
1366
1367 #[must_use]
1369 pub fn hub_client_info<'a>(
1370 &'a self,
1371 transport: &'a Transport,
1372 from: PartyRef,
1373 ) -> HubClientInfoClient<'a> {
1374 HubClientInfoClient::new(self.module(transport, ModuleId::HubClientInfo, from))
1375 }
1376
1377 #[must_use]
1379 pub fn payments<'a>(&'a self, transport: &'a Transport, from: PartyRef) -> PaymentsClient<'a> {
1380 PaymentsClient::new(self.module(transport, ModuleId::Payments, from))
1381 }
1382}
1383
1384fn bridge_error(error: BridgeError, kind: ObjectKind) -> OcpiError {
1386 match error {
1387 BridgeError::Unsupported { from, to } => OcpiError::Unsupported(format!(
1388 "this build has no conversions between OCPI {from} and OCPI {to}, so a {kind} cannot \
1389 be carried between them"
1390 )),
1391 BridgeError::Decode { version, message, .. } => OcpiError::Decode {
1392 path: "/".to_owned(),
1393 message: format!("the peer's OCPI {version} {kind} could not be read: {message}"),
1394 },
1395 }
1396}
1397
1398fn decode<T: DeserializeOwned>(value: serde_json::Value) -> Result<T, OcpiError> {
1400 serde_path_to_error::deserialize(value)
1401 .map_err(|e| OcpiError::Decode { path: e.path().to_string(), message: e.into_inner().to_string() })
1402}
1403
1404#[must_use]
1406pub fn correlated_ids() -> RequestIds {
1407 RequestIds::generate()
1408}