Skip to main content

mcp_gmailcal/
config.rs

1use crate::errors::ConfigError;
2use dotenv::dotenv;
3use log::debug;
4use std::env;
5
6#[derive(Debug, Clone)]
7pub struct Config {
8    pub client_id: String,
9    pub client_secret: String,
10    pub refresh_token: String,
11    pub access_token: Option<String>,
12    
13    /// Number of seconds before an access token expires that it should be refreshed.
14    /// Allows for proactive refresh to prevent working with nearly-expired tokens.
15    /// Can be configured with TOKEN_REFRESH_THRESHOLD_SECONDS environment variable.
16    pub token_refresh_threshold: u64,
17    
18    /// Buffer time in seconds subtracted from the token's expiration time to ensure
19    /// we don't use tokens too close to their expiry time. Provides a safety margin.
20    /// Can be configured with TOKEN_EXPIRY_BUFFER_SECONDS environment variable.
21    pub token_expiry_buffer: u64,
22}
23
24impl Config {
25    pub fn from_env() -> Result<Self, ConfigError> {
26        // Attempt to load .env file if present
27        // If DOTENV_PATH is set, use that path, otherwise use default
28        if let Ok(path) = std::env::var("DOTENV_PATH") {
29            let _ = dotenv::from_path(path);
30        } else {
31            let _ = dotenv();
32        }
33
34        debug!("Loading Gmail OAuth configuration from environment");
35
36        // Get required variables
37        let client_id = env::var("GMAIL_CLIENT_ID")
38            .map_err(|_| ConfigError::MissingEnvVar("GMAIL_CLIENT_ID".to_string()))?;
39
40        let client_secret = env::var("GMAIL_CLIENT_SECRET")
41            .map_err(|_| ConfigError::MissingEnvVar("GMAIL_CLIENT_SECRET".to_string()))?;
42
43        let refresh_token = env::var("GMAIL_REFRESH_TOKEN")
44            .map_err(|_| ConfigError::MissingEnvVar("GMAIL_REFRESH_TOKEN".to_string()))?;
45
46        // Get optional access token
47        let access_token = env::var("GMAIL_ACCESS_TOKEN").ok();
48        
49        // Get token expiry configuration with defaults
50        let token_refresh_threshold = get_token_refresh_threshold_seconds();
51        let token_expiry_buffer = get_token_expiry_buffer_seconds();
52        
53        debug!("OAuth configuration loaded successfully");
54        debug!("Token refresh threshold: {} seconds", token_refresh_threshold);
55        debug!("Token expiry buffer: {} seconds", token_expiry_buffer);
56
57        Ok(Config {
58            client_id,
59            client_secret,
60            refresh_token,
61            access_token,
62            token_refresh_threshold,
63            token_expiry_buffer,
64        })
65    }
66}
67
68// API URL constants
69pub const GMAIL_API_BASE_URL: &str = "https://gmail.googleapis.com/gmail/v1";
70pub const OAUTH_TOKEN_URL: &str = "https://oauth2.googleapis.com/token";
71
72// Configuration utility functions
73
74/// Returns the total token expiry time in seconds.
75/// 
76/// This value controls how long the application considers the token valid.
77/// Default is 3540 seconds (59 minutes) if not configured.
78/// 
79/// Environment variable: TOKEN_EXPIRY_SECONDS
80pub fn get_token_expiry_seconds() -> u64 {
81    std::env::var("TOKEN_EXPIRY_SECONDS")
82        .ok()
83        .and_then(|s| s.parse::<u64>().ok())
84        .unwrap_or(3540) // Default 59 minutes if not configured
85}
86
87/// Returns the buffer time in seconds subtracted from token expiry time.
88/// 
89/// This buffer ensures we don't use tokens that are too close to expiry.
90/// It's subtracted from the token's actual expiry time to create a safety margin.
91/// Default is 60 seconds (1 minute) if not configured.
92/// 
93/// Environment variable: TOKEN_EXPIRY_BUFFER_SECONDS
94pub fn get_token_expiry_buffer_seconds() -> u64 {
95    std::env::var("TOKEN_EXPIRY_BUFFER_SECONDS")
96        .ok()
97        .and_then(|s| s.parse::<u64>().ok())
98        .unwrap_or(60) // Default 1 minute if not configured
99}
100
101/// Returns the threshold in seconds before token expiry that a refresh should be triggered.
102/// 
103/// This controls how soon before a token expires that the application should proactively
104/// refresh it. This prevents using nearly-expired tokens which might expire during operations.
105/// Default is 300 seconds (5 minutes) if not configured.
106/// 
107/// Environment variable: TOKEN_REFRESH_THRESHOLD_SECONDS
108pub fn get_token_refresh_threshold_seconds() -> u64 {
109    std::env::var("TOKEN_REFRESH_THRESHOLD_SECONDS")
110        .ok()
111        .and_then(|s| s.parse::<u64>().ok())
112        .unwrap_or(300) // Default 5 minutes if not configured
113}