1use bytes::Bytes;
2use rusoto_core::RusotoError;
3use rusoto_lambda::{InvocationRequest, InvocationResponse, InvokeError, Lambda, LambdaClient};
4use serde::{Deserialize, Serialize};
5use serde_json::{json, Value};
6use std::env;
7
8pub async fn invoke<P>(
9 function_name: String,
10 path: String,
11 method: String,
12 body_option: Option<P>,
13) -> Result<String, RusotoError<InvokeError>>
14where
15 P: Serialize,
16{
17 let body: Value;
18 if body_option.is_none() {
19 body = Default::default();
20 } else {
21 body = json!(json!(body_option.unwrap()).to_string());
22 }
23
24 let request = Request {
25 resource: path.clone(),
26 path: path.clone(),
27 http_method: method.clone(),
28 headers: Headers {
29 accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9".to_string(),
30 accept_encoding: "gzip, deflate, br".to_string(),
31 accept_language: "en-US,en;q=0.9".to_string(),
32 cookie: "s_fid=7AAB6XMPLAFD9BBF-0643XMPL09956DE2; regStatus=pre-register".to_string(),
33 content_type: "application/json".to_string(),
34 host: "70ixmpl4fl.execute-api.us-east-2.amazonaws.com".to_string(),
35 sec_fetch_dest: "document".to_string(),
36 sec_fetch_mode: "navigate".to_string(),
37 sec_fetch_site: "none".to_string(),
38 upgrade_insecure_requests: "1".to_string(),
39 user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36".to_string(),
40 x_amzn_trace_id: "Root=1-5e66d96f-7491f09xmpl79d18acf3d050".to_string(),
41 x_forwarded_for: "52.255.255.12".to_string(),
42 x_forwarded_port: "443".to_string(),
43 x_forwarded_proto: "https".to_string()
44 },
45 multi_value_headers: Default::default(),
46 query_string_parameters: Default::default(),
47 multi_value_query_string_parameters: Default::default(),
48 path_parameters: Default::default(),
49 stage_variables: Default::default(),
50 request_context: RequestContext {
51 resource_id: "id123".to_string(),
52 resource_path: path.clone(),
53 http_method: method,
54 extended_request_id: "ext123".to_string(),
55 request_time: "10/Mar/2020:00:03:59 +0000".to_string(),
56 path: path.clone(),
57 account_id: "123456789012".to_string(),
58 protocol: "HTTP/1.1".to_string(),
59 stage: "dev".to_string(),
60 domain_prefix: "prefix123".to_string(),
61 request_time_epoch: 1583798639428,
62 request_id: "id123".to_string(),
63 identity: Default::default(),
64 domain_name: "".to_string(),
65 api_id: "".to_string()
66 },
67 body,
68 is_base64_encoded: false
69 };
70 let json_request: Value = json!(request);
71 let json_request_string = serde_json::to_string(&json_request).unwrap();
72 println!("invoking with {}", json_request_string);
73 let json_request_bytes = json_request_string.into_bytes();
74
75 let lambda_client = LambdaClient::new("ap-southeast-1".parse().unwrap());
76 let res = lambda_client
77 .invoke(InvocationRequest {
78 client_context: None,
79 function_name: (env::var("APP_ENV").unwrap() + "_" + &*function_name)
80 .parse()
81 .unwrap(),
82 invocation_type: None,
83 log_type: None,
84 payload: Option::from(Bytes::from(json_request_bytes)),
85 qualifier: None,
86 })
87 .await;
88 if res.is_err() {
89 Err(res.err().unwrap())
90 } else {
91 let payload_bytes = res.unwrap().payload.unwrap();
92 Ok(String::from_utf8(payload_bytes.to_vec()).unwrap())
97 }
98}
99
100#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
101#[serde(rename_all = "camelCase")]
102pub struct Request {
103 pub resource: String,
104 pub path: String,
105 pub http_method: String,
106 pub headers: Headers,
107 pub multi_value_headers: MultiValueHeaders,
108 pub query_string_parameters: ::serde_json::Value,
109 pub multi_value_query_string_parameters: ::serde_json::Value,
110 pub path_parameters: ::serde_json::Value,
111 pub stage_variables: ::serde_json::Value,
112 pub request_context: RequestContext,
113 pub body: ::serde_json::Value,
114 pub is_base64_encoded: bool,
115}
116
117#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
118#[serde(rename_all = "camelCase")]
119pub struct Headers {
120 pub accept: String,
121 #[serde(rename = "accept-encoding")]
122 pub accept_encoding: String,
123 #[serde(rename = "accept-language")]
124 pub accept_language: String,
125 pub cookie: String,
126 #[serde(rename = "content-type")]
127 pub content_type: String,
128 #[serde(rename = "Host")]
129 pub host: String,
130 #[serde(rename = "sec-fetch-dest")]
131 pub sec_fetch_dest: String,
132 #[serde(rename = "sec-fetch-mode")]
133 pub sec_fetch_mode: String,
134 #[serde(rename = "sec-fetch-site")]
135 pub sec_fetch_site: String,
136 #[serde(rename = "upgrade-insecure-requests")]
137 pub upgrade_insecure_requests: String,
138 #[serde(rename = "User-Agent")]
139 pub user_agent: String,
140 #[serde(rename = "X-Amzn-Trace-Id")]
141 pub x_amzn_trace_id: String,
142 #[serde(rename = "X-Forwarded-For")]
143 pub x_forwarded_for: String,
144 #[serde(rename = "X-Forwarded-Port")]
145 pub x_forwarded_port: String,
146 #[serde(rename = "X-Forwarded-Proto")]
147 pub x_forwarded_proto: String,
148}
149
150#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
151#[serde(rename_all = "camelCase")]
152pub struct MultiValueHeaders {
153 pub accept: Vec<String>,
154 #[serde(rename = "accept-encoding")]
155 pub accept_encoding: Vec<String>,
156 #[serde(rename = "accept-language")]
157 pub accept_language: Vec<String>,
158 pub cookie: Vec<String>,
159 #[serde(rename = "Host")]
160 pub host: Vec<String>,
161 #[serde(rename = "sec-fetch-dest")]
162 pub sec_fetch_dest: Vec<String>,
163 #[serde(rename = "sec-fetch-mode")]
164 pub sec_fetch_mode: Vec<String>,
165 #[serde(rename = "sec-fetch-site")]
166 pub sec_fetch_site: Vec<String>,
167 #[serde(rename = "upgrade-insecure-requests")]
168 pub upgrade_insecure_requests: Vec<String>,
169 #[serde(rename = "User-Agent")]
170 pub user_agent: Vec<String>,
171 #[serde(rename = "X-Amzn-Trace-Id")]
172 pub x_amzn_trace_id: Vec<String>,
173 #[serde(rename = "X-Forwarded-For")]
174 pub x_forwarded_for: Vec<String>,
175 #[serde(rename = "X-Forwarded-Port")]
176 pub x_forwarded_port: Vec<String>,
177 #[serde(rename = "X-Forwarded-Proto")]
178 pub x_forwarded_proto: Vec<String>,
179}
180
181#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
182#[serde(rename_all = "camelCase")]
183pub struct RequestContext {
184 pub resource_id: String,
185 pub resource_path: String,
186 pub http_method: String,
187 pub extended_request_id: String,
188 pub request_time: String,
189 pub path: String,
190 pub account_id: String,
191 pub protocol: String,
192 pub stage: String,
193 pub domain_prefix: String,
194 pub request_time_epoch: i64,
195 pub request_id: String,
196 pub identity: Identity,
197 pub domain_name: String,
198 pub api_id: String,
199}
200
201#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
202#[serde(rename_all = "camelCase")]
203pub struct Identity {
204 pub cognito_identity_pool_id: ::serde_json::Value,
205 pub account_id: ::serde_json::Value,
206 pub cognito_identity_id: ::serde_json::Value,
207 pub caller: ::serde_json::Value,
208 pub source_ip: String,
209 pub principal_org_id: ::serde_json::Value,
210 pub access_key: ::serde_json::Value,
211 pub cognito_authentication_type: ::serde_json::Value,
212 pub cognito_authentication_provider: ::serde_json::Value,
213 pub user_arn: ::serde_json::Value,
214 pub user_agent: String,
215 pub user: ::serde_json::Value,
216}