From 933a1ce62ecedeb9937111256d5c5ed850fbeaef Mon Sep 17 00:00:00 2001 From: Marc Nijdam Date: Fri, 7 Apr 2023 07:47:43 -0500 Subject: [PATCH] Add support for port or complete api socketaddr (#411) * Add support for port or complete api socketaddr * Add ip:port doc for api listen setting --- config/settings.toml | 5 +-- src/api/client.rs | 14 +++++---- src/api/mod.rs | 11 ------- src/api/server.rs | 15 +++++---- src/cmd/add.rs | 2 +- src/cmd/info.rs | 12 +++---- src/settings.rs | 75 ++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 97 insertions(+), 37 deletions(-) diff --git a/config/settings.toml b/config/settings.toml index 59bdc770..54906606 100644 --- a/config/settings.toml +++ b/config/settings.toml @@ -14,8 +14,9 @@ keypair = "/etc/helium_gateway/gateway_key.bin" # The address to listen on for the (semtech) packet forwarder listen = "127.0.0.1:1680" -# The local port to serve the local grpc on. -# Do NOT expose this port outside of the host network for security +# The local port to serve the local grpc on. Supports both a simple port number +# or full ip:port listen address. Do NOT expose this port outside of the host +# network for security api = 4467 # The default region to use until a region is received from the Helium network. diff --git a/src/api/client.rs b/src/api/client.rs index faa6f72f..06c50cf7 100644 --- a/src/api/client.rs +++ b/src/api/client.rs @@ -1,7 +1,9 @@ -use super::{connect_uri, AddGatewayReq, GatewayStakingMode, PubkeyReq, RegionReq, RouterReq}; +use super::{AddGatewayReq, GatewayStakingMode, PubkeyReq, RegionReq, RouterReq}; use crate::{ - error::Error, packet_router::RouterStatus, settings::StakingMode, PublicKey, Region, Result, - TxnEnvelope, + error::Error, + packet_router::RouterStatus, + settings::{ListenAddress, StakingMode}, + PublicKey, Region, Result, TxnEnvelope, }; use helium_proto::{services::local::Client, BlockchainTxnAddGatewayV1}; use std::convert::TryFrom; @@ -12,9 +14,9 @@ pub struct LocalClient { } impl LocalClient { - pub async fn new(port: u16) -> Result { - let uri = connect_uri(port); - let endpoint = Endpoint::from_shared(uri).unwrap(); + pub async fn new(address: &ListenAddress) -> Result { + let uri = http::Uri::try_from(address)?; + let endpoint = Endpoint::from_shared(uri.to_string()).unwrap(); let client = Client::connect(endpoint) .await .map_err(Error::local_client_connect)?; diff --git a/src/api/mod.rs b/src/api/mod.rs index 774386c6..f7a10dbf 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,8 +1,6 @@ mod client; mod server; -const LISTEN_ADDR: &str = "127.0.0.1"; - pub use client::LocalClient; pub use helium_proto::{ services::local::{ @@ -13,15 +11,6 @@ pub use helium_proto::{ }; pub use server::LocalServer; -pub fn listen_addr(port: u16) -> String { - format!("{LISTEN_ADDR}:{port}") -} - -pub fn connect_uri(port: u16) -> String { - let listen_addr = listen_addr(port); - format!("http://{listen_addr}") -} - use crate::{Error, Result}; impl TryFrom for crate::packet_router::RouterStatus { diff --git a/src/api/server.rs b/src/api/server.rs index 8e9916cf..5727213d 100644 --- a/src/api/server.rs +++ b/src/api/server.rs @@ -1,6 +1,5 @@ use super::{ - listen_addr, AddGatewayReq, AddGatewayRes, PubkeyReq, PubkeyRes, RegionReq, RegionRes, - RouterReq, RouterRes, + AddGatewayReq, AddGatewayRes, PubkeyReq, PubkeyRes, RegionReq, RegionRes, RouterReq, RouterRes, }; use crate::{ packet_router, region_watcher, settings::StakingMode, Error, Keypair, PublicKey, Result, @@ -21,7 +20,7 @@ pub struct LocalServer { packet_router: packet_router::MessageSender, keypair: Arc, onboarding_key: PublicKey, - listen_port: u16, + listen_addr: SocketAddr, } impl LocalServer { @@ -33,19 +32,19 @@ impl LocalServer { Ok(Self { keypair: settings.keypair.clone(), onboarding_key: settings.onboarding_key(), - listen_port: settings.api, + listen_addr: (&settings.api).try_into()?, region_watch, packet_router, }) } pub async fn run(self, shutdown: &triggered::Listener) -> Result { - let addr: SocketAddr = listen_addr(self.listen_port).parse().unwrap(); - tracing::Span::current().record("listen", addr.to_string()); - info!(listen = %addr, "starting"); + let listen_addr = self.listen_addr; + tracing::Span::current().record("listen", &listen_addr.to_string()); + info!(listen = %listen_addr, "starting"); TransportServer::builder() .add_service(Server::new(self)) - .serve_with_shutdown(addr, shutdown.clone()) + .serve_with_shutdown(listen_addr, shutdown.clone()) .map_err(Error::from) .await } diff --git a/src/cmd/add.rs b/src/cmd/add.rs index 77e1049e..4ba83cf8 100644 --- a/src/cmd/add.rs +++ b/src/cmd/add.rs @@ -23,7 +23,7 @@ pub struct Cmd { impl Cmd { pub async fn run(&self, settings: Settings) -> Result { - let mut client = LocalClient::new(settings.api).await?; + let mut client = LocalClient::new(&settings.api).await?; let txn = client .add_gateway(&self.owner, &self.payer, &self.mode) diff --git a/src/cmd/info.rs b/src/cmd/info.rs index 8001e3c6..e5d93860 100644 --- a/src/cmd/info.rs +++ b/src/cmd/info.rs @@ -56,16 +56,16 @@ impl fmt::Display for InfoKey { } } struct InfoCache { - port: u16, + address: settings::ListenAddress, public_keys: Option<(PublicKey, PublicKey)>, region: Option>, router: Option, } impl InfoCache { - fn new(port: u16) -> Self { + fn new(address: settings::ListenAddress) -> Self { Self { - port, + address, public_keys: None, region: None, router: None, @@ -76,7 +76,7 @@ impl InfoCache { if let Some(public_keys) = &self.public_keys { return Ok(public_keys.clone()); } - let mut client = LocalClient::new(self.port).await?; + let mut client = LocalClient::new(&self.address).await?; let public_keys = client.pubkey().await?; self.public_keys = Some(public_keys.clone()); Ok(public_keys) @@ -96,7 +96,7 @@ impl InfoCache { if let Some(maybe_region) = self.region { return Ok(maybe_region); } - let mut client = LocalClient::new(self.port).await?; + let mut client = LocalClient::new(&self.address).await?; let region = client.region().await?; let maybe_region = if region.is_unknown() { None @@ -111,7 +111,7 @@ impl InfoCache { if let Some(router) = &self.router { return Ok(router.clone()); } - let mut client = LocalClient::new(self.port).await?; + let mut client = LocalClient::new(&self.address).await?; let router = client.router().await?; self.router = Some(router.clone()); Ok(router) diff --git a/src/settings.rs b/src/settings.rs index a95a529c..18fcce42 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -18,7 +18,7 @@ pub struct Settings { /// The listening network port for the grpc / jsonrpc API. /// Default 4467 #[serde(default = "default_api")] - pub api: u16, + pub api: ListenAddress, /// The location of the keypair binary file for the gateway. If the keyfile /// is not found there a new one is generated and saved in that location. pub keypair: Arc, @@ -139,8 +139,8 @@ fn default_listen() -> String { "127.0.0.1:1680".to_string() } -fn default_api() -> u16 { - 4467 +fn default_api() -> ListenAddress { + ListenAddress::Address("127.0.0.1:4467".to_string()) } fn default_poc_interval() -> u64 { @@ -187,6 +187,75 @@ impl fmt::Display for StakingMode { } } +#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] +#[serde(untagged)] +pub enum ListenAddress { + Port(u16), + Address(String), +} + +impl TryFrom<&ListenAddress> for std::net::SocketAddr { + type Error = crate::Error; + fn try_from(value: &ListenAddress) -> std::result::Result { + match value { + ListenAddress::Address(str) => Ok(str.parse()?), + ListenAddress::Port(v) => Ok(format!("127.0.0.1:{v}").parse()?), + } + } +} + +impl TryFrom<&ListenAddress> for http::Uri { + type Error = crate::Error; + fn try_from(value: &ListenAddress) -> std::result::Result { + match value { + ListenAddress::Address(str) => Ok(Uri::from_str(&format!("http://{str}"))?), + ListenAddress::Port(v) => Ok(Uri::from_str(&format!("http://127.0.0.1:{v}"))?), + } + } +} + +// pub mod api { +// use serde::de; + +// pub fn deserialize<'de, D>(deserializer: D) -> std::result::Result +// where +// D: de::Deserializer<'de>, +// { +// struct _Visitor; + +// impl<'de> de::Visitor<'de> for _Visitor { +// type Value = String; +// fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { +// formatter.write_str("api listen port or address") +// } + +// fn visit_i32(self, v: i32) -> Result +// where +// E: de::Error, +// { +// Ok(format!("127.0.0.1:{v}")) +// } + +// fn visit_u16(self, v: u16) -> Result +// where +// E: de::Error, +// { +// Ok(format!("127.0.0.1:{v}")) +// } + +// fn visit_str(self, value: &str) -> std::result::Result +// where +// E: de::Error, +// { +// Ok(value.to_string()) +// } +// } + +// eprintln!("visiting"); +// deserializer.deserialize_any(_Visitor) +// } +// } + pub mod log_level { use serde::de::{self, Deserialize, Deserializer, Visitor}; use std::fmt;