par_term/profile/dynamic/
cache.rs1use anyhow::Context;
7use serde::{Deserialize, Serialize};
8use sha2::{Digest, Sha256};
9use std::path::PathBuf;
10use std::time::SystemTime;
11
12pub fn cache_dir() -> PathBuf {
14 par_term_config::Config::config_dir()
15 .join("cache")
16 .join("dynamic_profiles")
17}
18
19pub fn url_to_cache_filename(url: &str) -> String {
21 let mut hasher = Sha256::new();
22 hasher.update(url.as_bytes());
23 let hash = hasher.finalize();
24 hash.iter().map(|b| format!("{:02x}", b)).collect()
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct CacheMeta {
30 pub url: String,
32 pub last_fetched: SystemTime,
34 pub etag: Option<String>,
36 pub profile_count: usize,
38}
39
40pub fn read_cache(url: &str) -> anyhow::Result<(Vec<par_term_config::Profile>, CacheMeta)> {
42 let dir = cache_dir();
43 let hash = url_to_cache_filename(url);
44 let data_path = dir.join(format!("{hash}.yaml"));
45 let meta_path = dir.join(format!("{hash}.meta"));
46
47 let data = std::fs::read_to_string(&data_path)
48 .with_context(|| format!("Failed to read cache data from {data_path:?}"))?;
49 let meta_str = std::fs::read_to_string(&meta_path)
50 .with_context(|| format!("Failed to read cache meta from {meta_path:?}"))?;
51
52 let profiles: Vec<par_term_config::Profile> =
53 serde_yaml_ng::from_str(&data).with_context(|| "Failed to parse cached profiles")?;
54 let meta: CacheMeta =
55 serde_json::from_str(&meta_str).with_context(|| "Failed to parse cache metadata")?;
56
57 Ok((profiles, meta))
58}
59
60pub fn write_cache(
62 url: &str,
63 profiles: &[par_term_config::Profile],
64 etag: Option<String>,
65) -> anyhow::Result<()> {
66 let dir = cache_dir();
67 std::fs::create_dir_all(&dir)
68 .with_context(|| format!("Failed to create cache directory {dir:?}"))?;
69
70 let hash = url_to_cache_filename(url);
71 let data_path = dir.join(format!("{hash}.yaml"));
72 let meta_path = dir.join(format!("{hash}.meta"));
73
74 crate::atomic_save::save_yaml_atomic(&data_path, profiles)
78 .with_context(|| format!("Failed to write cache data to {data_path:?}"))?;
79
80 let meta = CacheMeta {
81 url: url.to_string(),
82 last_fetched: SystemTime::now(),
83 etag,
84 profile_count: profiles.len(),
85 };
86 let meta_str = serde_json::to_string_pretty(&meta)
87 .with_context(|| "Failed to serialize cache metadata")?;
88 crate::atomic_save::save_string_atomic(&meta_path, &meta_str)
89 .with_context(|| format!("Failed to write cache meta to {meta_path:?}"))?;
90
91 Ok(())
92}