aws_lambda_runtime_proxy/lib.rs
1mod client;
2mod server;
3
4use std::env;
5
6use anyhow::Result;
7use tokio::process::{Child, Command};
8
9pub use client::*;
10pub use server::*;
11
12/// This is the high level API for this crate,
13/// which will create a [`MockLambdaRuntimeApiServer`] and a handler process.
14///
15/// You can also use [`MockLambdaRuntimeApiServer`] and [`LambdaRuntimeApiClient`] directly.
16/// # Examples
17/// ```
18/// use aws_lambda_runtime_proxy::Proxy;
19///
20/// # async fn t1() {
21/// // create the proxy server and the handler process using the default configuration
22/// let proxy = Proxy::default().spawn().await.unwrap();
23/// // forward all requests to the real Lambda Runtime API
24/// proxy.server.passthrough().await;
25/// # }
26/// ```
27#[derive(Default)]
28pub struct Proxy {
29 /// See [`Self::port`].
30 pub port: Option<u16>,
31 /// See [`Self::command`].
32 pub command: Option<Command>,
33}
34
35impl Proxy {
36 /// Create the handler command from the `argv[1..]`.
37 /// For example if the command of the current process is `proxy node --help`
38 /// then the handler command will be `node --help`.
39 /// You can modify the handler command and pass it to [`Self::command`].
40 /// # Examples
41 /// ```
42 /// use aws_lambda_runtime_proxy::Proxy;
43 /// use std::process::Stdio;
44 ///
45 /// # async fn t1() {
46 /// // retrieve the default handler command
47 /// let mut command = Proxy::default_command().unwrap();
48 ///
49 /// // enhance the handler command
50 /// command
51 /// // override environment variables for the handler process
52 /// .env("KEY", "VALUE")
53 /// // pipe the stdout and stderr of the handler process
54 /// .stdout(Stdio::piped())
55 /// .stderr(Stdio::piped());
56 ///
57 /// Proxy::default()
58 /// .command(command)
59 /// .spawn()
60 /// .await;
61 /// # }
62 /// ```
63 pub fn default_command() -> Option<Command> {
64 let mut cmd = Command::new(env::args().nth(1)?);
65 cmd.args(env::args().skip(2));
66 cmd.into()
67 }
68
69 /// Set the port of the proxy server.
70 /// If not set, the port will be read from the environment variable `AWS_LAMBDA_RUNTIME_PROXY_PORT`,
71 /// or default to `3000`.
72 pub fn port(mut self, port: u16) -> Self {
73 self.port = Some(port);
74 self
75 }
76
77 /// Set the command of the handler process.
78 /// If not set, the command will be created using [`Self::default_command`].
79 pub fn command(mut self, cmd: Command) -> Self {
80 self.command = Some(cmd);
81 self
82 }
83
84 /// Spawn the proxy server and the handler process.
85 /// The handler process will be spawned with the environment variable `AWS_LAMBDA_RUNTIME_API`
86 /// set to the address of the proxy server.
87 pub async fn spawn(self) -> Result<RunningProxy> {
88 let port = self
89 .port
90 .or_else(|| {
91 env::var("AWS_LAMBDA_RUNTIME_PROXY_PORT")
92 .ok()
93 .and_then(|s| s.parse().ok())
94 })
95 .unwrap_or(3000);
96
97 let mut command = self
98 .command
99 .or_else(Self::default_command)
100 .ok_or_else(|| anyhow::anyhow!("Handler command is not set."))?;
101 command.env("AWS_LAMBDA_RUNTIME_API", format!("127.0.0.1:{}", port));
102
103 let server = MockLambdaRuntimeApiServer::bind(port).await?;
104
105 // server is ready, spawn the real handler process
106 let handler = command.spawn()?;
107
108 Ok(RunningProxy { server, handler })
109 }
110}
111
112/// Created by [`Proxy::spawn`].
113pub struct RunningProxy {
114 pub server: MockLambdaRuntimeApiServer,
115 /// The lambda handler process.
116 pub handler: Child,
117}