diff --git a/cli/tauri.js/src/helpers/tauri-config.ts b/cli/tauri.js/src/helpers/tauri-config.ts index 8931d4258..b2d038fcd 100644 --- a/cli/tauri.js/src/helpers/tauri-config.ts +++ b/cli/tauri.js/src/helpers/tauri-config.ts @@ -31,8 +31,7 @@ const getTauriConfig = (cfg: Partial): TauriConfig => { ctx: {}, tauri: { embeddedServer: { - active: true, - port: "3000" + active: true }, bundle: { active: true, diff --git a/cli/tauri.js/src/types/config.schema.json b/cli/tauri.js/src/types/config.schema.json index 78493e630..1e10dc788 100644 --- a/cli/tauri.js/src/types/config.schema.json +++ b/cli/tauri.js/src/types/config.schema.json @@ -401,8 +401,18 @@ "type": "boolean" }, "port": { - "description": "enable custom port, instead of using random port", - "type": "string" + "anyOf": [ + { + "enum": [ + "random" + ], + "type": "string" + }, + { + "type": "number" + } + ], + "description": "the embedded server port number or the 'random' string to generate one at runtime" } }, "type": "object" @@ -490,4 +500,4 @@ "tauri" ], "type": "object" -} +} \ No newline at end of file diff --git a/cli/tauri.js/src/types/config.ts b/cli/tauri.js/src/types/config.ts index 2369bc28a..98ac01062 100644 --- a/cli/tauri.js/src/types/config.ts +++ b/cli/tauri.js/src/types/config.ts @@ -223,7 +223,10 @@ export interface TauriConfig { * whether we should use the embedded-server or the no-server mode */ active?: boolean - port?: string + /** + * the embedded server port number or the 'random' string to generate one at runtime + */ + port?: number | 'random' | undefined } /** * tauri bundler configuration diff --git a/cli/tauri.js/src/types/config.validator.ts b/cli/tauri.js/src/types/config.validator.ts index 005c70a92..3b8b781bc 100644 --- a/cli/tauri.js/src/types/config.validator.ts +++ b/cli/tauri.js/src/types/config.validator.ts @@ -411,8 +411,18 @@ export const TauriConfigSchema = { "type": "boolean" }, "port": { - "description": "enable custom port, instead of using random port", - "type": "string" + "anyOf": [ + { + "enum": [ + "random" + ], + "type": "string" + }, + { + "type": "number" + } + ], + "description": "the embedded server port number or the 'random' string to generate one at runtime" } }, "type": "object" diff --git a/tauri-api/src/config.rs b/tauri-api/src/config.rs index 8ddadc0a0..fb2bf38d8 100644 --- a/tauri-api/src/config.rs +++ b/tauri-api/src/config.rs @@ -1,3 +1,4 @@ +use serde::de::{Deserializer, Error as DeError, Visitor}; use serde::Deserialize; use once_cell::sync::OnceCell; @@ -52,6 +53,15 @@ fn default_window() -> WindowConfig { } } +/// The embedded server port. +#[derive(PartialEq, Debug, Deserialize)] +pub enum Port { + /// Port with a numeric value. + Value(u16), + /// Random port. + Random, +} + /// The embeddedServer configuration object. #[derive(PartialEq, Deserialize, Debug)] #[serde(tag = "embeddedServer", rename_all = "camelCase")] @@ -61,16 +71,52 @@ pub struct EmbeddedServerConfig { pub host: String, /// The embedded server port. /// If it's `random`, we'll generate one at runtime. - #[serde(default = "default_port")] - pub port: String, + #[serde(default = "default_port", deserialize_with = "port_deserializer")] + pub port: Port, } fn default_host() -> String { "http://127.0.0.1".to_string() } -fn default_port() -> String { - "random".to_string() +fn port_deserializer<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + struct PortDeserializer; + + impl<'de> Visitor<'de> for PortDeserializer { + type Value = Port; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("a port number or the 'random' string") + } + + fn visit_str(self, value: &str) -> Result + where + E: DeError, + { + if value != "random" { + Err(DeError::custom( + "expected a 'random' string or a port number", + )) + } else { + Ok(Port::Random) + } + } + + fn visit_u64(self, value: u64) -> Result + where + E: DeError, + { + Ok(Port::Value(value as u16)) + } + } + + deserializer.deserialize_any(PortDeserializer {}) +} + +fn default_port() -> Port { + Port::Random } fn default_embedded_server() -> EmbeddedServerConfig { @@ -341,7 +387,7 @@ mod test { }, embedded_server: EmbeddedServerConfig { host: String::from("http://127.0.0.1"), - port: String::from("random"), + port: Port::Random, }, bundle: BundleConfig { identifier: String::from("com.tauri.communication"), @@ -437,7 +483,7 @@ mod test { }, embedded_server: EmbeddedServerConfig { host: String::from("http://127.0.0.1"), - port: String::from("random"), + port: Port::Random, }, bundle: BundleConfig { identifier: String::from(""), diff --git a/tauri/src/app/runner.rs b/tauri/src/app/runner.rs index e61a7e845..4773f47a4 100644 --- a/tauri/src/app/runner.rs +++ b/tauri/src/app/runner.rs @@ -103,19 +103,15 @@ fn setup_content() -> crate::Result> { #[cfg(embedded_server)] fn setup_port() -> crate::Result<(String, bool)> { let config = get()?; - if config.tauri.embedded_server.port == "random" { - match get_available_port() { + match config.tauri.embedded_server.port { + tauri_api::config::Port::Random => match get_available_port() { Some(available_port) => Ok((available_port.to_string(), true)), None => Ok(("0".to_string(), false)), + }, + tauri_api::config::Port::Value(port) => { + let port_valid = port_is_available(port); + Ok((port.to_string(), port_valid)) } - } else { - let port = &config.tauri.embedded_server.port; - let port_valid = port_is_available( - port - .parse::() - .unwrap_or_else(|_| panic!("Invalid port {}", port)), - ); - Ok((port.to_string(), port_valid)) } }