openapp_sdk_core/resources/
devices.rs1use std::sync::Arc;
4
5use openapp_sdk_common::NameMatch;
6use reqwest::Method;
7
8use super::JsonValue;
9use super::types;
10use crate::{
11 error::SdkError,
12 resolve::{fetch_all_paginated, resolve_unique_sdk, use_server_q_prefilter},
13 transport::{RequestSpec, Transport},
14};
15
16#[derive(Debug, Clone, Default)]
18pub struct ListDevicesParams {
19 pub integration_id: Option<String>,
20 pub zone_id: Option<String>,
21 pub q: Option<String>,
22 pub limit: Option<u32>,
23 pub offset: Option<u32>,
24}
25
26#[derive(Debug, Clone)]
27pub struct DevicesClient {
28 transport: Arc<Transport>,
29}
30
31impl DevicesClient {
32 pub(crate) fn new(transport: Arc<Transport>) -> Self {
33 Self { transport }
34 }
35
36 pub async fn list(&self) -> Result<JsonValue, SdkError> {
37 self.list_with(ListDevicesParams::default()).await
38 }
39
40 pub async fn list_with(&self, params: ListDevicesParams) -> Result<JsonValue, SdkError> {
41 let query = build_list_query(¶ms);
42 self.transport
43 .request_json::<(), JsonValue>(RequestSpec {
44 method: Method::GET,
45 path: "/devices",
46 query: &query,
47 ..Default::default()
48 })
49 .await
50 }
51
52 pub async fn get_by_name(
54 &self,
55 name: &str,
56 mode: NameMatch,
57 integration_id: Option<&str>,
58 ) -> Result<JsonValue, SdkError> {
59 let q = use_server_q_prefilter(mode, name).then(|| name.to_owned());
60 let integration = integration_id.map(str::to_owned);
61 let client = self.clone();
62 let all_items = fetch_all_paginated(move |limit, offset| {
63 let client = client.clone();
64 let params = ListDevicesParams {
65 integration_id: integration.clone(),
66 q: q.clone(),
67 limit: Some(limit),
68 offset: Some(offset),
69 ..Default::default()
70 };
71 async move {
72 let page = client.list_with(params).await?;
73 Ok(normalize_devices_page(page))
74 }
75 })
76 .await?;
77 resolve_unique_sdk(&all_items, "device", "name", name, mode)
78 }
79
80 pub async fn create(
81 &self,
82 body: &types::CreateDeviceRequest,
83 ) -> Result<types::DeviceResponse, SdkError> {
84 self.transport
85 .request_json::<types::CreateDeviceRequest, types::DeviceResponse>(RequestSpec {
86 method: Method::POST,
87 path: "/devices",
88 body: Some(body),
89 ..Default::default()
90 })
91 .await
92 }
93
94 pub async fn get(&self, id: &str) -> Result<types::DeviceResponse, SdkError> {
95 let path = format!("/devices/{id}");
96 self.transport
97 .request_json::<(), types::DeviceResponse>(RequestSpec {
98 method: Method::GET,
99 path: &path,
100 ..Default::default()
101 })
102 .await
103 }
104
105 pub async fn update(
106 &self,
107 id: &str,
108 body: &types::UpdateDeviceRequest,
109 ) -> Result<types::DeviceResponse, SdkError> {
110 let path = format!("/devices/{id}");
111 self.transport
112 .request_json::<types::UpdateDeviceRequest, types::DeviceResponse>(RequestSpec {
113 method: Method::PUT,
114 path: &path,
115 body: Some(body),
116 ..Default::default()
117 })
118 .await
119 }
120
121 pub async fn delete(&self, id: &str) -> Result<(), SdkError> {
122 let path = format!("/devices/{id}");
123 self.transport
124 .request_json::<(), ()>(RequestSpec {
125 method: Method::DELETE,
126 path: &path,
127 ..Default::default()
128 })
129 .await
130 }
131
132 pub async fn purge(&self, id: &str) -> Result<(), SdkError> {
133 let path = format!("/devices/{id}/purge");
134 self.transport
135 .request_json::<(), ()>(RequestSpec {
136 method: Method::DELETE,
137 path: &path,
138 ..Default::default()
139 })
140 .await
141 }
142
143 pub async fn restore(&self, id: &str) -> Result<types::DeviceResponse, SdkError> {
144 let path = format!("/devices/{id}/restore");
145 self.transport
146 .request_json::<(), types::DeviceResponse>(RequestSpec {
147 method: Method::POST,
148 path: &path,
149 ..Default::default()
150 })
151 .await
152 }
153
154 pub async fn door_restrictions(
155 &self,
156 id: &str,
157 ) -> Result<types::DoorRestrictionsResponse, SdkError> {
158 let path = format!("/devices/{id}/door-restrictions");
159 self.transport
160 .request_json::<(), types::DoorRestrictionsResponse>(RequestSpec {
161 method: Method::GET,
162 path: &path,
163 ..Default::default()
164 })
165 .await
166 }
167
168 pub async fn metadata_definition(
169 &self,
170 id: &str,
171 ) -> Result<types::DeviceMetadataDefinitionResponse, SdkError> {
172 let path = format!("/devices/{id}/metadata-definition");
173 self.transport
174 .request_json::<(), types::DeviceMetadataDefinitionResponse>(RequestSpec {
175 method: Method::GET,
176 path: &path,
177 ..Default::default()
178 })
179 .await
180 }
181}
182
183fn build_list_query(params: &ListDevicesParams) -> Vec<(&str, Option<String>)> {
184 vec![
185 (
186 "integration_id",
187 params
188 .integration_id
189 .as_ref()
190 .map(std::borrow::ToOwned::to_owned),
191 ),
192 (
193 "zone_id",
194 params.zone_id.as_ref().map(std::borrow::ToOwned::to_owned),
195 ),
196 ("q", params.q.as_ref().map(std::borrow::ToOwned::to_owned)),
197 ("limit", params.limit.map(|n| n.to_string())),
198 ("offset", params.offset.map(|n| n.to_string())),
199 ]
200}
201
202fn normalize_devices_page(page: JsonValue) -> JsonValue {
203 if page.is_array() {
204 let len = page.as_array().map_or(0, std::vec::Vec::len);
205 serde_json::json!({ "items": page, "total": len })
206 } else {
207 page
208 }
209}