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}