Skip to content

Commit f9d5295

Browse files
committed
adding custom port in cli opt-in
Signed-off-by: Aminu 'Seun Joshua <[email protected]>
1 parent 9bcec7b commit f9d5295

File tree

3 files changed

+47
-12
lines changed

3 files changed

+47
-12
lines changed

crates/trigger-http/src/lib.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ pub struct CliArgs {
5050
/// The path to the certificate key to use for https, if this is not set, normal http will be used. The key should be in PKCS#8 format
5151
#[clap(long, env = "SPIN_TLS_KEY", requires = "tls-cert")]
5252
pub tls_key: Option<PathBuf>,
53+
54+
/// The port to listen on
55+
#[clap(long = "port", env = "SPIN_HTTP_LISTEN_PORT")]
56+
pub port: Option<u16>,
5357
}
5458

5559
impl CliArgs {
@@ -73,6 +77,8 @@ pub struct HttpTrigger {
7377
/// If the port is set to 0, the actual address will be determined by the OS.
7478
listen_addr: SocketAddr,
7579
tls_config: Option<TlsConfig>,
80+
/// Optional port to listen on
81+
port: Option<u16>,
7682
}
7783

7884
impl<F: RuntimeFactors> Trigger<F> for HttpTrigger {
@@ -82,7 +88,8 @@ impl<F: RuntimeFactors> Trigger<F> for HttpTrigger {
8288
type InstanceState = ();
8389

8490
fn new(cli_args: Self::CliArgs, app: &spin_app::App) -> anyhow::Result<Self> {
85-
Self::new(app, cli_args.address, cli_args.into_tls_config())
91+
let port = cli_args.port;
92+
Self::new(app, cli_args.address, cli_args.into_tls_config(), port)
8693
}
8794

8895
async fn run(self, trigger_app: TriggerApp<F>) -> anyhow::Result<()> {
@@ -104,12 +111,14 @@ impl HttpTrigger {
104111
app: &spin_app::App,
105112
listen_addr: SocketAddr,
106113
tls_config: Option<TlsConfig>,
114+
port: Option<u16>,
107115
) -> anyhow::Result<Self> {
108116
Self::validate_app(app)?;
109117

110118
Ok(Self {
111119
listen_addr,
112120
tls_config,
121+
port,
113122
})
114123
}
115124

@@ -121,8 +130,9 @@ impl HttpTrigger {
121130
let Self {
122131
listen_addr,
123132
tls_config,
133+
port,
124134
} = self;
125-
let server = Arc::new(HttpServer::new(listen_addr, tls_config, trigger_app)?);
135+
let server = Arc::new(HttpServer::new(listen_addr, tls_config, port, trigger_app)?);
126136
Ok(server)
127137
}
128138

crates/trigger-http/src/server.rs

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
use std::{collections::HashMap, future::Future, io::IsTerminal, net::SocketAddr, sync::Arc};
1+
use std::{
2+
collections::HashMap,
3+
future::Future,
4+
io::{ErrorKind, IsTerminal},
5+
net::SocketAddr,
6+
sync::Arc,
7+
};
28

39
use anyhow::{bail, Context};
410
use http::{
@@ -47,6 +53,8 @@ pub struct HttpServer<F: RuntimeFactors> {
4753
listen_addr: SocketAddr,
4854
/// The TLS configuration for the server.
4955
tls_config: Option<TlsConfig>,
56+
/// Optional custom port the server is listening on.
57+
port: Option<u16>,
5058
/// Request router.
5159
router: Router,
5260
/// The app being triggered.
@@ -62,6 +70,7 @@ impl<F: RuntimeFactors> HttpServer<F> {
6270
pub fn new(
6371
listen_addr: SocketAddr,
6472
tls_config: Option<TlsConfig>,
73+
port: Option<u16>,
6574
trigger_app: TriggerApp<F>,
6675
) -> anyhow::Result<Self> {
6776
// This needs to be a vec before building the router to handle duplicate routes
@@ -129,6 +138,7 @@ impl<F: RuntimeFactors> HttpServer<F> {
129138
Ok(Self {
130139
listen_addr,
131140
tls_config,
141+
port,
132142
router,
133143
trigger_app,
134144
component_trigger_configs,
@@ -138,16 +148,31 @@ impl<F: RuntimeFactors> HttpServer<F> {
138148

139149
/// Serve incoming requests over the provided [`TcpListener`].
140150
pub async fn serve(self: Arc<Self>) -> anyhow::Result<()> {
141-
let listener = TcpListener::bind(self.listen_addr).await.with_context(|| {
142-
format!(
143-
"Unable to listen on {listen_addr}",
144-
listen_addr = self.listen_addr
145-
)
146-
})?;
151+
let listener: anyhow::Result<TcpListener> = match TcpListener::bind(self.listen_addr).await
152+
{
153+
Ok(listener) => Ok(listener),
154+
Err(err) => {
155+
if err.kind() == ErrorKind::AddrInUse {
156+
let mut addr = self.listen_addr;
157+
addr.set_port(self.port.unwrap_or(0));
158+
let listener = TcpListener::bind(addr).await.with_context(|| {
159+
format!(
160+
"Unable to listen on {listen_addr}",
161+
listen_addr = self.listen_addr
162+
)
163+
})?;
164+
165+
Ok(listener)
166+
} else {
167+
Err(anyhow::anyhow!("Unable to listen on {}", self.listen_addr))
168+
}
169+
}
170+
};
171+
147172
if let Some(tls_config) = self.tls_config.clone() {
148-
self.serve_https(listener, tls_config).await?;
173+
self.serve_https(listener?, tls_config).await?;
149174
} else {
150-
self.serve_http(listener).await?;
175+
self.serve_http(listener?).await?;
151176
}
152177
Ok(())
153178
}

tests/testing-framework/src/runtimes/in_process_spin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ async fn initialize_trigger(
104104
.await?;
105105

106106
let app = spin_app::App::new("my-app", locked_app);
107-
let trigger = HttpTrigger::new(&app, "127.0.0.1:80".parse().unwrap(), None)?;
107+
let trigger = HttpTrigger::new(&app, "127.0.0.1:80".parse().unwrap(), None, None)?;
108108
let mut builder = TriggerAppBuilder::<_, FactorsBuilder>::new(trigger);
109109
let trigger_app = builder
110110
.build(

0 commit comments

Comments
 (0)