diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f2a4093 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +**/target \ No newline at end of file diff --git a/.sqlx/query-52bb01ba66ab2c2c3dda00e31483e9d6896fdd4ad7189e240fbc7254be43e5dd.json b/.sqlx/query-52bb01ba66ab2c2c3dda00e31483e9d6896fdd4ad7189e240fbc7254be43e5dd.json new file mode 100644 index 0000000..51116f2 --- /dev/null +++ b/.sqlx/query-52bb01ba66ab2c2c3dda00e31483e9d6896fdd4ad7189e240fbc7254be43e5dd.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO subscriptions (id,email, name)\n VALUES ($1,$2,$3)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "52bb01ba66ab2c2c3dda00e31483e9d6896fdd4ad7189e240fbc7254be43e5dd" +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2ce7ccd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM rust:latest +WORKDIR /app +RUN apt update && apt install lld clang -y +COPY . . +ENV SQLX_OFFLINE true +RUN cargo build --release +ENV APP_ENVIRONMENT production +ENTRYPOINT ["./target/release/zero2prod"] \ No newline at end of file diff --git a/configuration.yaml b/configuration/base.yaml similarity index 82% rename from configuration.yaml rename to configuration/base.yaml index b3a7d9a..a7e4a5d 100644 --- a/configuration.yaml +++ b/configuration/base.yaml @@ -1,4 +1,5 @@ -application_port: 8000 +application: + port: 8000 database: host: "localhost" port: 5432 diff --git a/configuration/local.yaml b/configuration/local.yaml new file mode 100644 index 0000000..c464c2f --- /dev/null +++ b/configuration/local.yaml @@ -0,0 +1,2 @@ +application: + host: 127.0.0.1 diff --git a/configuration/production.yaml b/configuration/production.yaml new file mode 100644 index 0000000..b936a88 --- /dev/null +++ b/configuration/production.yaml @@ -0,0 +1,2 @@ +application: + host: 0.0.0.0 diff --git a/src/configuration.rs b/src/configuration.rs index 42e4694..28a9734 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,10 +1,16 @@ use secrecy::{ExposeSecret, Secret}; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; #[derive(serde::Deserialize)] pub struct Settings { pub database: DatabaseSettings, - pub application_port: u16, + pub application: ApplicationSettings, +} + +#[derive(serde::Deserialize)] +pub struct ApplicationSettings { + pub port: u16, + pub host: String, } #[derive(serde::Deserialize)] @@ -44,27 +50,65 @@ pub fn get_configuration() -> Result { fn try_from(config: config::Config) -> Result { let database = config.get::("database")?; - let application_port = config.get::("application_port")?; + let application = config.get::("application")?; Ok(Settings { database, - application_port, + application, }) } } let mut settings = config::Config::builder(); - // Add configuration values from a file named `configuration`. - // It will look for any top-level file with an extension - // that `config` knows how to parse: yaml, json, etc. - settings = settings.add_source(config::File::with_name("configuration")); + let base_path = std::env::current_dir().expect("Failed to determine the current directory"); + let configuration_directory = base_path.join("configuration"); + + // Read the "default" configuration file + settings = settings + .add_source(config::File::from(configuration_directory.join("base")).required(true)); + + let environment: Environment = std::env::var("APP_ENVIRONMENT") + .unwrap_or_else(|_| "local".into()) + .try_into() + .expect("Failed to parse APP_ENVIRONMENT."); + + // Layer on the environment-specific values. + settings = settings.add_source( + config::File::from(configuration_directory.join(environment.as_str())).required(true), + ); - // Build the configuration and unwrap it, handling any errors let settings = settings.build()?; - // Try to convert the configuration values you read into - // our Settings type - // nosso tipo Settings settings.try_into() } + +/// The possible runtime environment for our application. +pub enum Environment { + Local, + Production, +} + +impl Environment { + pub fn as_str(&self) -> &'static str { + match self { + Environment::Local => "local", + Environment::Production => "production", + } + } +} + +impl TryFrom for Environment { + type Error = String; + + fn try_from(s: String) -> Result { + match s.to_lowercase().as_str() { + "local" => Ok(Self::Local), + "production" => Ok(Self::Production), + other => Err(format!( + "{} is not a supported environment. Use either `local` or `production`.", + other + )), + } + } +} diff --git a/src/main.rs b/src/main.rs index 6d9cfc6..49e519d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,11 +11,13 @@ async fn main() -> std::io::Result<()> { let configuration = get_configuration().expect("Failed to read configuration."); - let connection_pool = PgPool::connect(&configuration.database.connection_string()) - .await + let connection_pool = PgPool::connect_lazy(&configuration.database.connection_string()) .expect("Failed to connect to Postgres."); - let address = format!("127.0.0.1:{}", configuration.application_port); + let address = format!( + "{}:{}", + configuration.application.host, configuration.application.port + ); let listener = TcpListener::bind(address)?; run(listener, connection_pool)?.await }