1use crate::client::{Client, ParamType};
2use std::collections::HashMap;
3use crate::services::AppwriteException;
4use crate::models;
5use serde_json::json;
6use std::io::Read;
7
8#[derive(Clone)]
9pub struct Functions {
10 client: Client
11}
12
13impl Functions {
14 pub fn new(client: &Client) -> Self {
15 Self {
16 client: client.clone()
17 }
18 }
19
20 pub fn list(&self, search: Option<&str>, limit: Option<i64>, offset: Option<i64>, cursor: Option<&str>, cursor_direction: Option<&str>, order_type: Option<&str>) -> Result<models::FunctionList, AppwriteException> {
23 let path = "/functions";
24 let headers: HashMap<String, String> = [
25 ("content-type".to_string(), "application/json".to_string()),
26 ].iter().cloned().collect();
27
28 let search:&str = match search {
29 Some(data) => data,
30 None => ""
31 };
32
33 let cursor:&str = match cursor {
34 Some(data) => data,
35 None => ""
36 };
37
38 let cursor_direction:&str = match cursor_direction {
39 Some(data) => data,
40 None => ""
41 };
42
43 let order_type:&str = match order_type {
44 Some(data) => data,
45 None => ""
46 };
47
48 let params: HashMap<String, ParamType> = [
49 ("search".to_string(), ParamType::String(search.to_string())),
50 ("limit".to_string(), ParamType::OptionalNumber(limit)),
51 ("offset".to_string(), ParamType::OptionalNumber(offset)),
52 ("cursor".to_string(), ParamType::String(cursor.to_string())),
53 ("cursorDirection".to_string(), ParamType::String(cursor_direction.to_string())),
54 ("orderType".to_string(), ParamType::String(order_type.to_string())),
55 ].iter().cloned().collect();
56
57 let response = self.client.clone().call("GET", &path, Some(headers), Some(params) );
58
59 let processedResponse:models::FunctionList = match response {
60 Ok(r) => {
61 match r.json() {
62 Ok(json) => json,
63 Err(e) => {
64 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
65 }
66 }
67 }
68 Err(e) => {
69 return Err(e);
70 }
71 };
72
73 Ok(processedResponse)
74 }
75
76 pub fn create(&self, function_id: &str, name: &str, execute: &[&str], runtime: &str, vars: Option<Option<HashMap<String, crate::client::ParamType>>>, events: Option<&[&str]>, schedule: Option<&str>, timeout: Option<i64>) -> Result<models::Function, AppwriteException> {
80 let path = "/functions";
81 let headers: HashMap<String, String> = [
82 ("content-type".to_string(), "application/json".to_string()),
83 ].iter().cloned().collect();
84
85 let events:&[&str] = match events {
86 Some(data) => data,
87 None => &[]
88 };
89
90 let schedule:&str = match schedule {
91 Some(data) => data,
92 None => ""
93 };
94
95 let params: HashMap<String, ParamType> = [
96 ("functionId".to_string(), ParamType::String(function_id.to_string())),
97 ("name".to_string(), ParamType::String(name.to_string())),
98 ("execute".to_string(), ParamType::Array(execute.into_iter().map(|x| ParamType::String(x.to_string())).collect())),
99 ("runtime".to_string(), ParamType::String(runtime.to_string())),
100 ("vars".to_string(), ParamType::OptionalObject(match vars {
101 Some(data) => data,
102 None => Some(HashMap::new())
103 })),
104 ("events".to_string(), ParamType::Array(events.into_iter().map(|x| ParamType::String(x.to_string())).collect())),
105 ("schedule".to_string(), ParamType::String(schedule.to_string())),
106 ("timeout".to_string(), ParamType::OptionalNumber(timeout)),
107 ].iter().cloned().collect();
108
109 let response = self.client.clone().call("POST", &path, Some(headers), Some(params) );
110
111 let processedResponse:models::Function = match response {
112 Ok(r) => {
113 match r.json() {
114 Ok(json) => json,
115 Err(e) => {
116 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
117 }
118 }
119 }
120 Err(e) => {
121 return Err(e);
122 }
123 };
124
125 Ok(processedResponse)
126 }
127
128 pub fn list_runtimes(&self) -> Result<models::RuntimeList, AppwriteException> {
130 let path = "/functions/runtimes";
131 let headers: HashMap<String, String> = [
132 ("content-type".to_string(), "application/json".to_string()),
133 ].iter().cloned().collect();
134
135 let params: HashMap<String, ParamType> = [
136 ].iter().cloned().collect();
137
138 let response = self.client.clone().call("GET", &path, Some(headers), Some(params) );
139
140 let processedResponse:models::RuntimeList = match response {
141 Ok(r) => {
142 match r.json() {
143 Ok(json) => json,
144 Err(e) => {
145 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
146 }
147 }
148 }
149 Err(e) => {
150 return Err(e);
151 }
152 };
153
154 Ok(processedResponse)
155 }
156
157 pub fn get(&self, function_id: &str) -> Result<models::Function, AppwriteException> {
159 let path = "/functions/functionId".replace("functionId", &function_id);
160 let headers: HashMap<String, String> = [
161 ("content-type".to_string(), "application/json".to_string()),
162 ].iter().cloned().collect();
163
164 let params: HashMap<String, ParamType> = [
165 ].iter().cloned().collect();
166
167 let response = self.client.clone().call("GET", &path, Some(headers), Some(params) );
168
169 let processedResponse:models::Function = match response {
170 Ok(r) => {
171 match r.json() {
172 Ok(json) => json,
173 Err(e) => {
174 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
175 }
176 }
177 }
178 Err(e) => {
179 return Err(e);
180 }
181 };
182
183 Ok(processedResponse)
184 }
185
186 pub fn update(&self, function_id: &str, name: &str, execute: &[&str], vars: Option<Option<HashMap<String, crate::client::ParamType>>>, events: Option<&[&str]>, schedule: Option<&str>, timeout: Option<i64>) -> Result<models::Function, AppwriteException> {
188 let path = "/functions/functionId".replace("functionId", &function_id);
189 let headers: HashMap<String, String> = [
190 ("content-type".to_string(), "application/json".to_string()),
191 ].iter().cloned().collect();
192
193 let events:&[&str] = match events {
194 Some(data) => data,
195 None => &[]
196 };
197
198 let schedule:&str = match schedule {
199 Some(data) => data,
200 None => ""
201 };
202
203 let params: HashMap<String, ParamType> = [
204 ("name".to_string(), ParamType::String(name.to_string())),
205 ("execute".to_string(), ParamType::Array(execute.into_iter().map(|x| ParamType::String(x.to_string())).collect())),
206 ("vars".to_string(), ParamType::OptionalObject(match vars {
207 Some(data) => data,
208 None => Some(HashMap::new())
209 })),
210 ("events".to_string(), ParamType::Array(events.into_iter().map(|x| ParamType::String(x.to_string())).collect())),
211 ("schedule".to_string(), ParamType::String(schedule.to_string())),
212 ("timeout".to_string(), ParamType::OptionalNumber(timeout)),
213 ].iter().cloned().collect();
214
215 let response = self.client.clone().call("PUT", &path, Some(headers), Some(params) );
216
217 let processedResponse:models::Function = match response {
218 Ok(r) => {
219 match r.json() {
220 Ok(json) => json,
221 Err(e) => {
222 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
223 }
224 }
225 }
226 Err(e) => {
227 return Err(e);
228 }
229 };
230
231 Ok(processedResponse)
232 }
233
234 pub fn delete(&self, function_id: &str) -> Result<serde_json::value::Value, AppwriteException> {
236 let path = "/functions/functionId".replace("functionId", &function_id);
237 let headers: HashMap<String, String> = [
238 ("content-type".to_string(), "application/json".to_string()),
239 ].iter().cloned().collect();
240
241 let params: HashMap<String, ParamType> = [
242 ].iter().cloned().collect();
243
244 let response = self.client.clone().call("DELETE", &path, Some(headers), Some(params) );
245
246 match response {
247 Ok(r) => {
248 let status_code = r.status();
249 if status_code == reqwest::StatusCode::NO_CONTENT {
250 Ok(json!(true))
251 } else {
252 Ok(serde_json::from_str(&r.text().unwrap()).unwrap())
253 }
254 }
255 Err(e) => {
256 Err(e)
257 }
258 }
259 }
260
261 pub fn list_deployments(&self, function_id: &str, search: Option<&str>, limit: Option<i64>, offset: Option<i64>, cursor: Option<&str>, cursor_direction: Option<&str>, order_type: Option<&str>) -> Result<models::DeploymentList, AppwriteException> {
264 let path = "/functions/functionId/deployments".replace("functionId", &function_id);
265 let headers: HashMap<String, String> = [
266 ("content-type".to_string(), "application/json".to_string()),
267 ].iter().cloned().collect();
268
269 let search:&str = match search {
270 Some(data) => data,
271 None => ""
272 };
273
274 let cursor:&str = match cursor {
275 Some(data) => data,
276 None => ""
277 };
278
279 let cursor_direction:&str = match cursor_direction {
280 Some(data) => data,
281 None => ""
282 };
283
284 let order_type:&str = match order_type {
285 Some(data) => data,
286 None => ""
287 };
288
289 let params: HashMap<String, ParamType> = [
290 ("search".to_string(), ParamType::String(search.to_string())),
291 ("limit".to_string(), ParamType::OptionalNumber(limit)),
292 ("offset".to_string(), ParamType::OptionalNumber(offset)),
293 ("cursor".to_string(), ParamType::String(cursor.to_string())),
294 ("cursorDirection".to_string(), ParamType::String(cursor_direction.to_string())),
295 ("orderType".to_string(), ParamType::String(order_type.to_string())),
296 ].iter().cloned().collect();
297
298 let response = self.client.clone().call("GET", &path, Some(headers), Some(params) );
299
300 let processedResponse:models::DeploymentList = match response {
301 Ok(r) => {
302 match r.json() {
303 Ok(json) => json,
304 Err(e) => {
305 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
306 }
307 }
308 }
309 Err(e) => {
310 return Err(e);
311 }
312 };
313
314 Ok(processedResponse)
315 }
316
317 pub fn create_deployment(&self, function_id: &str, entrypoint: &str, code: std::path::PathBuf, activate: bool) -> Result<models::Deployment, AppwriteException> {
328 let path = "/functions/functionId/deployments".replace("functionId", &function_id);
329 let mut headers: HashMap<String, String> = [
330 ("content-type".to_string(), "multipart/form-data".to_string()),
331 ].iter().cloned().collect();
332
333 let mut params: HashMap<String, ParamType> = [
334 ("entrypoint".to_string(), ParamType::String(entrypoint.to_string())),
335 ("activate".to_string(), ParamType::Bool(activate)),
336 ].iter().cloned().collect();
337
338 let mut fileBuf = std::fs::File::open(code.clone()).unwrap();
339
340 let size = fileBuf.metadata().unwrap().len();
341
342 match size {
343 size if size <= crate::client::CHUNK_SIZE => {
344 params.insert("code".to_string(), ParamType::FilePath(code));
345 match self.client.clone().call("POST", &path, Some(headers), Some(params)) {
346 Ok(r) => {
347 Ok(r.json::<models::Deployment>().unwrap())
348 }
349 Err(e) => {
350 Err(e)
351 }
352 }
353 }
354 _ => {
355 let mut id = "".to_string();
357
358 let mut resumeCounter: u64 = 0;
359 let totalCounters = (((size / crate::client::CHUNK_SIZE) as f64).ceil() as u64) + 1;
360
361
362 let response: reqwest::blocking::Response;
363
364 for counter in resumeCounter..totalCounters {
365 let mut headers: HashMap<String, String> = [
366 ("content-type".to_string(), "multipart/form-data".to_string()),
367 ].iter().cloned().collect();
368
369 let mut params = params.clone();
370
371 headers.insert("content-range".to_string(), format!("bytes {}-{}/{}", (counter * crate::client::CHUNK_SIZE),
372 std::cmp::min((counter * crate::client::CHUNK_SIZE) + crate::client::CHUNK_SIZE - 1, size), size));
373
374 if id.len() != 0 {
375 headers.insert("x-appwrite-id".to_string(), id.to_string());
376 }
377
378 let mut chunk = Vec::with_capacity(crate::client::CHUNK_SIZE as usize);
379
380 match fileBuf.by_ref().take(crate::client::CHUNK_SIZE).read_to_end(&mut chunk) {
381 Ok(_) => (),
382 Err(e) => {
383 return Err(AppwriteException::new(format!("A error occoured. ERR: {}, This could either be a connection error or an internal Appwrite error. Please check your Appwrite instance logs. ", e), 0, "".to_string()))
384 }
385 };
386
387 params.insert("file".to_string(), ParamType::StreamData(chunk, code.file_name().unwrap().to_string_lossy().to_string()));
388
389 let response = match self.client.clone().call("POST", &path, Some(headers), Some(params)) {
390 Ok(r) => r,
391 Err(e) => {
392 return Err(e);
393 }
394 };
395
396 if counter == totalCounters - 1 {
398 return Ok(response.json::<models::Deployment>().unwrap());
399 } else {
400 if id.len() == 0 {
401 id = response.json::<serde_json::Value>().unwrap()["$id"].as_str().unwrap().to_owned();
402 }
403 }
404 };
405
406 return Err(AppwriteException::new("Error uploading chunk data.".to_string(), 500, "0".to_string()));
407 }
408 }
409 }
410
411 pub fn get_deployment(&self, function_id: &str, deployment_id: &str) -> Result<models::DeploymentList, AppwriteException> {
413 let path = "/functions/functionId/deployments/deploymentId".replace("functionId", &function_id).replace("deploymentId", &deployment_id);
414 let headers: HashMap<String, String> = [
415 ("content-type".to_string(), "application/json".to_string()),
416 ].iter().cloned().collect();
417
418 let params: HashMap<String, ParamType> = [
419 ].iter().cloned().collect();
420
421 let response = self.client.clone().call("GET", &path, Some(headers), Some(params) );
422
423 let processedResponse:models::DeploymentList = match response {
424 Ok(r) => {
425 match r.json() {
426 Ok(json) => json,
427 Err(e) => {
428 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
429 }
430 }
431 }
432 Err(e) => {
433 return Err(e);
434 }
435 };
436
437 Ok(processedResponse)
438 }
439
440 pub fn update_deployment(&self, function_id: &str, deployment_id: &str) -> Result<models::Function, AppwriteException> {
444 let path = "/functions/functionId/deployments/deploymentId".replace("functionId", &function_id).replace("deploymentId", &deployment_id);
445 let headers: HashMap<String, String> = [
446 ("content-type".to_string(), "application/json".to_string()),
447 ].iter().cloned().collect();
448
449 let params: HashMap<String, ParamType> = [
450 ].iter().cloned().collect();
451
452 let response = self.client.clone().call("PATCH", &path, Some(headers), Some(params) );
453
454 let processedResponse:models::Function = match response {
455 Ok(r) => {
456 match r.json() {
457 Ok(json) => json,
458 Err(e) => {
459 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
460 }
461 }
462 }
463 Err(e) => {
464 return Err(e);
465 }
466 };
467
468 Ok(processedResponse)
469 }
470
471 pub fn delete_deployment(&self, function_id: &str, deployment_id: &str) -> Result<serde_json::value::Value, AppwriteException> {
473 let path = "/functions/functionId/deployments/deploymentId".replace("functionId", &function_id).replace("deploymentId", &deployment_id);
474 let headers: HashMap<String, String> = [
475 ("content-type".to_string(), "application/json".to_string()),
476 ].iter().cloned().collect();
477
478 let params: HashMap<String, ParamType> = [
479 ].iter().cloned().collect();
480
481 let response = self.client.clone().call("DELETE", &path, Some(headers), Some(params) );
482
483 match response {
484 Ok(r) => {
485 let status_code = r.status();
486 if status_code == reqwest::StatusCode::NO_CONTENT {
487 Ok(json!(true))
488 } else {
489 Ok(serde_json::from_str(&r.text().unwrap()).unwrap())
490 }
491 }
492 Err(e) => {
493 Err(e)
494 }
495 }
496 }
497
498 pub fn retry_build(&self, function_id: &str, deployment_id: &str, build_id: &str) -> Result<serde_json::value::Value, AppwriteException> {
499 let path = "/functions/functionId/deployments/deploymentId/builds/buildId".replace("functionId", &function_id).replace("deploymentId", &deployment_id).replace("buildId", &build_id);
500 let headers: HashMap<String, String> = [
501 ("content-type".to_string(), "application/json".to_string()),
502 ].iter().cloned().collect();
503
504 let params: HashMap<String, ParamType> = [
505 ].iter().cloned().collect();
506
507 let response = self.client.clone().call("POST", &path, Some(headers), Some(params) );
508
509 match response {
510 Ok(r) => {
511 let status_code = r.status();
512 if status_code == reqwest::StatusCode::NO_CONTENT {
513 Ok(json!(true))
514 } else {
515 Ok(serde_json::from_str(&r.text().unwrap()).unwrap())
516 }
517 }
518 Err(e) => {
519 Err(e)
520 }
521 }
522 }
523
524 pub fn list_executions(&self, function_id: &str, limit: Option<i64>, offset: Option<i64>, search: Option<&str>, cursor: Option<&str>, cursor_direction: Option<&str>) -> Result<models::ExecutionList, AppwriteException> {
529 let path = "/functions/functionId/executions".replace("functionId", &function_id);
530 let headers: HashMap<String, String> = [
531 ("content-type".to_string(), "application/json".to_string()),
532 ].iter().cloned().collect();
533
534 let search:&str = match search {
535 Some(data) => data,
536 None => ""
537 };
538
539 let cursor:&str = match cursor {
540 Some(data) => data,
541 None => ""
542 };
543
544 let cursor_direction:&str = match cursor_direction {
545 Some(data) => data,
546 None => ""
547 };
548
549 let params: HashMap<String, ParamType> = [
550 ("limit".to_string(), ParamType::OptionalNumber(limit)),
551 ("offset".to_string(), ParamType::OptionalNumber(offset)),
552 ("search".to_string(), ParamType::String(search.to_string())),
553 ("cursor".to_string(), ParamType::String(cursor.to_string())),
554 ("cursorDirection".to_string(), ParamType::String(cursor_direction.to_string())),
555 ].iter().cloned().collect();
556
557 let response = self.client.clone().call("GET", &path, Some(headers), Some(params) );
558
559 let processedResponse:models::ExecutionList = match response {
560 Ok(r) => {
561 match r.json() {
562 Ok(json) => json,
563 Err(e) => {
564 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
565 }
566 }
567 }
568 Err(e) => {
569 return Err(e);
570 }
571 };
572
573 Ok(processedResponse)
574 }
575
576 pub fn create_execution(&self, function_id: &str, data: Option<&str>, xasync: Option<bool>) -> Result<models::Execution, AppwriteException> {
581 let path = "/functions/functionId/executions".replace("functionId", &function_id);
582 let headers: HashMap<String, String> = [
583 ("content-type".to_string(), "application/json".to_string()),
584 ].iter().cloned().collect();
585
586 let data:&str = match data {
587 Some(data) => data,
588 None => ""
589 };
590
591 let params: HashMap<String, ParamType> = [
592 ("data".to_string(), ParamType::String(data.to_string())),
593 ("async".to_string(), ParamType::OptionalBool(xasync)),
594 ].iter().cloned().collect();
595
596 let response = self.client.clone().call("POST", &path, Some(headers), Some(params) );
597
598 let processedResponse:models::Execution = match response {
599 Ok(r) => {
600 match r.json() {
601 Ok(json) => json,
602 Err(e) => {
603 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
604 }
605 }
606 }
607 Err(e) => {
608 return Err(e);
609 }
610 };
611
612 Ok(processedResponse)
613 }
614
615 pub fn get_execution(&self, function_id: &str, execution_id: &str) -> Result<models::Execution, AppwriteException> {
617 let path = "/functions/functionId/executions/executionId".replace("functionId", &function_id).replace("executionId", &execution_id);
618 let headers: HashMap<String, String> = [
619 ("content-type".to_string(), "application/json".to_string()),
620 ].iter().cloned().collect();
621
622 let params: HashMap<String, ParamType> = [
623 ].iter().cloned().collect();
624
625 let response = self.client.clone().call("GET", &path, Some(headers), Some(params) );
626
627 let processedResponse:models::Execution = match response {
628 Ok(r) => {
629 match r.json() {
630 Ok(json) => json,
631 Err(e) => {
632 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
633 }
634 }
635 }
636 Err(e) => {
637 return Err(e);
638 }
639 };
640
641 Ok(processedResponse)
642 }
643
644 pub fn get_usage(&self, function_id: &str, range: Option<&str>) -> Result<models::UsageFunctions, AppwriteException> {
645 let path = "/functions/functionId/usage".replace("functionId", &function_id);
646 let headers: HashMap<String, String> = [
647 ("content-type".to_string(), "application/json".to_string()),
648 ].iter().cloned().collect();
649
650 let range:&str = match range {
651 Some(data) => data,
652 None => ""
653 };
654
655 let params: HashMap<String, ParamType> = [
656 ("range".to_string(), ParamType::String(range.to_string())),
657 ].iter().cloned().collect();
658
659 let response = self.client.clone().call("GET", &path, Some(headers), Some(params) );
660
661 let processedResponse:models::UsageFunctions = match response {
662 Ok(r) => {
663 match r.json() {
664 Ok(json) => json,
665 Err(e) => {
666 return Err(AppwriteException::new(format!("Error parsing response json: {}", e), 0, "".to_string()));
667 }
668 }
669 }
670 Err(e) => {
671 return Err(e);
672 }
673 };
674
675 Ok(processedResponse)
676 }
677}