diff --git a/BookForge.toml b/BookForge.toml new file mode 100644 index 0000000..3c2268e --- /dev/null +++ b/BookForge.toml @@ -0,0 +1,5 @@ +database_path = "" + +[listener] +port = 8000 +host = "0.0.0.0" diff --git a/config.toml b/config.toml deleted file mode 100644 index 1b43556..0000000 --- a/config.toml +++ /dev/null @@ -1 +0,0 @@ -database_path = "/home/torrpenn/projects/Gabatxo1312/bookforge/db.sqlite" diff --git a/src/main.rs b/src/main.rs index 19f21d0..d3161b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use bookforge::state::error::AppStateError; +use bookforge::state::listener::ListenerError; use snafu::ErrorCompat; use snafu::prelude::*; @@ -11,6 +12,10 @@ pub enum AppError { State { source: AppStateError, }, + #[snafu(display("Listener Error"))] + Listener { + source: ListenerError, + }, Error, } @@ -18,9 +23,14 @@ async fn main_inner() -> Result<(), AppError> { pretty_env_logger::init(); let app_state = AppState::new().await.context(StateSnafu)?; - let app = build_app(app_state); + let app = build_app(app_state.clone()); - let listener = tokio::net::TcpListener::bind("0.0.0.0:8000").await.unwrap(); + let addr = app_state + .config + .listener + .socket_addr() + .context(ListenerSnafu)?; + let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); let _ = axum::serve(listener, app).await; diff --git a/src/state/config.rs b/src/state/config.rs index 4c0d77b..4f81560 100644 --- a/src/state/config.rs +++ b/src/state/config.rs @@ -5,6 +5,8 @@ use camino::Utf8PathBuf; use dirs::config_dir; use serde::{Deserialize, Serialize}; +use crate::state::listener::Listener; + #[derive(Snafu, Debug)] pub enum ConfigError { #[snafu(display("File doesn't exist at path : {path}"))] @@ -30,12 +32,14 @@ pub enum ConfigError { pub struct AppConfig { #[serde(default = "AppConfig::default_sqlite_path")] pub database_path: Utf8PathBuf, + pub listener: Listener, } impl Default for AppConfig { fn default() -> Self { AppConfig { database_path: Self::default_sqlite_path(), + listener: Listener::default(), } } } diff --git a/src/state/listener.rs b/src/state/listener.rs new file mode 100644 index 0000000..48b158f --- /dev/null +++ b/src/state/listener.rs @@ -0,0 +1,62 @@ +use snafu::prelude::*; +use std::net::{AddrParseError, SocketAddr}; + +use serde::{Deserialize, Serialize}; + +/// Errors related to listener configuration and socket binding. +#[derive(Snafu, Debug)] +pub enum ListenerError { + /// The provided bind address and/or port could not be parsed into a valid + /// `SocketAddr`. + #[snafu(display("Socket address is wrong"))] + SocketAddrInvalid { + socket_addr: String, + source: AddrParseError, + }, +} + +/// Listener configuration used to bind a TCP socket. +/// +/// `bind_addr` represents the interface to bind to (e.g. `0.0.0.0`, +/// `127.0.0.1`, `::`), and `port` is the TCP port. +#[derive(Clone, Deserialize, Serialize, Debug)] +pub struct Listener { + pub port: u32, + pub bind_addr: String, +} + +/// Default listener configuration: +/// - bind on all interfaces (`0.0.0.0`) +/// - listen on port 8000 +impl Default for Listener { + fn default() -> Self { + Listener { + port: Self::default_port(), + bind_addr: Self::default_bind_addr(), + } + } +} + +impl Listener { + /// Default bind address used when none is specified. + fn default_bind_addr() -> String { + "0.0.0.0".to_string() + } + + /// Default port used whend none is specified + fn default_port() -> u32 { + 8000 + } + + /// Computes the socket address used for binding. + /// + /// # Errors + /// Returns `ListenerError::SocketAddrInvalid` if the address or port + /// cannot be parsed into a valid `SocketAddr`. + pub fn socket_addr(&self) -> Result { + let socket_addr = format!("{}:{}", self.bind_addr, self.port); + socket_addr + .parse() + .context(SocketAddrInvalidSnafu { socket_addr }) + } +} diff --git a/src/state/mod.rs b/src/state/mod.rs index 1ae4694..c4e97d0 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -7,6 +7,7 @@ use sea_orm_migration::MigratorTrait; pub mod config; pub mod error; +pub mod listener; #[derive(Clone, Debug)] pub struct AppState {