Skip to content

Commit

Permalink
refactor(env): use collected vars from app state
Browse files Browse the repository at this point in the history
  • Loading branch information
Ahmard committed Apr 29, 2024
1 parent 7948de0 commit 9db03a8
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 155 deletions.
115 changes: 48 additions & 67 deletions src/app_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,73 +12,72 @@ use mobc::Pool;
use redis::Client;
use tera::Tera;

use crate::app_state::{AppRedisChannels, AppRedisQueues, AppServices, AppState, Frontend};
use crate::app_state::{AppServices, MedullahState};
#[cfg(feature = "feat-database")]
use crate::database::DBPool;
use crate::helpers::fs::get_cwd;
use crate::redis::{RedisConnectionManager, RedisPool};
use crate::services::cache_service::CacheService;
use crate::services::redis_service::RedisService;
use crate::APP;
use crate::MEDULLAH;

const CACHE_POOL_MAX_OPEN: u64 = 16;
const CACHE_POOL_MAX_IDLE: u64 = 8;
const CACHE_POOL_TIMEOUT_SECONDS: u64 = 1;
const CACHE_POOL_EXPIRE_SECONDS: u64 = 60;

pub async fn make_app_state() -> AppState {
let app = create_app_state().await;
APP.set(app.clone()).expect("failed to set up TSP");
pub async fn make_app_state(env_prefix: String) -> MedullahState {
let app = create_app_state(env_prefix).await;
MEDULLAH.set(app.clone()).expect("failed to set up TSP");
app
}

async fn create_app_state() -> AppState {
async fn create_app_state(env_prefix: String) -> MedullahState {
#[cfg(feature = "feat-database")]
let database_pool = establish_database_connection();
let database_pool = establish_database_connection(&env_prefix);

let redis = establish_redis_connection();
let redis_pool = establish_redis_connection_pool();
let redis = establish_redis_connection(&env_prefix);
let redis_pool = establish_redis_connection_pool(&env_prefix);
let redis_service = Arc::new(RedisService::new(redis_pool.clone()));

// templating
let tpl_dir = get_cwd() + "/resources/templates/**/*.tera.html";
let tera_templating = Tera::new(tpl_dir.as_str()).unwrap();

AppState {
app_id: env::var("SPACE_APP_ID").unwrap(),
app_domain: env::var("SPACE_APP_DOMAIN").unwrap(),
app_name: env::var("SPACE_APP_NAME").unwrap(),
app_desc: env::var("SPACE_APP_DESC").unwrap(),
app_key: env::var("SPACE_APP_KEY").unwrap(),
app_help_email: env::var("SPACE_APP_HELP_EMAIL").unwrap(),
app_frontend_url: env::var("SPACE_FRONTEND_ADDRESS").unwrap(),

frontend: load_frontend_config(),
MedullahState {
app_id: env::var(format!("{}_APP_ID", env_prefix)).unwrap(),
app_domain: env::var(format!("{}_APP_DOMAIN", env_prefix)).unwrap(),
app_name: env::var(format!("{}_APP_NAME", env_prefix)).unwrap(),
app_desc: env::var(format!("{}_APP_DESC", env_prefix)).unwrap(),
app_key: env::var(format!("{}_APP_KEY", env_prefix)).unwrap(),
app_help_email: env::var(format!("{}_APP_HELP_EMAIL", env_prefix)).unwrap(),
app_frontend_url: env::var(format!("{}_FRONTEND_ADDRESS", env_prefix)).unwrap(),

redis: Arc::new(redis),
redis_pool: Arc::new(redis_pool),
#[cfg(feature = "feat-database")]
database: database_pool,
tera: tera_templating,

auth_pat_prefix: env::var("SPACE_AUTH_PAT_PREFIX").unwrap(),
auth_pat_prefix: env::var(format!("{}_AUTH_PAT_PREFIX", env_prefix)).unwrap(),
auth_token_lifetime: env::var(format!("{}_AUTH_TOKEN_LIFETIME", env_prefix))
.unwrap()
.parse()
.unwrap(),

allowed_origins: get_allowed_origins(),
allowed_origins: get_allowed_origins(&env_prefix),

// mail
mailer_from_name: env::var("SPACE_MAIL_FROM_NAME").unwrap(),
mailer_from_email: env::var("SPACE_MAIL_FROM_EMAIL").unwrap(),
mailer_server_endpoint: env::var("SPACE_MAILER_SERVER_ENDPOINT").unwrap(),
mailer_server_auth_token: env::var("SPACE_MAILER_SERVER_AUTH_TOKEN").unwrap(),
mailer_server_application_id: env::var("SPACE_MAILER_SERVER_APPLICATION_ID").unwrap(),

monnify_api_key: env::var("SPACE_MONNIFY_API_KEY").unwrap(),
monnify_secret_key: env::var("SPACE_MONNIFY_SECRET_KEY").unwrap(),
monnify_contract_code: env::var("SPACE_MONNIFY_CONTRACT_CODE").unwrap(),
monnify_server_endpoint: env::var("SPACE_MONNIFY_SERVER_ENDPOINT").unwrap(),
mailer_from_name: env::var(format!("{}_MAIL_FROM_NAME", env_prefix)).unwrap(),
mailer_from_email: env::var(format!("{}_MAIL_FROM_EMAIL", env_prefix)).unwrap(),
mailer_server_endpoint: env::var(format!("{}_MAILER_SERVER_ENDPOINT", env_prefix)).unwrap(),
mailer_server_auth_token: env::var(format!("{}_MAILER_SERVER_AUTH_TOKEN", env_prefix)).unwrap(),
mailer_server_application_id: env::var(format!("{}_MAILER_SERVER_APPLICATION_ID", env_prefix)).unwrap(),

redis_queues: get_redis_queues(),
redis_channels: get_redis_channels(),
monnify_api_key: env::var(format!("{}_MONNIFY_API_KEY", env_prefix)).unwrap(),
monnify_secret_key: env::var(format!("{}_MONNIFY_SECRET_KEY", env_prefix)).unwrap(),
monnify_contract_code: env::var(format!("{}_MONNIFY_CONTRACT_CODE", env_prefix)).unwrap(),
monnify_server_endpoint: env::var(format!("{}_MONNIFY_SERVER_ENDPOINT", env_prefix)).unwrap(),

services: AppServices {
redis: redis_service.clone(),
Expand All @@ -87,20 +86,26 @@ async fn create_app_state() -> AppState {
}
}

pub fn get_server_host_config() -> (String, u16, usize) {
let host: String = env::var("SPACE_SERVER_HOST").unwrap();
let port: u16 = env::var("SPACE_SERVER_PORT").unwrap().parse().unwrap();
let workers: usize = env::var("SPACE_SERVER_WORKERS").unwrap().parse().unwrap();
pub fn get_server_host_config(env_prefix: &String) -> (String, u16, usize) {
let host: String = env::var(format!("{}_SERVER_HOST", env_prefix)).unwrap();
let port: u16 = env::var(format!("{}_SERVER_PORT", env_prefix)).unwrap().parse().unwrap();
let workers: usize = env::var(format!("{}_SERVER_WORKERS", env_prefix)).unwrap().parse().unwrap();
(host, port, workers)
}

pub fn establish_redis_connection() -> Client {
let redis_url: String = env::var("SPACE_REDIS_DSN").unwrap();
pub fn get_allowed_origins(env_prefix: &String) -> Vec<String> {
let url_str = env::var(format!("{}_ALLOWED_ORIGINS", env_prefix)).unwrap();
let origins: Vec<&str> = url_str.split(',').collect();
origins.iter().map(|o| o.trim().to_string()).collect()
}

pub fn establish_redis_connection(env_prefix: &String) -> Client {
let redis_url: String = env::var(format!("{}_REDIS_DSN", env_prefix)).unwrap();
Client::open(redis_url).unwrap()
}

pub fn establish_redis_connection_pool() -> RedisPool {
let redis_url: String = env::var("SPACE_REDIS_DSN").unwrap();
pub fn establish_redis_connection_pool(env_prefix: &String) -> RedisPool {
let redis_url: String = env::var(format!("{}_REDIS_DSN", env_prefix)).unwrap();
let client = Client::open(redis_url).unwrap();
let manager = RedisConnectionManager::new(client);
Pool::builder()
Expand All @@ -112,38 +117,14 @@ pub fn establish_redis_connection_pool() -> RedisPool {
}

#[cfg(feature = "feat-database")]
pub fn establish_database_connection() -> DBPool {
let db_url: String = env::var("SPACE_DATABASE_DSN").unwrap();
pub fn establish_database_connection(env_prefix: &String) -> DBPool {
let db_url: String = env::var(format!("{}_DATABASE_DSN", env_prefix)).unwrap();
let manager = ConnectionManager::<PgConnection>::new(db_url);
r2d2::Pool::builder()
.build(manager)
.expect("Failed to create database pool.")
}

pub fn get_redis_queues() -> AppRedisQueues {
AppRedisQueues {
virtual_acc_num: env::var("SPACE_REDIS_QUEUE_VIRTUAL_ACC_NUM").unwrap(),
announcement_un_synced: env::var("GENESIS_REDIS_QUEUE_ANNOUNCEMENT_UN_SYNCED").unwrap(),
}
}

pub fn get_redis_channels() -> AppRedisChannels {
AppRedisChannels {
payment_received: env::var("SPACE_REDIS_CHANNEL_TRANSFER_RECEIVED").unwrap()
}
}

pub fn get_allowed_origins() -> Vec<String> {
let url_str = env::var("SPACE_ALLOWED_ORIGINS").unwrap();
let origins: Vec<&str> = url_str.split(',').collect();
origins.iter().map(|o| o.trim().to_string()).collect()
}

pub fn load_frontend_config() -> Frontend {
let file_contents = load_config_file("frontend.toml");
toml::from_str::<Frontend>(&file_contents).unwrap()
}

pub fn load_config_file(file: &str) -> String {
fs::read_to_string(format!("resources/config/{}", file)).unwrap()
}
Expand Down
39 changes: 4 additions & 35 deletions src/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ use std::fmt::{Debug, Formatter};
use std::sync::Arc;

use redis::Client as RedisClient;
use serde::Deserialize;
use tera::{Context, Tera};

use crate::redis::RedisPool;
use crate::services::cache_service::CacheService;
use crate::services::redis_service::RedisService;

#[derive(Clone)]
pub struct AppState {
pub struct MedullahState {
pub app_id: String,
pub app_domain: String,
pub app_name: String,
Expand All @@ -19,8 +18,6 @@ pub struct AppState {
pub app_frontend_url: String,
pub app_key: String,

pub frontend: Frontend,

#[cfg(feature = "feat-templating")]
pub(crate) tera: Tera,

Expand All @@ -30,6 +27,7 @@ pub struct AppState {
pub(crate) database: crate::database::DBPool,

pub auth_pat_prefix: String,
pub auth_token_lifetime: i64,

pub allowed_origins: Vec<String>,

Expand All @@ -39,9 +37,6 @@ pub struct AppState {
pub mailer_server_auth_token: String,
pub mailer_server_application_id: String,

pub redis_queues: AppRedisQueues,
pub redis_channels: AppRedisChannels,

pub monnify_contract_code: String,
pub monnify_api_key: String,
pub monnify_secret_key: String,
Expand All @@ -56,33 +51,7 @@ pub struct AppServices {
pub cache: Arc<CacheService>,
}

#[derive(Clone)]
pub struct AppRedisQueues {
pub virtual_acc_num: String,
pub announcement_un_synced: String,
}

#[derive(Clone)]
pub struct AppRedisChannels {
pub payment_received: String
}

#[derive(Deserialize, Clone)]
pub struct Frontend {
pub url: FrontendUrl,
}

#[derive(Deserialize, Clone)]
pub struct FrontendUrl {
pub base: String,
pub profile: String,
pub login: String,
pub register: String,
pub forget_password: String,
pub change_password: String,
}

impl AppState {
impl MedullahState {
#[cfg(feature = "feat-database")]
pub fn database(&self) -> &crate::database::DBPool {
&self.database
Expand Down Expand Up @@ -113,7 +82,7 @@ impl AppState {
}
}

impl Debug for AppState {
impl Debug for MedullahState {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("application state")
}
Expand Down
24 changes: 8 additions & 16 deletions src/helpers/once_lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,17 @@ use diesel::r2d2::ConnectionManager;
use diesel::PgConnection;
use redis::Client;

use crate::app_state::{AppRedisQueues, AppState, Frontend};
use crate::app_state::{MedullahState};
#[cfg(feature = "feat-database")]
use crate::database::DatabaseConnectionHelper;
use crate::redis::RedisPool;
use crate::services::cache_service::CacheService;
use crate::services::redis_service::RedisService;
use crate::APP;
use crate::MEDULLAH;

pub trait OnceLockHelper<'a> {
fn app(&self) -> &'a AppState {
APP.get().unwrap()
}

fn frontend(&self) -> &'a Frontend {
&self.app().frontend
fn app(&self) -> &'a MedullahState {
MEDULLAH.get().unwrap()
}

fn front_url(&self, url: &str) -> String {
Expand All @@ -29,7 +25,7 @@ pub trait OnceLockHelper<'a> {

#[cfg(feature = "feat-database")]
fn database(&self) -> &'a crate::database::DBPool {
APP.get().unwrap().database()
MEDULLAH.get().unwrap().database()
}

fn redis(&self) -> Arc<Client> {
Expand All @@ -41,15 +37,11 @@ pub trait OnceLockHelper<'a> {
}

fn cache(&self) -> &CacheService {
&APP.get().unwrap().services.cache
&MEDULLAH.get().unwrap().services.cache
}

fn redis_service(&self) -> &RedisService {
&APP.get().unwrap().services.redis
}

fn redis_queues(&self) -> &AppRedisQueues {
&APP.get().unwrap().redis_queues
&MEDULLAH.get().unwrap().services.redis
}

#[cfg(feature = "feat-database")]
Expand All @@ -60,4 +52,4 @@ pub trait OnceLockHelper<'a> {
}
}

impl<'a> OnceLockHelper<'a> for OnceLock<AppState> {}
impl<'a> OnceLockHelper<'a> for OnceLock<MedullahState> {}
8 changes: 4 additions & 4 deletions src/helpers/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use ntex::util::Bytes;
use ntex::web::HttpRequest;
use serde::de::DeserializeOwned;

use crate::app_state::AppState;
use crate::app_state::MedullahState;
use crate::database::DBPool;
use crate::helpers::http::get_ip_and_ua;
use crate::http::extractors::client_info::ClientInfo;
use crate::results::app_result::IntoAppResult;
use crate::results::AppResult;

pub trait RequestHelper {
fn app(&self) -> &AppState;
fn app(&self) -> &MedullahState;

fn db_pool(&self) -> &DBPool;

Expand All @@ -21,8 +21,8 @@ pub trait RequestHelper {
}

impl RequestHelper for HttpRequest {
fn app(&self) -> &AppState {
self.app_state::<AppState>().unwrap()
fn app(&self) -> &MedullahState {
self.app_state::<MedullahState>().unwrap()
}

fn db_pool(&self) -> &DBPool {
Expand Down
15 changes: 6 additions & 9 deletions src/helpers/security.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::env;

use chrono::{Duration, Utc};
use jsonwebtoken::{encode, EncodingKey, Header};
use serde::{Deserialize, Serialize};

use crate::MEDULLAH;
use crate::prelude::OnceLockHelper;

#[derive(Debug, Serialize, Deserialize)]
pub struct TokenClaims {
pub sub: String,
Expand All @@ -25,12 +26,8 @@ pub fn generate_token(
header: Option<Header>,
lifetime: Option<i64>,
) -> AuthTokenData {
let token_lifetime_in_minutes: i64 = lifetime.unwrap_or_else(|| {
env::var("SPACE_AUTH_TOKEN_LIFETIME")
.unwrap()
.parse()
.unwrap()
});
let token_lifetime_in_minutes: i64 =
lifetime.unwrap_or_else(|| MEDULLAH.app().auth_token_lifetime);

let now = Utc::now();
let iat = now.timestamp() as usize;
Expand All @@ -47,7 +44,7 @@ pub fn generate_token(
let token = encode(
&token_header,
&claims,
&EncodingKey::from_secret(env::var("SPACE_APP_KEY").unwrap().as_ref()),
&EncodingKey::from_secret(MEDULLAH.app().app_key.clone().as_ref()),
)
.unwrap();

Expand Down
Loading

0 comments on commit 9db03a8

Please sign in to comment.