Skip to main content

memvid_cli/
ticket_cache.rs

1//! Local ticket caching
2//!
3//! This module provides functionality for caching tickets locally to avoid
4//! repeated API calls and enable offline usage.
5
6use std::fs;
7use std::path::PathBuf;
8
9use anyhow::{Context, Result};
10use serde::{Deserialize, Serialize};
11use uuid::Uuid;
12
13use crate::config::CliConfig;
14
15const CACHE_DIR_NAME: &str = "tickets";
16
17/// A cached ticket entry stored locally
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct CachedTicket {
20    pub memory_id: Uuid,
21    pub issuer: String,
22    pub seq_no: i64,
23    pub expires_in: u64,
24    #[serde(default)]
25    pub capacity_bytes: Option<u64>,
26    pub signature: String,
27}
28
29pub fn store(config: &CliConfig, entry: &CachedTicket) -> Result<()> {
30    let path = cache_path(config, &entry.memory_id);
31    if let Some(parent) = path.parent() {
32        fs::create_dir_all(parent).with_context(|| {
33            format!(
34                "failed to create ticket cache directory: {}",
35                parent.display()
36            )
37        })?;
38    }
39    let tmp = path.with_extension("json.tmp");
40    let data = serde_json::to_vec_pretty(entry)?;
41    fs::write(&tmp, data)
42        .with_context(|| format!("failed to write ticket cache file: {}", tmp.display()))?;
43    fs::rename(&tmp, &path).with_context(|| {
44        format!(
45            "failed to atomically persist ticket cache file: {}",
46            path.display()
47        )
48    })?;
49    Ok(())
50}
51
52pub fn load(config: &CliConfig, memory_id: &Uuid) -> Result<CachedTicket> {
53    let path = cache_path(config, memory_id);
54    let data = fs::read(&path)
55        .with_context(|| format!("no cached ticket available for memory {}", memory_id))?;
56    let entry = serde_json::from_slice(&data)
57        .with_context(|| format!("failed to parse cached ticket: {}", path.display()))?;
58    Ok(entry)
59}
60
61fn cache_path(config: &CliConfig, memory_id: &Uuid) -> PathBuf {
62    config
63        .cache_dir
64        .join(CACHE_DIR_NAME)
65        .join(format!("{memory_id}.json"))
66}