medullah_web/
app_setup.rs

1use std::path::Path;
2#[allow(unused_imports)]
3use std::sync::Arc;
4use std::{env, fs};
5
6#[cfg(feature = "mailer")]
7use crate::app_state::AppMailerConfig;
8use crate::app_state::{AppHelpers, AppServices, MedullahState};
9#[cfg(feature = "database")]
10use crate::database::DBPool;
11#[cfg(feature = "jwt")]
12use crate::helpers::jwt::Jwt;
13#[cfg(feature = "crypto")]
14use crate::helpers::password::Password;
15use crate::http::Method;
16#[cfg(feature = "rabbitmq")]
17use crate::prelude::RabbitMQ;
18#[cfg(feature = "redis")]
19use crate::prelude::Redis;
20#[cfg(feature = "rabbitmq")]
21use crate::rabbitmq::conn::establish_rabbit_connection_pool;
22#[cfg(feature = "redis")]
23use crate::redis::conn::establish_redis_connection_pool;
24#[cfg(feature = "redis")]
25use crate::services::cache_service::CacheService;
26use crate::MEDULLAH;
27#[cfg(feature = "database")]
28use diesel::r2d2::ConnectionManager;
29#[cfg(feature = "database")]
30use diesel::PgConnection;
31use log::info;
32#[cfg(feature = "templating")]
33use tera::Tera;
34
35pub struct MedullahSetup {
36    pub env_prefix: String,
37    pub private_key: String,
38    pub public_key: String,
39    pub auth_iss_public_key: String,
40    pub allowed_origins: Vec<String>,
41    pub allowed_methods: Vec<Method>,
42}
43
44pub async fn make_app_state(setup: MedullahSetup) -> MedullahState {
45    let app = create_app_state(setup).await;
46    MEDULLAH
47        .set(app.clone())
48        .expect("failed to set up medullah-web");
49    app
50}
51
52async fn create_app_state(setup: MedullahSetup) -> MedullahState {
53    let helpers = make_helpers(&setup.env_prefix, &setup);
54    let env_prefix = setup.env_prefix;
55
56    #[cfg(feature = "database")]
57    let database_pool = establish_database_connection(&env_prefix);
58
59    #[cfg(feature = "redis")]
60    let redis_pool = establish_redis_connection_pool(&env_prefix);
61    #[cfg(feature = "redis")]
62    let redis = Arc::new(Redis::new(redis_pool.clone()));
63
64    // RabbitMQ
65    #[cfg(feature = "rabbitmq")]
66    let rabbitmq_pool = establish_rabbit_connection_pool(&env_prefix).await;
67
68    #[cfg(feature = "rabbitmq")]
69    let rabbitmq = Arc::new(tokio::sync::Mutex::new(
70        RabbitMQ::new(rabbitmq_pool.clone()).await.unwrap(),
71    ));
72
73    // templating
74    #[cfg(feature = "templating")]
75    let tera_templating = {
76        let tpl_dir = crate::helpers::fs::get_cwd() + "/resources/templates/**/*.tera.html";
77        Tera::new(tpl_dir.as_str()).unwrap()
78    };
79
80    MedullahState {
81        helpers,
82
83        app_id: env::var(format!("{}_APP_ID", env_prefix)).unwrap(),
84        app_domain: env::var(format!("{}_APP_DOMAIN", env_prefix)).unwrap(),
85        app_name: env::var(format!("{}_APP_NAME", env_prefix)).unwrap(),
86        app_desc: env::var(format!("{}_APP_DESC", env_prefix)).unwrap(),
87        app_help_email: env::var(format!("{}_APP_HELP_EMAIL", env_prefix)).unwrap(),
88        app_frontend_url: env::var(format!("{}_FRONTEND_ADDRESS", env_prefix)).unwrap(),
89
90        app_private_key: setup.private_key,
91        app_public_key: setup.public_key,
92        app_key: env::var(format!("{}_APP_KEY", env_prefix)).unwrap(),
93
94        #[cfg(feature = "redis")]
95        redis_pool,
96        #[cfg(feature = "redis")]
97        redis: redis.clone(),
98        #[cfg(feature = "rabbitmq")]
99        rabbitmq_pool,
100        #[cfg(feature = "rabbitmq")]
101        rabbitmq,
102        #[cfg(feature = "database")]
103        database: database_pool,
104        #[cfg(feature = "templating")]
105        tera: tera_templating,
106
107        #[cfg(feature = "jwt")]
108        auth_iss_public_key: setup.auth_iss_public_key,
109        #[cfg(feature = "jwt")]
110        auth_pat_prefix: env::var(format!("{}_AUTH_PAT_PREFIX", env_prefix)).unwrap(),
111        #[cfg(feature = "jwt")]
112        auth_token_lifetime: env::var(format!("{}_AUTH_TOKEN_LIFETIME", env_prefix))
113            .unwrap()
114            .parse()
115            .unwrap(),
116
117        allowed_origins: setup.allowed_origins,
118        allowed_methods: setup.allowed_methods,
119
120        #[cfg(feature = "mailer")]
121        mailer_config: make_mailer_config(&env_prefix),
122
123        services: AppServices {
124            #[cfg(feature = "redis")]
125            cache: Arc::new(CacheService::new(redis)),
126        },
127
128        app_env_prefix: env_prefix,
129    }
130}
131
132pub fn get_server_host_config(env_prefix: &String) -> (String, u16, usize) {
133    let host: String = env::var(format!("{}_SERVER_HOST", env_prefix)).unwrap();
134    let port: u16 = env::var(format!("{}_SERVER_PORT", env_prefix))
135        .unwrap()
136        .parse()
137        .unwrap();
138    let workers: usize = env::var(format!("{}_SERVER_WORKERS", env_prefix))
139        .unwrap()
140        .parse()
141        .unwrap();
142    (host, port, workers)
143}
144
145#[allow(unused_variables)]
146fn make_helpers(env_prefix: &str, setup: &MedullahSetup) -> AppHelpers {
147    #[cfg(feature = "crypto")]
148    let app_key = env::var(format!("{}_APP_KEY", env_prefix)).unwrap();
149
150    #[cfg(feature = "jwt")]
151    let token_lifetime: i64 = env::var(format!("{}_AUTH_TOKEN_LIFETIME", env_prefix))
152        .unwrap()
153        .parse()
154        .unwrap();
155
156    AppHelpers {
157        #[cfg(feature = "jwt")]
158        jwt: Arc::new(Jwt::new(
159            setup.auth_iss_public_key.clone(),
160            setup.private_key.clone(),
161            token_lifetime,
162        )),
163        #[cfg(feature = "crypto")]
164        password: Arc::new(Password::new(app_key)),
165    }
166}
167
168#[cfg(feature = "mailer")]
169fn make_mailer_config(env_prefix: &str) -> AppMailerConfig {
170    AppMailerConfig {
171        from_name: env::var(format!("{}_MAIL_FROM_NAME", env_prefix)).unwrap(),
172        from_email: env::var(format!("{}_MAIL_FROM_EMAIL", env_prefix)).unwrap(),
173        server_endpoint: env::var(format!("{}_MAILER_SERVER_ENDPOINT", env_prefix)).unwrap(),
174        server_auth_token: env::var(format!("{}_MAILER_SERVER_AUTH_TOKEN", env_prefix)).unwrap(),
175        server_application_id: env::var(format!("{}_MAILER_SERVER_APPLICATION_ID", env_prefix))
176            .unwrap(),
177    }
178}
179
180#[cfg(feature = "database")]
181pub fn establish_database_connection(env_prefix: &String) -> DBPool {
182    let db_url: String = env::var(format!("{}_DATABASE_DSN", env_prefix)).unwrap();
183    let manager = ConnectionManager::<PgConnection>::new(db_url);
184    r2d2::Pool::builder()
185        .build(manager)
186        .expect("Failed to create database pool.")
187}
188
189pub fn load_config_file(file: &str) -> String {
190    fs::read_to_string(format!("resources/config/{}", file)).unwrap()
191}
192
193pub fn load_environment_variables(service: &str) {
194    info!(
195        "log level: {:?}",
196        env::var("RUST_LOG").unwrap_or(String::from("info"))
197    );
198    info!("root directory: {:?}", service);
199
200    // load project level .env
201    let path = format!("apps/{}/.env", service);
202    dotenv::from_filename(path).ok();
203
204    // load project level .env.main
205    if Path::new(".env").exists() {
206        info!("loading env file: .env");
207        dotenv::from_filename(".env").ok();
208    }
209
210    // load project level .env.main
211    if Path::new(".env.main").exists() {
212        info!("loading env file: .env.main");
213        dotenv::from_filename(".env.main").ok();
214    }
215
216    // load project level .env.main
217    let filename = format!(".env.{}", service);
218    if Path::new(filename.as_str()).exists() {
219        info!("loading env file: {}", filename);
220        dotenv::from_filename(filename).ok();
221    }
222}