librcekunit 1.0.1

a pure library implementation into rust programming language for admin panel cekunit
Documentation
use crate::handler::error::ApiError;
use directories::ProjectDirs;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CacheData {
    pub cookies: Vec<Cookie>,
    pub csrf_token: String,
    pub logged_in: bool,
    pub timestamp: i64,
}
impl CacheData {
    pub fn with_csrf_token(mut self, new_token: String) -> Self {
        self.csrf_token = new_token;
        self.timestamp = now();
        self
    }
    pub fn is_fresh(&self, max_age_seconds: i64) -> bool {
        now() - self.timestamp < max_age_seconds
    }
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Cookie {
    pub name: String,
    pub value: String,
    pub domain: String,
    pub path: String,
    pub http_only: bool,
    pub secure: bool,
}
#[derive(Clone)]
pub struct CacheManager {
    cache_dir: PathBuf,
    cache_file: PathBuf,
}
impl CacheManager {
    pub fn new() -> Result<Self, ApiError> {
        let proj_dirs = ProjectDirs::from("com", "cekunit", "libcekunit")
            .ok_or_else(|| ApiError::CacheError("Cannot determine cache directory".to_string()))?;
        let cache_dir = proj_dirs.cache_dir().to_path_buf();
        let cache_file = cache_dir.join("session.json");
        fs::create_dir_all(&cache_dir)
            .map_err(|e| ApiError::CacheError(format!("Failed to create cache dir: {}", e)))?;
        Ok(Self {
            cache_dir,
            cache_file,
        })
    }
    pub fn with_paths(cache_dir: PathBuf, cache_file: PathBuf) -> Self {
        Self {
            cache_dir,
            cache_file,
        }
    }
    pub fn save(&self, data: &CacheData) -> Result<(), ApiError> {
        let json = serde_json::to_string_pretty(data)?;
        fs::write(&self.cache_file, json)
            .map_err(|e| ApiError::CacheError(format!("Failed to write cache: {}", e)))
    }
    pub fn load(&self) -> Result<Option<CacheData>, ApiError> {
        if !self.cache_file.exists() {
            return Ok(None);
        }
        let content = fs::read_to_string(&self.cache_file)
            .map_err(|e| ApiError::CacheError(format!("Failed to read cache: {}", e)))?;
        let data: CacheData = serde_json::from_str(&content)?;
        Ok(Some(data))
    }
    pub fn clear(&self) -> Result<(), ApiError> {
        if self.cache_file.exists() {
            fs::remove_file(&self.cache_file)
                .map_err(|e| ApiError::CacheError(format!("Failed to clear cache: {}", e)))?;
        }
        Ok(())
    }
    pub fn update_csrf_token(&self, new_token: String) -> Result<(), ApiError> {
        if let Some(data) = self.load()? {
            let updated = data.with_csrf_token(new_token);
            self.save(&updated)?;
        }
        Ok(())
    }
    pub fn load_fresh(&self, max_age_seconds: i64) -> Result<Option<CacheData>, ApiError> {
        match self.load()? {
            Some(data) if data.is_fresh(max_age_seconds) => Ok(Some(data)),
            _ => Ok(None),
        }
    }
    pub fn cache_file_path(&self) -> &Path {
        &self.cache_file
    }
    pub fn cache_dir_path(&self) -> &Path {
        &self.cache_dir
    }
}
impl Default for CacheManager {
    fn default() -> Self {
        Self::new().unwrap_or_else(|_| {
            let dir = PathBuf::from("./cache");
            let _ = fs::create_dir_all(&dir);
            Self {
                cache_dir: dir.clone(),
                cache_file: dir.join("session.json"),
            }
        })
    }
}
fn now() -> i64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap_or_default()
        .as_secs() as i64
}