1use std::sync::Arc;
2
3use serde_json::Value;
4
5use crate::error::{map_manager_err, ManagerError};
6use crate::gen::manager::apis::configuration::Configuration;
7use crate::gen::manager::apis::{application_api as api, local_automation_api, manager_api};
8use crate::gen::manager::models;
9use crate::http::{collect_all, fetch_page, Page};
10use crate::resources::raw::{get_json, post_json, post_json_body};
11use crate::retry::{with_retry, RetryPolicy};
12
13fn decode_application(v: Value) -> Result<models::Application, ManagerError> {
22 use models::Application as App;
23 fn var<T: serde::de::DeserializeOwned>(v: Value) -> Result<Box<T>, ManagerError> {
24 serde_json::from_value(v)
25 .map(Box::new)
26 .map_err(|e| ManagerError::Decode(e.to_string()))
27 }
28 let module = v
29 .get("module")
30 .and_then(Value::as_str)
31 .unwrap_or_default()
32 .to_string();
33 Ok(match module.as_str() {
34 "agentQueue" => App::AgentQueue(var(v)?),
35 "agentic" => App::Agentic(var(v)?),
36 "audioPlayer" => App::AudioPlayer(var(v)?),
37 "consumerQueue" => App::ConsumerQueue(var(v)?),
38 "inputReader" => App::InputReader(var(v)?),
39 "inputReader.v2" => App::InputReaderV2(var(v)?),
40 "promptPlayer" => App::PromptPlayer(var(v)?),
41 "recording" => App::Recording(var(v)?),
42 "simpleMenu" => App::SimpleMenu(var(v)?),
43 "speechToText" => App::SpeechToText(var(v)?),
44 "switchNode" => App::SwitchNode(var(v)?),
45 "textToSpeech" => App::TextToSpeech(var(v)?),
46 "transfer" => App::Transfer(var(v)?),
47 other => {
48 return Err(ManagerError::Decode(format!(
49 "unknown application module '{other}'"
50 )))
51 }
52 })
53}
54
55async fn applications_page(
61 cfg: &Configuration,
62 page: i32,
63 per_page: Option<i32>,
64) -> Result<(Vec<models::Application>, i32, i32, Option<i32>), ManagerError> {
65 let mut path = format!("/api/v2/applications?page={page}");
66 if let Some(max) = per_page {
67 path.push_str(&format!("&max={max}"));
68 }
69 let v = get_json(cfg, &path).await?;
70 let items = v
71 .get("items")
72 .and_then(Value::as_array)
73 .cloned()
74 .unwrap_or_default()
75 .into_iter()
76 .map(decode_application)
77 .collect::<Result<Vec<_>, _>>()?;
78 let p = v.get("pagination").cloned().unwrap_or(Value::Null);
79 let num = |k: &str| p.get(k).and_then(Value::as_i64).map(|n| n as i32);
80 Ok((
81 items,
82 num("pages").unwrap_or(1),
83 num("current").unwrap_or(page),
84 num("total"),
85 ))
86}
87
88pub struct ApplicationsResource {
90 pub(crate) cfg: Arc<Configuration>,
91 pub(crate) retry: RetryPolicy,
92 pub local_automations: LocalAutomationsResource,
94}
95
96impl ApplicationsResource {
97 pub async fn list_all(&self) -> Result<Vec<models::Application>, ManagerError> {
99 collect_all(
100 &self.retry,
101 |e| e,
102 |page| async move {
103 applications_page(self.cfg.as_ref(), page, None)
104 .await
105 .map(|(items, pages, current, _)| (items, pages, current))
106 },
107 )
108 .await
109 }
110
111 pub async fn list_page(
113 &self,
114 page: i32,
115 per_page: Option<i32>,
116 ) -> Result<Page<models::Application>, ManagerError> {
117 fetch_page(
118 &self.retry,
119 |e| e,
120 || async move { applications_page(self.cfg.as_ref(), page, per_page).await },
121 )
122 .await
123 }
124
125 pub async fn all_local_automations(
127 &self,
128 ) -> Result<Vec<models::LocalAutomation>, ManagerError> {
129 collect_all(&self.retry, map_manager_err, |page| async move {
130 let r = local_automation_api::list_all_local_automations(
131 self.cfg.as_ref(),
132 Some(page),
133 None,
134 )
135 .await?;
136 Ok((r.items, r.pagination.pages, r.pagination.current))
137 })
138 .await
139 }
140
141 pub async fn create(
143 &self,
144 body: models::ApplicationCreateBody,
145 ) -> Result<models::ApplicationItemResponse, ManagerError> {
146 with_retry(&self.retry, false, || {
147 api::create_application(self.cfg.as_ref(), body.clone())
148 })
149 .await
150 .map_err(map_manager_err)
151 }
152
153 pub async fn create_raw(&self, body: Value) -> Result<Value, ManagerError> {
160 with_retry(&self.retry, false, || {
162 post_json_body(self.cfg.as_ref(), "/api/v2/applications", &body)
163 })
164 .await
165 }
166
167 pub async fn get(&self, id: &str) -> Result<models::ApplicationItemResponse, ManagerError> {
173 let path = format!(
174 "/api/v2/applications/{}",
175 crate::gen::manager::apis::urlencode(id)
176 );
177 with_retry(&self.retry, true, || async {
178 let v = get_json(self.cfg.as_ref(), &path).await?;
179 let success = v.get("success").and_then(Value::as_bool).unwrap_or(true);
180 let item = v
181 .get("item")
182 .cloned()
183 .ok_or_else(|| ManagerError::Decode("response had no `item`".into()))?;
184 Ok(models::ApplicationItemResponse::new(
185 decode_application(item)?,
186 success,
187 ))
188 })
189 .await
190 }
191
192 pub async fn update(
194 &self,
195 id: &str,
196 body: models::ApplicationUpdateBody,
197 ) -> Result<models::ApplicationItemResponse, ManagerError> {
198 with_retry(&self.retry, false, || {
199 api::update_application(self.cfg.as_ref(), id, body.clone())
200 })
201 .await
202 .map_err(map_manager_err)
203 }
204
205 pub async fn delete(&self, id: &str) -> Result<(), ManagerError> {
207 with_retry(&self.retry, false, || {
208 api::delete_application(self.cfg.as_ref(), id)
209 })
210 .await
211 .map_err(map_manager_err)?;
212 Ok(())
213 }
214
215 pub async fn delete_many(
217 &self,
218 ids: Vec<String>,
219 ) -> Result<models::DefaultV2MessageResponse, ManagerError> {
220 let body = models::DeleteManyApplicationsRequest { ids };
221 with_retry(&self.retry, false, || {
222 api::delete_many_applications(self.cfg.as_ref(), body.clone())
223 })
224 .await
225 .map_err(map_manager_err)
226 }
227
228 pub async fn list_modules(&self) -> Result<models::ListModulesResponse, ManagerError> {
230 with_retry(&self.retry, true, || api::list_modules(self.cfg.as_ref()))
231 .await
232 .map_err(map_manager_err)
233 }
234
235 pub async fn dispatch(
238 &self,
239 id: &str,
240 position: &str,
241 is_async: bool,
242 body: models::LocalAutomationDispatch,
243 ) -> Result<models::DispatchLocalAutomationsResponse, ManagerError> {
244 with_retry(&self.retry, false, || {
245 manager_api::dispatch_local_automations(
246 self.cfg.as_ref(),
247 id,
248 position,
249 is_async,
250 Some(body.clone()),
251 )
252 })
253 .await
254 .map_err(map_manager_err)
255 }
256
257 pub async fn clone(&self, id: &str) -> Result<models::ApplicationItemResponse, ManagerError> {
259 with_retry(&self.retry, false, || {
260 api::clone_application(self.cfg.as_ref(), id)
261 })
262 .await
263 .map_err(map_manager_err)
264 }
265
266 pub async fn clone_raw(&self, id: &str) -> Result<Value, ManagerError> {
269 let path = format!(
270 "/api/v2/applications/{}/clone",
271 crate::gen::manager::apis::urlencode(id)
272 );
273 with_retry(&self.retry, false, || post_json(self.cfg.as_ref(), &path)).await
275 }
276
277 pub async fn bulk_update(
279 &self,
280 body: models::BulkUpdateApplicationsRequest,
281 ) -> Result<models::DefaultV2MessageResponse, ManagerError> {
282 with_retry(&self.retry, false, || {
283 api::bulk_update_applications(self.cfg.as_ref(), body.clone())
284 })
285 .await
286 .map_err(map_manager_err)
287 }
288
289 pub async fn list_app_actions(&self) -> Result<models::ObjectListResponse, ManagerError> {
291 with_retry(&self.retry, true, || {
292 api::list_application_actions(self.cfg.as_ref(), None, None)
293 })
294 .await
295 .map_err(map_manager_err)
296 }
297
298 pub async fn list_errors(&self) -> Result<models::ObjectListResponse, ManagerError> {
300 with_retry(&self.retry, true, || {
301 api::list_application_errors(self.cfg.as_ref())
302 })
303 .await
304 .map_err(map_manager_err)
305 }
306}
307
308pub struct LocalAutomationsResource {
310 pub(crate) cfg: Arc<Configuration>,
311 pub(crate) retry: RetryPolicy,
312}
313
314impl LocalAutomationsResource {
315 pub async fn list_all(
317 &self,
318 application_id: &str,
319 ) -> Result<Vec<models::LocalAutomation>, ManagerError> {
320 collect_all(&self.retry, map_manager_err, |page| async move {
321 let r = local_automation_api::list_local_automations(
322 self.cfg.as_ref(),
323 application_id,
324 Some(page),
325 None,
326 )
327 .await?;
328 Ok((r.items, r.pagination.pages, r.pagination.current))
329 })
330 .await
331 }
332
333 pub async fn create(
335 &self,
336 application_id: &str,
337 body: models::RestCreateLocalAutomation,
338 ) -> Result<models::LocalAutomationItemResponse, ManagerError> {
339 with_retry(&self.retry, false, || {
340 local_automation_api::create_local_automation(
341 self.cfg.as_ref(),
342 application_id,
343 body.clone(),
344 )
345 })
346 .await
347 .map_err(map_manager_err)
348 }
349
350 pub async fn get(
352 &self,
353 application_id: &str,
354 id: &str,
355 ) -> Result<models::LocalAutomationItemResponse, ManagerError> {
356 with_retry(&self.retry, true, || {
357 local_automation_api::get_local_automation(self.cfg.as_ref(), application_id, id)
358 })
359 .await
360 .map_err(map_manager_err)
361 }
362
363 pub async fn update(
365 &self,
366 application_id: &str,
367 id: &str,
368 body: models::RestUpdateLocalAutomation,
369 ) -> Result<models::LocalAutomationItemResponse, ManagerError> {
370 with_retry(&self.retry, false, || {
371 local_automation_api::update_local_automation(
372 self.cfg.as_ref(),
373 application_id,
374 id,
375 body.clone(),
376 )
377 })
378 .await
379 .map_err(map_manager_err)
380 }
381
382 pub async fn delete(&self, application_id: &str, id: &str) -> Result<(), ManagerError> {
384 with_retry(&self.retry, false, || {
385 local_automation_api::delete_local_automation(self.cfg.as_ref(), application_id, id)
386 })
387 .await
388 .map_err(map_manager_err)?;
389 Ok(())
390 }
391}