aw_test/services/
functions.rs

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    /// Get a list of all the project's functions. You can use the query params to
21    /// filter your results.
22    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    /// Create a new function. You can pass a list of
77    /// [permissions](/docs/permissions) to allow different project users or team
78    /// with access to execute the function using the client API.
79    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    /// Get a list of all runtimes that are currently active on your instance.
129    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    /// Get a function by its unique ID.
158    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    /// Update function by its unique ID.
187    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    /// Delete a function by its unique ID.
235    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    /// Get a list of all the project's code deployments. You can use the query
262    /// params to filter your results.
263    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    /// Create a new function code deployment. Use this endpoint to upload a new
318    /// version of your code function. To execute your newly uploaded code, you'll
319    /// need to update the function's deployment to use your new deployment UID.
320    /// 
321    /// This endpoint accepts a tar.gz file compressed with your code. Make sure to
322    /// include any dependencies your code has within the compressed file. You can
323    /// learn more about code packaging in the [Appwrite Cloud Functions
324    /// tutorial](/docs/functions).
325    /// 
326    /// Use the "command" param to set the entry point used to execute your code.
327    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                // Stream Data.
356                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 last chunk, return the response.
397                    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    /// Get a code deployment by its unique ID.
412    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    /// Update the function code deployment ID using the unique function ID. Use
441    /// this endpoint to switch the code deployment that should be executed by the
442    /// execution endpoint.
443    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    /// Delete a code deployment by its unique ID.
472    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    /// Get a list of all the current user function execution logs. You can use the
525    /// query params to filter your results. On admin mode, this endpoint will
526    /// return a list of all of the project's executions. [Learn more about
527    /// different API modes](/docs/admin).
528    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    /// Trigger a function execution. The returned object will return you the
577    /// current execution status. You can ping the `Get Execution` endpoint to get
578    /// updates on the current execution status. Once this endpoint is called, your
579    /// function execution process will start asynchronously.
580    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    /// Get a function execution log by its unique ID.
616    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}