iqps_backend/
env.rs

1//! ### Environment Variables
2//!
3//!  Each field in the struct `EnvVars` corresponds to an environment variable. The environment variable name will be in all capitals. The default values are set using the `arg()` macro of the `clap` crate. Check the source code for the defaults.
4
5use std::path::PathBuf;
6
7use hmac::{digest::InvalidLength, Hmac, Mac};
8use sha2::Sha256;
9
10use crate::pathutils::Paths;
11
12#[derive(Clone)]
13pub struct EnvVars {
14    // Database
15    /// Database name
16    pub db_name: String,
17    /// Database hostname
18    pub db_host: String,
19    /// Database port
20    pub db_port: String,
21    /// Database username
22    pub db_user: String,
23    /// Database password
24    pub db_password: String,
25
26    // Auth
27    /// GitHub app client id (public token)
28    pub gh_client_id: String,
29    /// GitHub app client secret
30    pub gh_client_secret: String,
31    /// JWT encryption secret (make it a long, randomized string)
32    jwt_secret: String,
33    /// Github organization name
34    pub gh_org_name: String,
35    /// Github organization team slug (this team has access to admin dashboard)
36    pub gh_org_team_slug: String,
37    /// The usernames of the admins (additional to org team members, comma separated)
38    pub gh_admin_usernames: String,
39    /// URL of Slack webhook for sending notifications
40    pub slack_webhook_url: String, 
41
42    // Other configs
43    /// Maximum number of papers that can be uploaded at a time
44    pub max_upload_limit: usize,
45    /// Location where logs are stored
46    pub log_location: PathBuf,
47
48    // Paths
49    /// The URL of the static files server (odin's vault)
50    static_files_url: String,
51    /// The path where static files are served from
52    static_file_storage_location: PathBuf,
53    /// The path where uploaded papers are stored temporarily, relative to the `static_file_storage_location`
54    uploaded_qps_path: PathBuf,
55    /// The path where library papers (scrapped) are stored, relative to the `static_file_storage_location`
56    library_qps_path: PathBuf,
57
58    // Server
59    /// The port the server listens on
60    pub server_port: i32,
61
62    // CORS
63    /// List of origins allowed (as a list of values separated by commas `origin1, origin2`)
64    pub cors_allowed_origins: String,
65
66    /// All paths must be handled using this
67    pub paths: Paths,
68}
69
70impl EnvVars {    
71    /// Parses the environment variables into the struct
72    pub fn parse() -> Result<Self, Box<dyn std::error::Error>> {
73        let db_name = std::env::var("DB_NAME")?;
74        let db_host = std::env::var("DB_HOST")?;
75        let db_port = std::env::var("DB_PORT")?;
76        let db_user = std::env::var("DB_USER")?;
77        let db_password = std::env::var("DB_PASSWORD")?;
78        let gh_client_id = std::env::var("GH_CLIENT_ID")?;
79        let jwt_secret = std::env::var("JWT_SECRET")?;
80        let gh_client_secret = std::env::var("GH_CLIENT_SECRET")?;
81        let gh_org_name = std::env::var("GH_ORG_NAME").unwrap_or_default();
82        let gh_org_team_slug = std::env::var("GH_ORG_TEAM_SLUG").unwrap_or_default();
83        let gh_admin_usernames = std::env::var("GH_ADMIN_USERNAMES").unwrap_or_default();
84        let slack_webhook_url = std::env::var("SLACK_WEBHOOK_URL").unwrap_or_default();
85        let max_upload_limit = std::env::var("MAX_UPLOAD_LIMIT")
86            .unwrap_or_else(|_| "10".to_string())
87            .parse::<usize>()?;
88        let log_location = std::env::var("LOG_LOCATION")
89            .unwrap_or_else(|_| "./log/application.log".to_string())
90            .into();
91        let static_files_url = std::env::var("STATIC_FILES_URL")
92            .unwrap_or_else(|_| "https://static.metakgp.org".to_string());
93        let static_file_storage_location = std::env::var("STATIC_FILE_STORAGE_LOCATION")
94            .unwrap_or_else(|_| "/srv/static".to_string())
95            .into();
96        let uploaded_qps_path = std::env::var("UPLOADED_QPS_PATH")
97            .unwrap_or_else(|_| "/iqps/uploaded".to_string())
98            .into();
99        let library_qps_path = std::env::var("LIBRARY_QPS_PATH")
100            .unwrap_or_else(|_| "/peqp/qp".to_string())
101            .into();
102        let server_port = std::env::var("SERVER_PORT")
103            .unwrap_or_else(|_| "8080".to_string())
104            .parse::<i32>()?;
105        let cors_allowed_origins = std::env::var("CORS_ALLOWED_ORIGINS")
106            .unwrap_or_else(|_| "https://qp.metakgp.org,http://localhost:5173".to_string());
107        Ok(Self {
108            db_name,
109            db_host,
110            db_port,
111            db_user,
112            db_password,
113            gh_client_id,
114            jwt_secret,
115            gh_client_secret,
116            gh_org_name,
117            gh_org_team_slug,
118            gh_admin_usernames,
119            slack_webhook_url,
120            max_upload_limit,
121            log_location,
122            static_files_url,
123            static_file_storage_location,
124            uploaded_qps_path,
125            library_qps_path,
126            server_port,
127            cors_allowed_origins,
128            paths: Paths::default(),
129        })
130    }
131    
132    /// Processes the environment variables after reading.
133    pub fn process(mut self) -> Result<Self, Box<dyn std::error::Error>> {
134        self.paths = Paths::new(
135            &self.static_files_url,
136            &self.static_file_storage_location,
137            &self.uploaded_qps_path,
138            &self.library_qps_path,
139        )?;
140        self.log_location = std::path::absolute(self.log_location)?;
141
142        Ok(self)
143    }
144
145    /// Returns the JWT signing key
146    pub fn get_jwt_key(&self) -> Result<Hmac<Sha256>, InvalidLength> {
147        Hmac::new_from_slice(self.jwt_secret.as_bytes())
148    }
149}