openwhisk_client_rust/api/
action.rs

1use crate::client::Context;
2use derive_new::new;
3use serde::{Deserialize, Serialize};
4use serde_json::{Error, Value};
5
6use super::{traits::Service, HttpMethods, KeyValue, Limits, ACTION_ENDPOINT, NAMESPACE_ENDPOINT};
7
8/// Representation of Action Service
9#[derive(new, Debug, Default, Deserialize, Serialize, Clone)]
10pub struct ActionService<T> {
11    /// A action service must have a client to handle http request
12    client: T,
13    /// A action service uses the context which sets openwhisk properties
14    context: Context,
15}
16
17/// Represenation of Action
18#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
19pub struct Action {
20    /// A action must have a namspace where it exists
21    #[serde(default)]
22    pub namespace: String,
23    /// A action must have a name to represent it
24    #[serde(default)]
25    pub name: String,
26    /// A action must have a versioning
27    #[serde(default)]
28    pub version: String,
29    /// A action can take concurrrent limit
30    #[serde(default)]
31    pub limits: Limits,
32    /// A action must have Exec properties
33    pub exec: Exec,
34    /// A action must have error to handle error created
35    #[serde(default)]
36    pub error: String,
37    /// Toggle to publish action
38    #[serde(default)]
39    pub publish: bool,
40    /// Updated version count of actions
41    #[serde(default)]
42    pub updated: i64,
43    /// Keyvalue pair for annotate Actions
44    pub annotations: Vec<KeyValue>,
45}
46
47/// Actions Execucatble properties
48#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
49pub struct Exec {
50    /// Action's Kind
51    #[serde(default)]
52    pub kind: String,
53    /// Action's Code
54    #[serde(default)]
55    pub code: String,
56    /// Action's Image
57    #[serde(default)]
58    pub image: String,
59    /// Action's Init method
60    #[serde(default)]
61    pub init: String,
62    /// Action's Main method
63    #[serde(default)]
64    pub main: String,
65    /// Action's components
66    #[serde(default)]
67    pub components: Vec<String>,
68    /// Toogled to true Action will be of binary
69    #[serde(default)]
70    pub binary: bool,
71}
72
73#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
74pub struct ActionList {
75    pub name: String,
76    pub namespace: String,
77}
78
79impl<T> ActionService<T>
80where
81    T: Service,
82{
83    /// Returns a list of Actions
84    pub fn list(&self) -> Result<Vec<ActionList>, String> {
85        let url = format!(
86            "{}/api/v1/{}/{}/{}",
87            self.context.host(),
88            NAMESPACE_ENDPOINT,
89            self.context.namespace(),
90            ACTION_ENDPOINT
91        );
92
93        let user_auth = self.context.auth();
94        let user = user_auth.0;
95        let pass = user_auth.1;
96
97        let request = match self.client.new_request(
98            Some(HttpMethods::GET),
99            url.as_str(),
100            Some((user, pass)),
101            None,
102        ) {
103            Ok(request) => request,
104            Err(error) => return Err(error),
105        };
106
107        match self.client.invoke_request(request) {
108            Ok(x) => {
109                let actions: Result<Vec<Action>, Error> = serde_json::from_value(x);
110                match actions {
111                    Ok(actions) => {
112                        let mut result = Vec::new();
113                        for action in actions.into_iter() {
114                            let actionlist = ActionList {
115                                name: action.name,
116                                namespace: action.namespace,
117                            };
118
119                            result.push(actionlist)
120                        }
121
122                        Ok(result)
123                    }
124                    Err(error) => Err(format!("Failed to deserailize actions {}", error)),
125                }
126            }
127
128            Err(error) => Err(format!("Failed to fetch the list of actions {}", error)),
129        }
130    }
131
132    ///
133    /// Returns Properties of action by using action name
134    ///
135    /// # Arguments
136    /// * `action_name` - String slice that holds action name
137    /// * `fetch_code`  - Toggle to get code for the action
138    ///
139
140    pub fn get(&self, action_name: &str, fetch_code: bool) -> Result<Action, String> {
141        let url = format!(
142            "{}/api/v1/{}/{}/{}/{}?code={}",
143            self.context.host(),
144            NAMESPACE_ENDPOINT,
145            self.context.namespace(),
146            ACTION_ENDPOINT,
147            action_name,
148            fetch_code
149        );
150
151        let user_auth = self.context.auth();
152        let user = user_auth.0;
153        let pass = user_auth.1;
154
155        let request = match self.client.new_request(
156            Some(HttpMethods::GET),
157            url.as_str(),
158            Some((user, pass)),
159            None,
160        ) {
161            Ok(request) => request,
162            Err(error) => return Err(error),
163        };
164
165        match self.client.invoke_request(request) {
166            Ok(x) => match serde_json::from_value(x) {
167                Ok(actions) => Ok(actions),
168                Err(error) => Err(format!("Failed to deserailize actions {}", error)),
169            },
170            Err(error) => Err(format!("Failed to get action properties {}", error)),
171        }
172    }
173
174    ///
175    /// Delete Action and returns deleted Action by using action name
176    ///
177    /// # Arguments
178    /// * `action_name` - String slice that holds action name
179    ///
180    pub fn delete(&self, action_name: &str) -> Result<Action, String> {
181        let url = format!(
182            "{}/api/v1/{}/{}/{}/{}?code=false",
183            self.context.host(),
184            NAMESPACE_ENDPOINT,
185            self.context.namespace(),
186            ACTION_ENDPOINT,
187            action_name,
188        );
189
190        let user_auth = self.context.auth();
191        let user = user_auth.0;
192        let pass = user_auth.1;
193
194        let request = match self.client.new_request(
195            Some(HttpMethods::DELETE),
196            url.as_str(),
197            Some((user, pass)),
198            None,
199        ) {
200            Ok(request) => request,
201            Err(error) => return Err(error),
202        };
203
204        match self.client.invoke_request(request) {
205            Ok(x) => match serde_json::from_value(x) {
206                Ok(actions) => Ok(actions),
207                Err(err) => Err(format!("Failed to deserailize actions {}", err)),
208            },
209            Err(x) => Err(format!("Failed to get action properties {}", x)),
210        }
211    }
212
213    ///
214    /// Insert Action and returns new action created
215    ///
216    /// # Arguments
217    /// * `action`    - String slice that holds action name
218    /// * `overwrite` - Bool toggle overwite of action if it present already
219    ///
220    pub fn insert(&self, action: &Action, overwrite: bool) -> Result<Action, String> {
221        let url = format!(
222            "{}/api/v1/{}/{}/{}/{}?overwrite={}",
223            self.context.host(),
224            NAMESPACE_ENDPOINT,
225            self.context.namespace(),
226            ACTION_ENDPOINT,
227            action.name,
228            overwrite,
229        );
230
231        let user_auth = self.context.auth();
232        let user = user_auth.0;
233        let pass = user_auth.1;
234
235        let body = serde_json::to_value(action).unwrap();
236
237        let request = match self.client.new_request(
238            Some(HttpMethods::PUT),
239            url.as_str(),
240            Some((user, pass)),
241            Some(body),
242        ) {
243            Ok(request) => request,
244            Err(error) => return Err(error),
245        };
246
247        match self.client.invoke_request(request) {
248            Ok(x) => match serde_json::from_value(x) {
249                Ok(actions) => Ok(actions),
250                Err(err) => Err(format!("Failed to deserailize actions {}", err)),
251            },
252            Err(x) => Err(format!("Failed to get action properties {}", x)),
253        }
254    }
255
256    ///
257    /// Invoke Action and returns action result
258    ///
259    /// # Arguments
260    /// * `action_name` - String slice that holds action name
261    /// * `payload`     - Params that action takes for exection
262    /// * `blocking`    - Toggle to block action execution until it returns result
263    /// * `result`      - Toggled only action result is returned
264    ///
265    pub fn invoke(
266        &self,
267        action_name: &str,
268        payload: Value,
269        blocking: bool,
270        result: bool,
271    ) -> Result<Value, String> {
272        let url = format!(
273            "{}/api/v1/{}/{}/{}/{}?blocking={}&result={}",
274            self.context.host(),
275            NAMESPACE_ENDPOINT,
276            self.context.namespace(),
277            ACTION_ENDPOINT,
278            action_name,
279            blocking,
280            result
281        );
282        let user_auth = self.context.auth();
283        let user = user_auth.0;
284        let pass = user_auth.1;
285
286        let request = match self.client.new_request(
287            Some(HttpMethods::POST),
288            url.as_str(),
289            Some((user, pass)),
290            Some(payload),
291        ) {
292            Ok(request) => request,
293            Err(error) => return Err(error),
294        };
295
296        match self.client.invoke_request(request) {
297            Ok(x) => match serde_json::from_value(x) {
298                Ok(actions) => Ok(actions),
299                Err(err) => Err(format!("Failed to deserailize actions {}", err)),
300            },
301            Err(x) => Err(format!("Failed to invoke action {}", x)),
302        }
303    }
304}