|
| 1 | +open Lwt.Infix |
| 2 | + |
| 3 | +module type DevEvent = sig |
| 4 | + type t |
| 5 | + |
| 6 | + val of_yojson : Yojson.Safe.t -> (t, string) result |
| 7 | + |
| 8 | + val of_piaf : Unix.sockaddr Piaf.Server.ctx -> (t, string) Lwt_result.t |
| 9 | +end |
| 10 | + |
| 11 | +module type DevResponse = sig |
| 12 | + type t |
| 13 | + |
| 14 | + val to_yojson : t -> Yojson.Safe.t |
| 15 | + |
| 16 | + val to_piaf : t -> Piaf.Response.t |
| 17 | +end |
| 18 | + |
| 19 | +module Make |
| 20 | + (Event : DevEvent) |
| 21 | + (Response : DevResponse) = struct |
| 22 | + let make_mocked_context () = |
| 23 | + (* TODO: add proper values for this *) |
| 24 | + Lambda_runtime.Context.{ memory_limit_in_mb = 128 |
| 25 | + ; function_name = "hello" |
| 26 | + ; function_version = "$LATEST" |
| 27 | + ; invoked_function_arn = "" |
| 28 | + ; aws_request_id = "" |
| 29 | + ; xray_trace_id = None |
| 30 | + ; log_stream_name = "" |
| 31 | + ; log_group_name = "" |
| 32 | + ; client_context = None |
| 33 | + ; identity = None |
| 34 | + ; deadline = 0L } |
| 35 | + |
| 36 | + let invoke_locally ~lift handler event = |
| 37 | + let context = make_mocked_context () in |
| 38 | + lift (handler event context) |
| 39 | + |
| 40 | + let run_locally ~lift handler = |
| 41 | + let event = |
| 42 | + if Array.length Sys.argv > 1 then |
| 43 | + Lwt_io.(open_file ~mode:Input Sys.argv.(2)) |
| 44 | + >>= Lwt_io.read |
| 45 | + >|= Yojson.Safe.from_string |
| 46 | + else |
| 47 | + Lwt.return `Null |
| 48 | + in |
| 49 | + event |
| 50 | + >|= Event.of_yojson |
| 51 | + >|= (function |
| 52 | + | Ok event -> event |
| 53 | + (* TODO: This shouldnt fail, it should show a better error message instead. (stack trace?) *) |
| 54 | + | Error msg -> failwith msg) |
| 55 | + >>= invoke_locally ~lift handler |
| 56 | + >|= (function |
| 57 | + | Ok response -> |
| 58 | + response |
| 59 | + |> Response.to_yojson |
| 60 | + |> Yojson.Safe.to_string |
| 61 | + | Error msg -> |
| 62 | + "Error: " ^ msg) |
| 63 | + >|= print_endline |
| 64 | + |
| 65 | + let start_locally ~lift handler = |
| 66 | + let server_handler ctx = |
| 67 | + let event = |
| 68 | + Event.of_piaf ctx |
| 69 | + (* TODO: Shouldn't fail, return 400 message instead. *) |
| 70 | + >|= (function Ok event -> event | Error msg -> failwith msg) |
| 71 | + in |
| 72 | + let response = |
| 73 | + event |
| 74 | + >>= invoke_locally ~lift handler |
| 75 | + in |
| 76 | + response |
| 77 | + >|= (function |
| 78 | + | Ok response -> |
| 79 | + Response.to_piaf response |
| 80 | + | Error body -> |
| 81 | + Piaf.Response.of_string ~body `Internal_server_error) |
| 82 | + in |
| 83 | + Lwt.async (fun () -> |
| 84 | + let address = Unix.(ADDR_INET (inet_addr_loopback, 5000)) in |
| 85 | + Lwt_io.establish_server_with_client_socket |
| 86 | + address |
| 87 | + (Piaf.Server.create server_handler) |
| 88 | + >|= fun _server -> |
| 89 | + print_endline "Server started at: http://127.0.0.1:5000" |
| 90 | + ); |
| 91 | + let forever, _ = Lwt.wait () in |
| 92 | + forever |
| 93 | + |
| 94 | + let start_lambda ~lift handler = |
| 95 | + let p = |
| 96 | + match Array.length Sys.argv with |
| 97 | + | 1 -> start_locally ~lift handler |
| 98 | + | 2 when Sys.argv.(1) = "invoke" -> |
| 99 | + run_locally ~lift handler |
| 100 | + | 2 when Sys.argv.(1) = "start-api" -> |
| 101 | + start_locally ~lift handler |
| 102 | + | 3 when Sys.argv.(1) = "invoke" -> |
| 103 | + run_locally ~lift handler |
| 104 | + | _ -> |
| 105 | + failwith "Invalid command line arguments!" |
| 106 | + in |
| 107 | + Lwt_main.run p |
| 108 | + |
| 109 | + let lambda handler = |
| 110 | + start_lambda ~lift:Lwt.return handler |
| 111 | +end |
0 commit comments