From bb859fc181a3394cbd252f1209b3cd7eacb77314 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 5 Feb 2024 20:13:02 +0700 Subject: [PATCH 01/15] feat: get server for openapi doc --- catalyst-gateway/Cargo.lock | 55 +++++++++++++++++++++ catalyst-gateway/Cargo.toml | 3 ++ catalyst-gateway/bin/Cargo.toml | 4 +- catalyst-gateway/bin/src/service/api/mod.rs | 26 ++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/catalyst-gateway/Cargo.lock b/catalyst-gateway/Cargo.lock index 9d1de423ca4..d01161ac9d1 100644 --- a/catalyst-gateway/Cargo.lock +++ b/catalyst-gateway/Cargo.lock @@ -395,7 +395,9 @@ dependencies = [ "cpu-time", "cryptoxide", "dotenvy", + "gethostname", "lazy_static", + "local-ip-address", "panic-message", "poem", "poem-extensions", @@ -668,6 +670,12 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -818,6 +826,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -1213,6 +1231,18 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +[[package]] +name = "local-ip-address" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612ed4ea9ce5acfb5d26339302528a5e1e59dfed95e9e11af3c083236ff1d15d" +dependencies = [ + "libc", + "neli", + "thiserror", + "windows-sys", +] + [[package]] name = "lock_api" version = "0.4.11" @@ -1300,6 +1330,31 @@ dependencies = [ "version_check", ] +[[package]] +name = "neli" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43" +dependencies = [ + "byteorder", + "libc", + "log", + "neli-proc-macros", +] + +[[package]] +name = "neli-proc-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + [[package]] name = "nix" version = "0.27.1" diff --git a/catalyst-gateway/Cargo.toml b/catalyst-gateway/Cargo.toml index 35fad6f767f..b9c1a1da68c 100644 --- a/catalyst-gateway/Cargo.toml +++ b/catalyst-gateway/Cargo.toml @@ -57,6 +57,9 @@ tokio = "1" dotenvy = "0.15" +local-ip-address = "0.5.7" +gethostname = "0.4.3" + [workspace.lints.rust] warnings = "deny" missing_docs = "deny" diff --git a/catalyst-gateway/bin/Cargo.toml b/catalyst-gateway/bin/Cargo.toml index 800d6302651..c91dee5cab3 100644 --- a/catalyst-gateway/bin/Cargo.toml +++ b/catalyst-gateway/bin/Cargo.toml @@ -67,4 +67,6 @@ dotenvy = { workspace = true } panic-message = { workspace = true } cpu-time = { workspace = true } ulid = { workspace = true, features = ["serde", "uuid"] } -rust-embed = { workspace = true } \ No newline at end of file +rust-embed = { workspace = true } +local-ip-address.workspace = true +gethostname.workspace = true diff --git a/catalyst-gateway/bin/src/service/api/mod.rs b/catalyst-gateway/bin/src/service/api/mod.rs index 8eafc46b557..5ccf99e1059 100644 --- a/catalyst-gateway/bin/src/service/api/mod.rs +++ b/catalyst-gateway/bin/src/service/api/mod.rs @@ -2,7 +2,11 @@ //! //! This defines all endpoints for the Catalyst Gateway API. //! It however does NOT contain any processing for them, that is defined elsewhere. +use std::net::IpAddr; + +use gethostname::gethostname; use health::HealthApi; +use local_ip_address::list_afinet_netifas; use poem_openapi::{ContactObject, LicenseObject, OpenApiService, ServerObject}; use registration::RegistrationApi; use test_endpoints::TestApi; @@ -23,6 +27,9 @@ const API_TITLE: &str = "Catalyst Gateway"; /// The version of the API const API_VERSION: &str = "1.2.0"; +/// Port +const PORT: &str = "5432"; + /// Get the contact details for inquiring about the API fn get_api_contact() -> ContactObject { ContactObject::new() @@ -75,5 +82,24 @@ pub(crate) fn mk_api( service = service.server(ServerObject::new(host)); } + // Get local hostname + if let Ok(hostname) = gethostname().into_string() { + let hostname_with_port = format!("{}:{}", hostname, PORT); + service = service.server(ServerObject::new(hostname_with_port)); + } + + // Get local IP address v4 and v6 + let network_interfaces = list_afinet_netifas(); + if let Ok(network_interfaces) = network_interfaces { + for (name, ip) in network_interfaces.iter() { + if *name == "en0" { + let ip_with_port = match ip { + IpAddr::V4(_) => format!("{}:{}", ip, PORT), + IpAddr::V6(_) => format!("[{}]:{}", ip, PORT), + }; + service = service.server(ServerObject::new(ip_with_port)); + } + } + } service } From 08ccc826ff8b8354fe8dd92f826b9e223eb758ca Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 5 Feb 2024 20:43:12 +0700 Subject: [PATCH 02/15] fix: add description --- catalyst-gateway/bin/src/service/api/mod.rs | 23 ++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/catalyst-gateway/bin/src/service/api/mod.rs b/catalyst-gateway/bin/src/service/api/mod.rs index 5ccf99e1059..95468ff6622 100644 --- a/catalyst-gateway/bin/src/service/api/mod.rs +++ b/catalyst-gateway/bin/src/service/api/mod.rs @@ -21,6 +21,8 @@ mod test_endpoints; mod v0; mod v1; +// cspell: words gethostname afinet netifas + /// The name of the API const API_TITLE: &str = "Catalyst Gateway"; @@ -79,13 +81,14 @@ pub(crate) fn mk_api( // Add all the hosts where this API should be reachable. for host in hosts { - service = service.server(ServerObject::new(host)); + service = service.server(ServerObject::new(host).description("API Host")); } - // Get local hostname + // Get localhost name if let Ok(hostname) = gethostname().into_string() { let hostname_with_port = format!("{}:{}", hostname, PORT); - service = service.server(ServerObject::new(hostname_with_port)); + service = + service.server(ServerObject::new(hostname_with_port).description("Server at localhost name")); } // Get local IP address v4 and v6 @@ -93,11 +96,17 @@ pub(crate) fn mk_api( if let Ok(network_interfaces) = network_interfaces { for (name, ip) in network_interfaces.iter() { if *name == "en0" { - let ip_with_port = match ip { - IpAddr::V4(_) => format!("{}:{}", ip, PORT), - IpAddr::V6(_) => format!("[{}]:{}", ip, PORT), + let (ip_with_port, desc) = match ip { + IpAddr::V4(_) => { + let ip_str = format!("{}:{}", ip, PORT); + (ip_str, "Server at local IPv4 address") + }, + IpAddr::V6(_) => { + let ip_str = format!("[{}]:{}", ip, PORT); + (ip_str, "Server at local IPv6 address") + }, }; - service = service.server(ServerObject::new(ip_with_port)); + service = service.server(ServerObject::new(ip_with_port).description(desc)); } } } From 3626fe56408a6dea4014f09df16ee39848b63161 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 5 Feb 2024 20:51:24 +0700 Subject: [PATCH 03/15] fix: spelling and format --- .config/dictionaries/project.dic | 5 ++++- catalyst-gateway/bin/src/service/api/mod.rs | 6 ++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.config/dictionaries/project.dic b/.config/dictionaries/project.dic index a9d7135f4b4..d0045f0b558 100644 --- a/.config/dictionaries/project.dic +++ b/.config/dictionaries/project.dic @@ -120,4 +120,7 @@ nextest testcov testdocs fmtchk -fmtfix \ No newline at end of file +fmtfix +gethostname +afinet +netifas \ No newline at end of file diff --git a/catalyst-gateway/bin/src/service/api/mod.rs b/catalyst-gateway/bin/src/service/api/mod.rs index 95468ff6622..768bd2424aa 100644 --- a/catalyst-gateway/bin/src/service/api/mod.rs +++ b/catalyst-gateway/bin/src/service/api/mod.rs @@ -21,8 +21,6 @@ mod test_endpoints; mod v0; mod v1; -// cspell: words gethostname afinet netifas - /// The name of the API const API_TITLE: &str = "Catalyst Gateway"; @@ -87,8 +85,8 @@ pub(crate) fn mk_api( // Get localhost name if let Ok(hostname) = gethostname().into_string() { let hostname_with_port = format!("{}:{}", hostname, PORT); - service = - service.server(ServerObject::new(hostname_with_port).description("Server at localhost name")); + service = service + .server(ServerObject::new(hostname_with_port).description("Server at localhost name")); } // Get local IP address v4 and v6 From 3e383ffd71cbe1cdd60d52b811b377db98cb7e7a Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 5 Feb 2024 21:01:00 +0700 Subject: [PATCH 04/15] fix: cargo lint --- catalyst-gateway/bin/src/service/api/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/catalyst-gateway/bin/src/service/api/mod.rs b/catalyst-gateway/bin/src/service/api/mod.rs index 768bd2424aa..50756db17c7 100644 --- a/catalyst-gateway/bin/src/service/api/mod.rs +++ b/catalyst-gateway/bin/src/service/api/mod.rs @@ -84,7 +84,7 @@ pub(crate) fn mk_api( // Get localhost name if let Ok(hostname) = gethostname().into_string() { - let hostname_with_port = format!("{}:{}", hostname, PORT); + let hostname_with_port = format!("{hostname}:{PORT}"); service = service .server(ServerObject::new(hostname_with_port).description("Server at localhost name")); } @@ -92,15 +92,15 @@ pub(crate) fn mk_api( // Get local IP address v4 and v6 let network_interfaces = list_afinet_netifas(); if let Ok(network_interfaces) = network_interfaces { - for (name, ip) in network_interfaces.iter() { + for (name, ip) in &network_interfaces { if *name == "en0" { let (ip_with_port, desc) = match ip { IpAddr::V4(_) => { - let ip_str = format!("{}:{}", ip, PORT); + let ip_str = format!("{ip}:{PORT}"); (ip_str, "Server at local IPv4 address") }, IpAddr::V6(_) => { - let ip_str = format!("[{}]:{}", ip, PORT); + let ip_str = format!("[{ip}]:{PORT}"); (ip_str, "Server at local IPv6 address") }, }; From e6e305c47cf04cec889ca5e3fda9f6ac8f856ae4 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 6 Feb 2024 13:04:13 +0700 Subject: [PATCH 05/15] fix: syntax --- catalyst-gateway/bin/src/service/api/mod.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/catalyst-gateway/bin/src/service/api/mod.rs b/catalyst-gateway/bin/src/service/api/mod.rs index 50756db17c7..80b90fdae64 100644 --- a/catalyst-gateway/bin/src/service/api/mod.rs +++ b/catalyst-gateway/bin/src/service/api/mod.rs @@ -90,19 +90,12 @@ pub(crate) fn mk_api( } // Get local IP address v4 and v6 - let network_interfaces = list_afinet_netifas(); - if let Ok(network_interfaces) = network_interfaces { + if let Ok(network_interfaces) = list_afinet_netifas() { for (name, ip) in &network_interfaces { if *name == "en0" { let (ip_with_port, desc) = match ip { - IpAddr::V4(_) => { - let ip_str = format!("{ip}:{PORT}"); - (ip_str, "Server at local IPv4 address") - }, - IpAddr::V6(_) => { - let ip_str = format!("[{ip}]:{PORT}"); - (ip_str, "Server at local IPv6 address") - }, + IpAddr::V4(_) => (format!("{ip}:{PORT}"), "Server at local IPv4 address"), + IpAddr::V6(_) => (format!("[{ip}]:{PORT}"), "Server at local IPv6 address"), }; service = service.server(ServerObject::new(ip_with_port).description(desc)); } From 8c7d47da1cfe2967bd68023e9212d0cc3bc4218d Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 7 Feb 2024 10:31:20 +0700 Subject: [PATCH 06/15] fix: remove hardcode port and get from socket addr --- catalyst-gateway/bin/src/cli.rs | 2 +- catalyst-gateway/bin/src/service/api/mod.rs | 16 ++++++++-------- catalyst-gateway/bin/src/service/poem_service.rs | 10 +++++----- catalyst-gateway/bin/src/settings.rs | 4 ++++ 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/catalyst-gateway/bin/src/cli.rs b/catalyst-gateway/bin/src/cli.rs index 49ca9d062d6..cac2d391acb 100644 --- a/catalyst-gateway/bin/src/cli.rs +++ b/catalyst-gateway/bin/src/cli.rs @@ -53,7 +53,7 @@ impl Cli { Ok(()) }, Self::Docs(settings) => { - let docs = service::get_app_docs(); + let docs = service::get_app_docs(&settings.service_settings.address); match settings.output { Some(path) => { let mut docs_file = std::fs::File::create(path)?; diff --git a/catalyst-gateway/bin/src/service/api/mod.rs b/catalyst-gateway/bin/src/service/api/mod.rs index 80b90fdae64..2353b044f0a 100644 --- a/catalyst-gateway/bin/src/service/api/mod.rs +++ b/catalyst-gateway/bin/src/service/api/mod.rs @@ -2,7 +2,7 @@ //! //! This defines all endpoints for the Catalyst Gateway API. //! It however does NOT contain any processing for them, that is defined elsewhere. -use std::net::IpAddr; +use std::net::{IpAddr, SocketAddr}; use gethostname::gethostname; use health::HealthApi; @@ -27,9 +27,6 @@ const API_TITLE: &str = "Catalyst Gateway"; /// The version of the API const API_VERSION: &str = "1.2.0"; -/// Port -const PORT: &str = "5432"; - /// Get the contact details for inquiring about the API fn get_api_contact() -> ContactObject { ContactObject::new() @@ -64,7 +61,7 @@ const TERMS_OF_SERVICE: &str = /// Create the `OpenAPI` definition pub(crate) fn mk_api( - hosts: Vec, + hosts: Vec, socket_addr: &SocketAddr, ) -> OpenApiService<(TestApi, HealthApi, RegistrationApi, V0Api, V1Api), ()> { let mut service = OpenApiService::new( (TestApi, HealthApi, RegistrationApi, V0Api, V1Api), @@ -77,6 +74,9 @@ pub(crate) fn mk_api( .terms_of_service(TERMS_OF_SERVICE) .url_prefix(API_URL_PREFIX.as_str()); + // Retrieve the port from the socket address + let port = socket_addr.port().to_string(); + // Add all the hosts where this API should be reachable. for host in hosts { service = service.server(ServerObject::new(host).description("API Host")); @@ -84,7 +84,7 @@ pub(crate) fn mk_api( // Get localhost name if let Ok(hostname) = gethostname().into_string() { - let hostname_with_port = format!("{hostname}:{PORT}"); + let hostname_with_port = format!("{hostname}:{port}"); service = service .server(ServerObject::new(hostname_with_port).description("Server at localhost name")); } @@ -94,8 +94,8 @@ pub(crate) fn mk_api( for (name, ip) in &network_interfaces { if *name == "en0" { let (ip_with_port, desc) = match ip { - IpAddr::V4(_) => (format!("{ip}:{PORT}"), "Server at local IPv4 address"), - IpAddr::V6(_) => (format!("[{ip}]:{PORT}"), "Server at local IPv6 address"), + IpAddr::V4(_) => (format!("{ip}:{port}"), "Server at local IPv4 address"), + IpAddr::V6(_) => (format!("[{ip}]:{port}"), "Server at local IPv6 address"), }; service = service.server(ServerObject::new(ip_with_port).description(desc)); } diff --git a/catalyst-gateway/bin/src/service/poem_service.rs b/catalyst-gateway/bin/src/service/poem_service.rs index 4426f9954c6..948034126a6 100644 --- a/catalyst-gateway/bin/src/service/poem_service.rs +++ b/catalyst-gateway/bin/src/service/poem_service.rs @@ -27,14 +27,14 @@ use crate::{ }; /// This exists to allow us to add extra routes to the service for testing purposes. -fn mk_app(hosts: Vec, base_route: Option, state: &Arc) -> impl Endpoint { +fn mk_app(hosts: Vec, base_route: Option, state: &Arc, socket_addr: &SocketAddr) -> impl Endpoint { // Get the base route if defined, or a new route if not. let base_route = match base_route { Some(route) => route, None => Route::new(), }; - let api_service = mk_api(hosts); + let api_service = mk_api(hosts, socket_addr); let docs = docs(&api_service); let prometheus_registry = init_prometheus(); @@ -52,8 +52,8 @@ fn mk_app(hosts: Vec, base_route: Option, state: &Arc) -> } /// Get the API docs as a string in the JSON format. -pub(crate) fn get_app_docs() -> String { - let api_service = mk_api(vec![]); +pub(crate) fn get_app_docs(socket_addr: &SocketAddr) -> String { + let api_service = mk_api(vec![], socket_addr); api_service.spec() } @@ -82,7 +82,7 @@ pub(crate) async fn run(addr: &SocketAddr, state: Arc) -> Result<(), Erro let hosts = get_api_host_names(addr); - let app = mk_app(hosts, None, &state); + let app = mk_app(hosts, None, &state, addr); poem::Server::new(TcpListener::bind(addr)) .run(app) diff --git a/catalyst-gateway/bin/src/settings.rs b/catalyst-gateway/bin/src/settings.rs index a53c365741e..8df6d346cf5 100644 --- a/catalyst-gateway/bin/src/settings.rs +++ b/catalyst-gateway/bin/src/settings.rs @@ -61,6 +61,10 @@ pub(crate) struct ServiceSettings { pub(crate) struct DocsSettings { /// The output path to the generated docs file, if omitted prints to stdout. pub(crate) output: Option, + + /// Service settings + #[clap(flatten)] + pub(crate) service_settings: ServiceSettings, } /// An environment variable read as a string. From 1354d61f5359fe3ba5cb3b387cda9259245ac492 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 7 Feb 2024 10:54:49 +0700 Subject: [PATCH 07/15] fix: format --- catalyst-gateway/bin/src/service/api/mod.rs | 2 +- catalyst-gateway/bin/src/service/poem_service.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/catalyst-gateway/bin/src/service/api/mod.rs b/catalyst-gateway/bin/src/service/api/mod.rs index 2353b044f0a..0a3537a5595 100644 --- a/catalyst-gateway/bin/src/service/api/mod.rs +++ b/catalyst-gateway/bin/src/service/api/mod.rs @@ -76,7 +76,7 @@ pub(crate) fn mk_api( // Retrieve the port from the socket address let port = socket_addr.port().to_string(); - + // Add all the hosts where this API should be reachable. for host in hosts { service = service.server(ServerObject::new(host).description("API Host")); diff --git a/catalyst-gateway/bin/src/service/poem_service.rs b/catalyst-gateway/bin/src/service/poem_service.rs index 948034126a6..29ed6df8059 100644 --- a/catalyst-gateway/bin/src/service/poem_service.rs +++ b/catalyst-gateway/bin/src/service/poem_service.rs @@ -27,7 +27,9 @@ use crate::{ }; /// This exists to allow us to add extra routes to the service for testing purposes. -fn mk_app(hosts: Vec, base_route: Option, state: &Arc, socket_addr: &SocketAddr) -> impl Endpoint { +fn mk_app( + hosts: Vec, base_route: Option, state: &Arc, socket_addr: &SocketAddr, +) -> impl Endpoint { // Get the base route if defined, or a new route if not. let base_route = match base_route { Some(route) => route, From 97220e26ae6260c75d64e5d7151f0319e7e4c725 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 7 Feb 2024 13:51:58 +0700 Subject: [PATCH 08/15] fix: docs setting use only socket addr --- catalyst-gateway/bin/src/cli.rs | 2 +- catalyst-gateway/bin/src/settings.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/catalyst-gateway/bin/src/cli.rs b/catalyst-gateway/bin/src/cli.rs index cac2d391acb..cd57d2967f6 100644 --- a/catalyst-gateway/bin/src/cli.rs +++ b/catalyst-gateway/bin/src/cli.rs @@ -53,7 +53,7 @@ impl Cli { Ok(()) }, Self::Docs(settings) => { - let docs = service::get_app_docs(&settings.service_settings.address); + let docs = service::get_app_docs(&settings.address); match settings.output { Some(path) => { let mut docs_file = std::fs::File::create(path)?; diff --git a/catalyst-gateway/bin/src/settings.rs b/catalyst-gateway/bin/src/settings.rs index 8df6d346cf5..8ac357d402a 100644 --- a/catalyst-gateway/bin/src/settings.rs +++ b/catalyst-gateway/bin/src/settings.rs @@ -62,9 +62,9 @@ pub(crate) struct DocsSettings { /// The output path to the generated docs file, if omitted prints to stdout. pub(crate) output: Option, - /// Service settings - #[clap(flatten)] - pub(crate) service_settings: ServiceSettings, + /// Server binding address + #[clap(long, default_value = ADDRESS_DEFAULT)] + pub(crate) address: SocketAddr, } /// An environment variable read as a string. From ae1170c0b0a8fbea52480dc2597a1a897f2761fe Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 7 Feb 2024 15:29:59 +0700 Subject: [PATCH 09/15] fix: extract common setting and add flag + env var --- catalyst-gateway/bin/src/settings.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/catalyst-gateway/bin/src/settings.rs b/catalyst-gateway/bin/src/settings.rs index 8ac357d402a..194a3710468 100644 --- a/catalyst-gateway/bin/src/settings.rs +++ b/catalyst-gateway/bin/src/settings.rs @@ -43,10 +43,6 @@ const API_URL_PREFIX_DEFAULT: &str = "/api"; /// and the logging level. #[derive(Args, Clone)] pub(crate) struct ServiceSettings { - /// Server binding address - #[clap(long, default_value = ADDRESS_DEFAULT)] - pub(crate) address: SocketAddr, - /// Url to the postgres event db #[clap(long, env)] pub(crate) database_url: String, @@ -54,6 +50,9 @@ pub(crate) struct ServiceSettings { /// Logging level #[clap(long, default_value = LOG_LEVEL_DEFAULT)] pub(crate) log_level: LogLevel, + + #[clap(flatten)] + pub(crate) common_settings: CommonSettings, } /// Settings specifies `OpenAPI` docs generation. @@ -62,9 +61,28 @@ pub(crate) struct DocsSettings { /// The output path to the generated docs file, if omitted prints to stdout. pub(crate) output: Option, + #[clap(flatten)] + pub(crate) common_settings: CommonSettings, +} + +/// Common settings for the application and OpenAPI docs generation. +#[derive(Args, Clone)] +pub(crate) struct CommonSettings { /// Server binding address #[clap(long, default_value = ADDRESS_DEFAULT)] pub(crate) address: SocketAddr, + + /// Flag for adding "http" to servers + #[clap(long, default_value = "false")] + pub(crate) http_auto_servers: bool, + + /// Flag for adding "https" to servers + #[clap(long, default_value = "true")] + pub(crate) https_auto_servers: bool, + + /// Server name + #[clap(env = "SERVER_NAME")] + pub(crate) server_name: Option, } /// An environment variable read as a string. From 5c5025c37665bca7ff6da37127201ad827e25dc0 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 7 Feb 2024 15:30:57 +0700 Subject: [PATCH 10/15] fix: add http(s) prefix and server name --- catalyst-gateway/bin/src/service/api/mod.rs | 52 +++++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/catalyst-gateway/bin/src/service/api/mod.rs b/catalyst-gateway/bin/src/service/api/mod.rs index 0a3537a5595..ca9427c7e42 100644 --- a/catalyst-gateway/bin/src/service/api/mod.rs +++ b/catalyst-gateway/bin/src/service/api/mod.rs @@ -2,7 +2,7 @@ //! //! This defines all endpoints for the Catalyst Gateway API. //! It however does NOT contain any processing for them, that is defined elsewhere. -use std::net::{IpAddr, SocketAddr}; +use std::net::IpAddr; use gethostname::gethostname; use health::HealthApi; @@ -13,7 +13,7 @@ use test_endpoints::TestApi; use v0::V0Api; use v1::V1Api; -use crate::settings::API_URL_PREFIX; +use crate::settings::{CommonSettings, API_URL_PREFIX}; mod health; mod registration; @@ -61,7 +61,7 @@ const TERMS_OF_SERVICE: &str = /// Create the `OpenAPI` definition pub(crate) fn mk_api( - hosts: Vec, socket_addr: &SocketAddr, + hosts: Vec, settings: &CommonSettings, ) -> OpenApiService<(TestApi, HealthApi, RegistrationApi, V0Api, V1Api), ()> { let mut service = OpenApiService::new( (TestApi, HealthApi, RegistrationApi, V0Api, V1Api), @@ -75,18 +75,34 @@ pub(crate) fn mk_api( .url_prefix(API_URL_PREFIX.as_str()); // Retrieve the port from the socket address - let port = socket_addr.port().to_string(); + let port = settings.address.port().to_string(); + + let is_http_auto_servers = settings.http_auto_servers; + let is_https_auto_servers = settings.https_auto_servers; + + let server_name = &settings.server_name; - // Add all the hosts where this API should be reachable. for host in hosts { service = service.server(ServerObject::new(host).description("API Host")); } + // Add server name if it is set + if let Some(name) = server_name { + service = service.server(ServerObject::new(name).description("Server at server name")); + } + // Get localhost name if let Ok(hostname) = gethostname().into_string() { - let hostname_with_port = format!("{hostname}:{port}"); - service = service - .server(ServerObject::new(hostname_with_port).description("Server at localhost name")); + let hostname_addresses = add_protocol_prefix( + &format!("{hostname}:{port}"), + is_http_auto_servers, + is_https_auto_servers, + ); + for hostname_address in hostname_addresses { + service = service.server( + ServerObject::new(hostname_address).description("Server at localhost name"), + ); + } } // Get local IP address v4 and v6 @@ -97,9 +113,27 @@ pub(crate) fn mk_api( IpAddr::V4(_) => (format!("{ip}:{port}"), "Server at local IPv4 address"), IpAddr::V6(_) => (format!("[{ip}]:{port}"), "Server at local IPv6 address"), }; - service = service.server(ServerObject::new(ip_with_port).description(desc)); + let ip_addresses = + add_protocol_prefix(&ip_with_port, is_http_auto_servers, is_https_auto_servers); + for address in ip_addresses { + service = service.server(ServerObject::new(address).description(desc)); + } } } } service } + +// Function to add protocol prefix based on flags +fn add_protocol_prefix( + address: &String, is_http_auto_servers: bool, is_https_auto_servers: bool, +) -> Vec { + let mut addresses = Vec::new(); + if is_http_auto_servers { + addresses.push(format!("http://{}", address)); + } + if is_https_auto_servers { + addresses.push(format!("https://{}", address)); + } + addresses +} From ede275e882ebc5bf51a78ec9d8f15d516273aad8 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 7 Feb 2024 15:31:16 +0700 Subject: [PATCH 11/15] fix: parameter needed for function --- catalyst-gateway/bin/src/cli.rs | 4 ++-- catalyst-gateway/bin/src/service/mod.rs | 10 ++++----- .../bin/src/service/poem_service.rs | 22 ++++++++++--------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/catalyst-gateway/bin/src/cli.rs b/catalyst-gateway/bin/src/cli.rs index cd57d2967f6..a9b08845978 100644 --- a/catalyst-gateway/bin/src/cli.rs +++ b/catalyst-gateway/bin/src/cli.rs @@ -49,11 +49,11 @@ impl Cli { logger::init(settings.log_level)?; let state = Arc::new(State::new(Some(settings.database_url)).await?); - service::run(&settings.address, state).await?; + service::run(&settings.common_settings, state).await?; Ok(()) }, Self::Docs(settings) => { - let docs = service::get_app_docs(&settings.address); + let docs = service::get_app_docs(&settings.common_settings); match settings.output { Some(path) => { let mut docs_file = std::fs::File::create(path)?; diff --git a/catalyst-gateway/bin/src/service/mod.rs b/catalyst-gateway/bin/src/service/mod.rs index 6e49be2fde6..edbc7ba771c 100644 --- a/catalyst-gateway/bin/src/service/mod.rs +++ b/catalyst-gateway/bin/src/service/mod.rs @@ -1,7 +1,7 @@ //! Main entrypoint to the service -use std::{net::SocketAddr, sync::Arc}; +use std::sync::Arc; -use crate::state::State; +use crate::{settings::CommonSettings, state::State}; // These Modules contain endpoints mod api; @@ -34,7 +34,7 @@ pub(crate) enum Error { /// /// ## Arguments /// -/// `service_addr`: &`SocketAddr` - the address to listen on +/// `settings`: &`CommonSettings` - common setting for the application and docs. /// `state`: `Arc` - the state /// /// ## Errors @@ -42,6 +42,6 @@ pub(crate) enum Error { /// `Error::CannotRunService` - cannot run the service /// `Error::EventDbError` - cannot connect to the event db /// `Error::IoError` - An IO error has occurred. -pub(crate) async fn run(service_addr: &SocketAddr, state: Arc) -> Result<(), Error> { - poem_service::run(service_addr, state).await +pub(crate) async fn run(settings: &CommonSettings, state: Arc) -> Result<(), Error> { + poem_service::run(settings, state).await } diff --git a/catalyst-gateway/bin/src/service/poem_service.rs b/catalyst-gateway/bin/src/service/poem_service.rs index 29ed6df8059..55c1a3ef8eb 100644 --- a/catalyst-gateway/bin/src/service/poem_service.rs +++ b/catalyst-gateway/bin/src/service/poem_service.rs @@ -2,7 +2,7 @@ //! //! This provides only the primary entrypoint to the service. -use std::{net::SocketAddr, sync::Arc}; +use std::sync::Arc; use poem::{ endpoint::PrometheusExporter, @@ -22,13 +22,13 @@ use crate::{ }, Error, }, - settings::{get_api_host_names, API_URL_PREFIX}, + settings::{get_api_host_names, CommonSettings, API_URL_PREFIX}, state::State, }; /// This exists to allow us to add extra routes to the service for testing purposes. fn mk_app( - hosts: Vec, base_route: Option, state: &Arc, socket_addr: &SocketAddr, + hosts: Vec, base_route: Option, state: &Arc, settings: &CommonSettings, ) -> impl Endpoint { // Get the base route if defined, or a new route if not. let base_route = match base_route { @@ -36,7 +36,7 @@ fn mk_app( None => Route::new(), }; - let api_service = mk_api(hosts, socket_addr); + let api_service = mk_api(hosts, settings); let docs = docs(&api_service); let prometheus_registry = init_prometheus(); @@ -54,8 +54,8 @@ fn mk_app( } /// Get the API docs as a string in the JSON format. -pub(crate) fn get_app_docs(socket_addr: &SocketAddr) -> String { - let api_service = mk_api(vec![], socket_addr); +pub(crate) fn get_app_docs(setting: &CommonSettings) -> String { + let api_service = mk_api(vec![], setting); api_service.spec() } @@ -65,14 +65,16 @@ pub(crate) fn get_app_docs(socket_addr: &SocketAddr) -> String { /// /// # Arguments /// -/// *`addr`: &`SocketAddr` - the address to listen on +/// *`settings`: &`CommonSettings` - common setting for the application and docs. /// /// # Errors /// /// * `Error::CannotRunService` - cannot run the service /// * `Error::EventDbError` - cannot connect to the event db /// * `Error::IoError` - An IO error has occurred. -pub(crate) async fn run(addr: &SocketAddr, state: Arc) -> Result<(), Error> { +pub(crate) async fn run(settings: &CommonSettings, state: Arc) -> Result<(), Error> { + // The address to listen on + let addr = settings.address; tracing::info!("Starting Poem Service ..."); tracing::info!("Listening on {addr}"); @@ -82,9 +84,9 @@ pub(crate) async fn run(addr: &SocketAddr, state: Arc) -> Result<(), Erro // help find them in the logs if they happen in production. set_panic_hook(); - let hosts = get_api_host_names(addr); + let hosts = get_api_host_names(&addr); - let app = mk_app(hosts, None, &state, addr); + let app = mk_app(hosts, None, &state, settings); poem::Server::new(TcpListener::bind(addr)) .run(app) From 18c4515bf5ceb0fa7c974ea2778bb0508a40d15c Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 7 Feb 2024 15:44:40 +0700 Subject: [PATCH 12/15] fix: linter --- catalyst-gateway/bin/src/service/api/mod.rs | 23 ++++++++------------- catalyst-gateway/bin/src/settings.rs | 4 +++- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/catalyst-gateway/bin/src/service/api/mod.rs b/catalyst-gateway/bin/src/service/api/mod.rs index ca9427c7e42..07fc4a98ef5 100644 --- a/catalyst-gateway/bin/src/service/api/mod.rs +++ b/catalyst-gateway/bin/src/service/api/mod.rs @@ -77,9 +77,6 @@ pub(crate) fn mk_api( // Retrieve the port from the socket address let port = settings.address.port().to_string(); - let is_http_auto_servers = settings.http_auto_servers; - let is_https_auto_servers = settings.https_auto_servers; - let server_name = &settings.server_name; for host in hosts { @@ -95,8 +92,8 @@ pub(crate) fn mk_api( if let Ok(hostname) = gethostname().into_string() { let hostname_addresses = add_protocol_prefix( &format!("{hostname}:{port}"), - is_http_auto_servers, - is_https_auto_servers, + settings.http_auto_servers, + settings.https_auto_servers, ); for hostname_address in hostname_addresses { service = service.server( @@ -114,7 +111,7 @@ pub(crate) fn mk_api( IpAddr::V6(_) => (format!("[{ip}]:{port}"), "Server at local IPv6 address"), }; let ip_addresses = - add_protocol_prefix(&ip_with_port, is_http_auto_servers, is_https_auto_servers); + add_protocol_prefix(&ip_with_port, settings.http_auto_servers, settings.https_auto_servers); for address in ip_addresses { service = service.server(ServerObject::new(address).description(desc)); } @@ -124,16 +121,14 @@ pub(crate) fn mk_api( service } -// Function to add protocol prefix based on flags -fn add_protocol_prefix( - address: &String, is_http_auto_servers: bool, is_https_auto_servers: bool, -) -> Vec { +/// Function to add protocol prefix based on flags. +fn add_protocol_prefix(address: &String, is_http: bool, is_https: bool) -> Vec { let mut addresses = Vec::new(); - if is_http_auto_servers { - addresses.push(format!("http://{}", address)); + if is_http { + addresses.push(format!("http://{address}")); } - if is_https_auto_servers { - addresses.push(format!("https://{}", address)); + if is_https { + addresses.push(format!("https://{address}")); } addresses } diff --git a/catalyst-gateway/bin/src/settings.rs b/catalyst-gateway/bin/src/settings.rs index 194a3710468..34c219308a3 100644 --- a/catalyst-gateway/bin/src/settings.rs +++ b/catalyst-gateway/bin/src/settings.rs @@ -51,6 +51,7 @@ pub(crate) struct ServiceSettings { #[clap(long, default_value = LOG_LEVEL_DEFAULT)] pub(crate) log_level: LogLevel, + /// Common settings. #[clap(flatten)] pub(crate) common_settings: CommonSettings, } @@ -62,10 +63,11 @@ pub(crate) struct DocsSettings { pub(crate) output: Option, #[clap(flatten)] + /// Common settings. pub(crate) common_settings: CommonSettings, } -/// Common settings for the application and OpenAPI docs generation. +/// Common settings for the application and `OpenAPI` docs generation. #[derive(Args, Clone)] pub(crate) struct CommonSettings { /// Server binding address From 0fdea2229388feb45b921131c9996d82c0617309 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 7 Feb 2024 15:47:07 +0700 Subject: [PATCH 13/15] fix: linter --- catalyst-gateway/bin/src/service/api/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/catalyst-gateway/bin/src/service/api/mod.rs b/catalyst-gateway/bin/src/service/api/mod.rs index 07fc4a98ef5..5359b368ba3 100644 --- a/catalyst-gateway/bin/src/service/api/mod.rs +++ b/catalyst-gateway/bin/src/service/api/mod.rs @@ -110,8 +110,11 @@ pub(crate) fn mk_api( IpAddr::V4(_) => (format!("{ip}:{port}"), "Server at local IPv4 address"), IpAddr::V6(_) => (format!("[{ip}]:{port}"), "Server at local IPv6 address"), }; - let ip_addresses = - add_protocol_prefix(&ip_with_port, settings.http_auto_servers, settings.https_auto_servers); + let ip_addresses = add_protocol_prefix( + &ip_with_port, + settings.http_auto_servers, + settings.https_auto_servers, + ); for address in ip_addresses { service = service.server(ServerObject::new(address).description(desc)); } From 821a1360d9f63219b12bcb0c9e188ba2228b57be Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 7 Feb 2024 17:33:38 +0700 Subject: [PATCH 14/15] fix: remove CommonSetting and add to DocsSetting --- catalyst-gateway/bin/src/cli.rs | 4 ++-- catalyst-gateway/bin/src/service/api/mod.rs | 4 ++-- catalyst-gateway/bin/src/service/mod.rs | 6 +++--- catalyst-gateway/bin/src/service/poem_service.rs | 10 +++++----- catalyst-gateway/bin/src/settings.rs | 12 ++---------- 5 files changed, 14 insertions(+), 22 deletions(-) diff --git a/catalyst-gateway/bin/src/cli.rs b/catalyst-gateway/bin/src/cli.rs index a9b08845978..9ab4a953924 100644 --- a/catalyst-gateway/bin/src/cli.rs +++ b/catalyst-gateway/bin/src/cli.rs @@ -49,11 +49,11 @@ impl Cli { logger::init(settings.log_level)?; let state = Arc::new(State::new(Some(settings.database_url)).await?); - service::run(&settings.common_settings, state).await?; + service::run(&settings.docs_settings, state).await?; Ok(()) }, Self::Docs(settings) => { - let docs = service::get_app_docs(&settings.common_settings); + let docs = service::get_app_docs(&settings); match settings.output { Some(path) => { let mut docs_file = std::fs::File::create(path)?; diff --git a/catalyst-gateway/bin/src/service/api/mod.rs b/catalyst-gateway/bin/src/service/api/mod.rs index 5359b368ba3..0a203e9ced0 100644 --- a/catalyst-gateway/bin/src/service/api/mod.rs +++ b/catalyst-gateway/bin/src/service/api/mod.rs @@ -13,7 +13,7 @@ use test_endpoints::TestApi; use v0::V0Api; use v1::V1Api; -use crate::settings::{CommonSettings, API_URL_PREFIX}; +use crate::settings::{DocsSettings, API_URL_PREFIX}; mod health; mod registration; @@ -61,7 +61,7 @@ const TERMS_OF_SERVICE: &str = /// Create the `OpenAPI` definition pub(crate) fn mk_api( - hosts: Vec, settings: &CommonSettings, + hosts: Vec, settings: &DocsSettings, ) -> OpenApiService<(TestApi, HealthApi, RegistrationApi, V0Api, V1Api), ()> { let mut service = OpenApiService::new( (TestApi, HealthApi, RegistrationApi, V0Api, V1Api), diff --git a/catalyst-gateway/bin/src/service/mod.rs b/catalyst-gateway/bin/src/service/mod.rs index edbc7ba771c..99d40b881e8 100644 --- a/catalyst-gateway/bin/src/service/mod.rs +++ b/catalyst-gateway/bin/src/service/mod.rs @@ -1,7 +1,7 @@ //! Main entrypoint to the service use std::sync::Arc; -use crate::{settings::CommonSettings, state::State}; +use crate::{settings::DocsSettings, state::State}; // These Modules contain endpoints mod api; @@ -34,7 +34,7 @@ pub(crate) enum Error { /// /// ## Arguments /// -/// `settings`: &`CommonSettings` - common setting for the application and docs. +/// `settings`: &`DocsSetting` - settings for docs /// `state`: `Arc` - the state /// /// ## Errors @@ -42,6 +42,6 @@ pub(crate) enum Error { /// `Error::CannotRunService` - cannot run the service /// `Error::EventDbError` - cannot connect to the event db /// `Error::IoError` - An IO error has occurred. -pub(crate) async fn run(settings: &CommonSettings, state: Arc) -> Result<(), Error> { +pub(crate) async fn run(settings: &DocsSettings, state: Arc) -> Result<(), Error> { poem_service::run(settings, state).await } diff --git a/catalyst-gateway/bin/src/service/poem_service.rs b/catalyst-gateway/bin/src/service/poem_service.rs index 55c1a3ef8eb..f06e87c0487 100644 --- a/catalyst-gateway/bin/src/service/poem_service.rs +++ b/catalyst-gateway/bin/src/service/poem_service.rs @@ -22,13 +22,13 @@ use crate::{ }, Error, }, - settings::{get_api_host_names, CommonSettings, API_URL_PREFIX}, + settings::{get_api_host_names, DocsSettings, API_URL_PREFIX}, state::State, }; /// This exists to allow us to add extra routes to the service for testing purposes. fn mk_app( - hosts: Vec, base_route: Option, state: &Arc, settings: &CommonSettings, + hosts: Vec, base_route: Option, state: &Arc, settings: &DocsSettings, ) -> impl Endpoint { // Get the base route if defined, or a new route if not. let base_route = match base_route { @@ -54,7 +54,7 @@ fn mk_app( } /// Get the API docs as a string in the JSON format. -pub(crate) fn get_app_docs(setting: &CommonSettings) -> String { +pub(crate) fn get_app_docs(setting: &DocsSettings) -> String { let api_service = mk_api(vec![], setting); api_service.spec() } @@ -65,14 +65,14 @@ pub(crate) fn get_app_docs(setting: &CommonSettings) -> String { /// /// # Arguments /// -/// *`settings`: &`CommonSettings` - common setting for the application and docs. +/// *`settings`: &`DocsSetting` - settings for docs /// /// # Errors /// /// * `Error::CannotRunService` - cannot run the service /// * `Error::EventDbError` - cannot connect to the event db /// * `Error::IoError` - An IO error has occurred. -pub(crate) async fn run(settings: &CommonSettings, state: Arc) -> Result<(), Error> { +pub(crate) async fn run(settings: &DocsSettings, state: Arc) -> Result<(), Error> { // The address to listen on let addr = settings.address; tracing::info!("Starting Poem Service ..."); diff --git a/catalyst-gateway/bin/src/settings.rs b/catalyst-gateway/bin/src/settings.rs index 34c219308a3..fcf5ca03e04 100644 --- a/catalyst-gateway/bin/src/settings.rs +++ b/catalyst-gateway/bin/src/settings.rs @@ -51,9 +51,9 @@ pub(crate) struct ServiceSettings { #[clap(long, default_value = LOG_LEVEL_DEFAULT)] pub(crate) log_level: LogLevel, - /// Common settings. + /// Docs settings. #[clap(flatten)] - pub(crate) common_settings: CommonSettings, + pub(crate) docs_settings: DocsSettings, } /// Settings specifies `OpenAPI` docs generation. @@ -62,14 +62,6 @@ pub(crate) struct DocsSettings { /// The output path to the generated docs file, if omitted prints to stdout. pub(crate) output: Option, - #[clap(flatten)] - /// Common settings. - pub(crate) common_settings: CommonSettings, -} - -/// Common settings for the application and `OpenAPI` docs generation. -#[derive(Args, Clone)] -pub(crate) struct CommonSettings { /// Server binding address #[clap(long, default_value = ADDRESS_DEFAULT)] pub(crate) address: SocketAddr, From c5003ac2a2358a3541173f6e2f3b8c2fd02ca573 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 7 Feb 2024 18:39:22 +0700 Subject: [PATCH 15/15] fix: env var and cli param --- catalyst-gateway/bin/src/settings.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/catalyst-gateway/bin/src/settings.rs b/catalyst-gateway/bin/src/settings.rs index fcf5ca03e04..e0a45150761 100644 --- a/catalyst-gateway/bin/src/settings.rs +++ b/catalyst-gateway/bin/src/settings.rs @@ -63,19 +63,19 @@ pub(crate) struct DocsSettings { pub(crate) output: Option, /// Server binding address - #[clap(long, default_value = ADDRESS_DEFAULT)] + #[clap(long, default_value = ADDRESS_DEFAULT, env = "ADDRESS")] pub(crate) address: SocketAddr, /// Flag for adding "http" to servers - #[clap(long, default_value = "false")] + #[clap(long, default_value = "false", env = "HTTP_AUTO_SERVERS")] pub(crate) http_auto_servers: bool, /// Flag for adding "https" to servers - #[clap(long, default_value = "true")] + #[clap(long, default_value = "true", env = "HTTPS_AUTO_SERVERS")] pub(crate) https_auto_servers: bool, /// Server name - #[clap(env = "SERVER_NAME")] + #[clap(long, env = "SERVER_NAME")] pub(crate) server_name: Option, }