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