Skip to main content

openleadr_client/
ven.rs

1use crate::{
2    BusinessLogic, ClientKind, ClientRef, Error, Result, VirtualEndNode, resource::ResourceClient,
3};
4use chrono::{DateTime, Utc};
5use openleadr_wire::{
6    Ven,
7    resource::{BlResourceRequest, Resource, ResourceId, ResourceRequest, VenResourceRequest},
8    target::Target,
9    values_map::ValuesMap,
10    ven::{BlVenRequest, VenId, VenRequest},
11};
12use std::{fmt::Display, sync::Arc};
13
14/// A client for interacting with the data in a specific VEN and the resources contained in the VEN.
15#[derive(Debug, Clone)]
16pub struct VenClient<K> {
17    client: Arc<ClientRef<K>>,
18    data: Ven,
19}
20
21impl VenClient<BusinessLogic> {
22    /// Create a resource as a child of this VEN
23    pub async fn create_resource<S: Display>(
24        &self,
25        name: S,
26        attributes: Option<Vec<ValuesMap>>,
27        targets: Vec<Target>,
28    ) -> Result<ResourceClient<BusinessLogic>> {
29        let resource = self
30            .client
31            .post(
32                "resources",
33                &ResourceRequest::BlResourceRequest(BlResourceRequest {
34                    targets,
35                    resource_name: name.to_string(),
36                    ven_id: self.data.id.clone(),
37                    attributes,
38                }),
39            )
40            .await?;
41        Ok(ResourceClient::from_resource(
42            Arc::clone(&self.client),
43            resource,
44        ))
45    }
46}
47
48impl VenClient<VirtualEndNode> {
49    /// Create a resource as a child of this VEN
50    pub async fn create_resource<S: Display>(
51        &self,
52        name: S,
53        attributes: Option<Vec<ValuesMap>>,
54    ) -> Result<ResourceClient<VirtualEndNode>> {
55        let resource = self
56            .client
57            .post(
58                "resources",
59                &ResourceRequest::VenResourceRequest(VenResourceRequest {
60                    resource_name: name.to_string(),
61                    attributes,
62                }),
63            )
64            .await?;
65        Ok(ResourceClient::from_resource(
66            Arc::clone(&self.client),
67            resource,
68        ))
69    }
70}
71
72impl<K: ClientKind> VenClient<K> {
73    pub(super) fn from_ven(client: Arc<ClientRef<K>>, data: Ven) -> Self {
74        Self { client, data }
75    }
76
77    /// Get the VEN ID
78    pub fn id(&self) -> &VenId {
79        &self.data.id
80    }
81
82    /// Get the time the VEN was created on the VTN
83    pub fn created_date_time(&self) -> DateTime<Utc> {
84        self.data.created_date_time
85    }
86
87    /// Get the time the VEN was last modified on the VTN
88    pub fn modification_date_time(&self) -> DateTime<Utc> {
89        self.data.modification_date_time
90    }
91
92    /// Read the content of the VEN
93    pub fn content(&self) -> &BlVenRequest {
94        &self.data.content
95    }
96
97    /// Modify the content of the VEN.
98    /// Make sure to call [`update`](Self::update)
99    /// after your modifications to store them on the VTN.
100    pub fn content_mut(&mut self) -> &mut BlVenRequest {
101        &mut self.data.content
102    }
103
104    /// Stores any modifications made to the VEN content at the VTN
105    /// and refreshes the data stored locally with the returned VTN data
106    pub async fn update(&mut self) -> Result<()> {
107        self.data = self
108            .client
109            .put(
110                &format!("vens/{}", self.id()),
111                &VenRequest::BlVenRequest(self.data.content.clone()),
112            )
113            .await?;
114        Ok(())
115    }
116
117    /// Delete the VEN from the VTN.
118    ///
119    /// Depending on the VTN implementation,
120    /// you may need to delete all associated resources before you can delete the VEN
121    pub async fn delete(self) -> Result<Ven> {
122        self.client.delete(&format!("vens/{}", self.id())).await
123    }
124
125    async fn get_resources_req(
126        &self,
127        resource_name: Option<&str>,
128        skip: usize,
129        limit: usize,
130    ) -> Result<Vec<ResourceClient<K>>> {
131        let skip_str = skip.to_string();
132        let limit_str = limit.to_string();
133
134        let mut query: Vec<(&str, &str)> = vec![("skip", &skip_str), ("limit", &limit_str)];
135
136        if let Some(resource_name) = resource_name {
137            query.push(("resourceName", resource_name));
138        }
139
140        let resources: Vec<Resource> = self.client.get("/resources", &query).await?;
141        Ok(resources
142            .into_iter()
143            .map(|resource| ResourceClient::from_resource(Arc::clone(&self.client), resource))
144            .collect())
145    }
146
147    /// Get all resources stored as children of this VEN.
148    ///
149    /// The client automatically tries to iterate pages where necessary.
150    pub async fn get_all_resources(
151        &self,
152        resource_name: Option<&str>,
153    ) -> Result<Vec<ResourceClient<K>>> {
154        self.client
155            .iterate_pages(|skip, limit| self.get_resources_req(resource_name, skip, limit))
156            .await
157    }
158
159    /// Get a resource by its ID
160    pub async fn get_resource_by_id(&self, id: &ResourceId) -> Result<ResourceClient<K>> {
161        let resource = self.client.get(&format!("resources/{}", id), &[]).await?;
162        Ok(ResourceClient::from_resource(
163            Arc::clone(&self.client),
164            resource,
165        ))
166    }
167
168    /// Get VEN by name from VTN.
169    /// According to the spec, a [`resource_name`](BlResourceRequest::resource_name) must be unique per VEN.
170    pub async fn get_resource_by_name(&self, name: &str) -> Result<ResourceClient<K>> {
171        let mut resources: Vec<Resource> = self
172            .client
173            .get("resources", &[("resourceName", name)])
174            .await?;
175        match resources[..] {
176            [] => Err(Error::ObjectNotFound),
177            [_] => Ok(ResourceClient::from_resource(
178                Arc::clone(&self.client),
179                resources.remove(0),
180            )),
181            [..] => Err(Error::DuplicateObject),
182        }
183    }
184}