assemblylift_awslambda_guest/
lib.rs1extern crate assemblylift_core_guest;
2extern crate assemblylift_core_io_guest;
3
4use std::collections::HashMap;
5use std::fmt;
6use std::fmt::Debug;
7
8use serde::{Deserialize, Serialize};
9
10use assemblylift_core_guest::*;
11
12extern "C" {
13 fn __asml_abi_console_log(ptr: *const u8, len: usize);
14 fn __asml_abi_success(ptr: *const u8, len: usize);
15}
16
17pub struct AwsLambdaClient(Guest);
18
19impl AwsLambdaClient {
20 pub fn new() -> AwsLambdaClient {
21 AwsLambdaClient { 0: Guest {} }
22 }
23}
24
25impl GuestCore for AwsLambdaClient {
26 fn console_log(message: String) {
27 unsafe { __asml_abi_console_log(message.as_ptr(), message.len()) }
28 }
29
30 fn success(response: String) {
31 unsafe { __asml_abi_success(response.as_ptr(), response.len()) }
32 }
33}
34
35#[derive(Serialize, Deserialize, Clone, Debug)]
36pub struct ApiGatewayEvent {
37 pub resource: String,
38 pub path: String,
39 #[serde(rename = "httpMethod")]
40 pub http_method: String,
41 pub headers: HashMap<String, String>,
42 #[serde(rename = "queryStringParameters")]
43 pub query_string_parameters: Option<HashMap<String, String>>,
44 #[serde(rename = "pathParameters")]
45 pub path_parameters: Option<HashMap<String, String>>,
46 #[serde(rename = "stageVariables")]
47 pub stage_variables: Option<HashMap<String, String>>,
48 #[serde(rename = "requestContext")]
49 pub request_context: Option<ApiGatewayRequestContext>,
50 pub body: Option<String>,
51}
52
53pub type StatusCode = u16;
54#[derive(Serialize, Deserialize)]
55pub struct ApiGatewayResponse {
56 #[serde(rename = "isBase64Encoded")]
57 is_base64_encoded: bool,
58 #[serde(rename = "statusCode")]
59 status_code: StatusCode,
60 headers: HashMap<String, String>,
61 body: String,
62}
63
64#[derive(Serialize, Deserialize)]
65pub struct ApiGatewayError {
66 pub code: StatusCode,
67 pub desc: String,
68 pub message: String,
69}
70
71#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
72pub enum ApiGatewayErrorCode {
73 NotFound = 404,
74 FunctionError = 520,
75}
76
77#[derive(Serialize, Deserialize, Clone, Debug)]
78pub struct ApiGatewayRequestContext {
79 pub authorizer: Option<ApiGatewayRequestContextAuthorizer>,
80 pub identity: Option<ApiGatewayRequestContextIdentity>,
81}
82
83#[derive(Serialize, Deserialize, Clone, Debug)]
84pub struct ApiGatewayRequestContextAuthorizer {
85 pub claims: Option<HashMap<String, String>>,
86 pub scopes: Option<Vec<String>>,
87}
88
89#[derive(Serialize, Deserialize, Clone, Debug)]
90pub struct ApiGatewayRequestContextIdentity {
91 #[serde(rename = "accessKey")]
92 pub access_key: Option<String>,
93 #[serde(rename = "accountId")]
94 pub account_id: Option<String>,
95 pub caller: Option<String>,
96 #[serde(rename = "cognitoAmr")]
97 pub cognito_amr: Option<String>,
98 #[serde(rename = "cognitoAuthenticationProvider")]
99 pub cognito_authentication_provider: Option<String>,
100 #[serde(rename = "cognitoAuthenticationType")]
101 pub cognito_authentication_type: Option<String>,
102 #[serde(rename = "cognitoIdentityId")]
103 pub cognito_identity_id: Option<String>,
104 #[serde(rename = "cognitoIdentityPoolId")]
105 pub cognito_identity_pool_id: Option<String>,
106 #[serde(rename = "principalOrgId")]
107 pub principal_org_id: Option<String>,
108 #[serde(rename = "sourceIp")]
109 pub source_ip: String,
110 pub user: Option<String>,
111 #[serde(rename = "userAgent")]
112 pub user_agent: Option<String>,
113 #[serde(rename = "userArn")]
114 pub user_arn: Option<String>,
115}
116
117impl fmt::Display for ApiGatewayErrorCode {
118 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119 match self {
120 ApiGatewayErrorCode::NotFound => write!(f, "Missing Resource"),
121 ApiGatewayErrorCode::FunctionError => write!(f, "Function Error"),
122 }
123 }
124}
125
126impl ApiGatewayResponse {
127 pub fn ok(body: String, content_type: Option<String>, is_base64_encoded: bool, gzip: bool) -> Self {
128 let mut headers = HashMap::default();
129 headers.insert(
130 "content-type".to_string(),
131 content_type.unwrap_or_else(|| String::from("application/json")),
132 );
133 if gzip {
134 headers.insert(
135 "content-encoding".to_string(),
136 "gzip".to_string(),
137 );
138 }
139
140 Self {
141 status_code: 200,
142 is_base64_encoded,
143 headers,
144 body,
145 }
146 }
147
148 pub fn error(message: String, code: ApiGatewayErrorCode) -> Self {
149 let mut headers = HashMap::default();
150 headers.insert(
151 String::from("content-type"),
152 String::from("application/json"),
153 );
154
155 Self {
156 status_code: code as StatusCode,
157 is_base64_encoded: false,
158 headers,
159 body: serde_json::to_string(&ApiGatewayError {
160 code: code as StatusCode,
161 desc: code.to_string(),
162 message,
163 })
164 .unwrap(),
165 }
166 }
167}
168
169pub struct LambdaContext<'a, E: Serialize + Deserialize<'a> + Clone + Debug> {
170 pub client: AwsLambdaClient,
171 pub event: E,
172 pub _phantom: std::marker::PhantomData<&'a E>,
173}
174
175#[macro_export]
176macro_rules! handler {
177 ($context:ident: $type:ty, $async_handler:expr) => {
178 #[no_mangle]
179 pub fn handler() -> i32 {
180 use assemblylift_core_io_guest;
181 use assemblylift_core_io_guest::get_time;
182 use direct_executor;
183
184 let client = AwsLambdaClient::new();
185 let mut fib = std::io::BufReader::new(assemblylift_core_io_guest::FunctionInputBuffer::new());
186
187 let event = match serde_json::from_reader(fib) {
188 Ok(event) => event,
189 Err(why) => {
190 AwsLambdaClient::console_log(format!(
191 "ERROR deserializing Lambda Event: {}",
192 why.to_string()
193 ));
194 return -1;
195 }
196 };
197
198 let $context: $type = LambdaContext { client, event, _phantom: std::marker::PhantomData };
199
200 direct_executor::run_spinning($async_handler);
201
202 0
203 }
204 };
205}
206
207#[macro_export]
208macro_rules! http_ok {
209 ($response:ident) => {
210 AwsLambdaClient::success(
211 serde_json::to_string(&ApiGatewayResponse::ok(
212 serde_json::to_string(&$response).unwrap(),
213 None,
214 false,
215 false,
216 ))
217 .unwrap(),
218 );
219 };
220
221 ($response:expr, $type:expr, $isb64:expr, $isgzip:expr) => {
222 AwsLambdaClient::success(
223 serde_json::to_string(&ApiGatewayResponse::ok(
224 $response,
225 $type,
226 $isb64,
227 $isgzip,
228 ))
229 .unwrap(),
230 );
231 };
232}
233
234#[macro_export]
235macro_rules! http_error {
236 ($message:expr) => {
237 AwsLambdaClient::success(
238 serde_json::to_string(&ApiGatewayResponse::error(
239 $message,
240 ApiGatewayErrorCode::FunctionError,
241 ))
242 .unwrap(),
243 );
244 };
245}
246
247#[macro_export]
248macro_rules! http_not_found {
249 ($resource_name:expr) => {
250 AwsLambdaClient::success(
251 serde_json::to_string(&ApiGatewayResponse::error(
252 format!("missing resource {:?}", $resource_name),
253 ApiGatewayErrorCode::NotFound,
254 ))
255 .unwrap(),
256 );
257 };
258}