diff --git a/.github/workflows/general.yml b/.github/workflows/general.yml index 8de6d41..58b34ad 100644 --- a/.github/workflows/general.yml +++ b/.github/workflows/general.yml @@ -15,7 +15,7 @@ env: SQLX_FEATURES: "rustls,postgres" DATABASE_URL: postgres://postgres:password@postgres:5432/newsletter APP_DATABASE__HOST: postgres - APP_REDIS_URI: redis://redis:6379 + APP_KV_STORE__HOST: redis jobs: test: diff --git a/configuration/local.yaml b/configuration/local.yaml index 81c9322..20fef36 100644 --- a/configuration/local.yaml +++ b/configuration/local.yaml @@ -2,6 +2,8 @@ application: port: 8080 host: "127.0.0.1" base_url: "http://127.0.0.1:8080" +email_client: + authorization_token: "secret-token" database: host: "127.0.0.1" port: 5432 @@ -10,6 +12,6 @@ database: password: "password" require_ssl: false timeout_milliseconds: 1000 -email_client: - authorization_token: "secret-token" -redis_uri: "redis://127.0.0.1:6379" +kv_store: + host: "127.0.0.1" + port: 6379 diff --git a/src/configuration.rs b/src/configuration.rs index 9316ba0..f5cd987 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,8 +1,13 @@ use crate::domain::SubscriberEmail; +use anyhow::Context; use secrecy::{ExposeSecret, SecretString}; use serde::Deserialize; use serde_aux::field_attributes::deserialize_number_from_string; use sqlx::postgres::{PgConnectOptions, PgSslMode}; +use tower_sessions_redis_store::{ + RedisStore, + fred::prelude::{ClientLike, Pool}, +}; pub fn get_configuration() -> Result { let base_path = std::env::current_dir().expect("Failed to determine the current directory"); @@ -60,7 +65,7 @@ pub struct Settings { pub application: ApplicationSettings, pub database: DatabaseSettings, pub email_client: EmailClientSettings, - pub redis_uri: SecretString, + pub kv_store: RedisSettings, } #[derive(Clone, Deserialize)] @@ -100,6 +105,35 @@ impl EmailClientSettings { } } +#[derive(Clone, Deserialize)] +pub struct RedisSettings { + pub host: String, + pub port: u16, +} + +impl RedisSettings { + pub fn connection_string(&self) -> String { + format!("redis://{}:{}", self.host, self.port) + } + + pub async fn session_store(&self) -> Result, anyhow::Error> { + let pool = Pool::new( + tower_sessions_redis_store::fred::prelude::Config::from_url(&self.connection_string()) + .context("Failed to parse Redis URL string.")?, + None, + None, + None, + 6, + ) + .unwrap(); + pool.connect(); + pool.wait_for_connect() + .await + .context("Failed to connect to the Redis server.")?; + Ok(RedisStore::new(pool)) + } +} + #[derive(Clone, Deserialize)] pub struct DatabaseSettings { pub username: String, diff --git a/src/startup.rs b/src/startup.rs index 79aeaa7..6df9909 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -10,16 +10,12 @@ use axum::{ routing::{delete, get, post}, }; use reqwest::{StatusCode, header}; -use secrecy::ExposeSecret; use sqlx::{PgPool, postgres::PgPoolOptions}; use std::{sync::Arc, time::Duration}; use tokio::net::TcpListener; use tower_http::{services::ServeDir, trace::TraceLayer}; use tower_sessions::SessionManagerLayer; -use tower_sessions_redis_store::{ - RedisStore, - fred::prelude::{ClientLike, Config, Pool}, -}; +use tower_sessions_redis_store::{RedisStore, fred::prelude::Pool}; use uuid::Uuid; #[derive(Clone)] @@ -46,18 +42,11 @@ impl Application { )) .connect_lazy_with(configuration.database.with_db()); let email_client = EmailClient::build(configuration.email_client).unwrap(); - let pool = Pool::new( - Config::from_url(configuration.redis_uri.expose_secret()) - .expect("Failed to parse Redis URL string"), - None, - None, - None, - 6, - ) - .unwrap(); - pool.connect(); - pool.wait_for_connect().await.unwrap(); - let redis_store = RedisStore::new(pool); + let redis_store = configuration + .kv_store + .session_store() + .await + .context("Failed to acquire Redis session store.")?; let router = app( connection_pool, email_client,