Skip to main content

viser_ffmpeg/
cache.rs

1use std::collections::HashMap;
2use std::sync::Arc;
3use tokio::sync::RwLock;
4
5use crate::{ProbeResult, probe};
6
7/// Thread-safe probe result cache to avoid redundant ffprobe calls.
8#[derive(Debug, Clone)]
9pub struct ProbeCache {
10    cache: Arc<RwLock<HashMap<String, ProbeResult>>>,
11    engine: ProbeEngine,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum ProbeEngine {
16    Ffprobe,
17    #[cfg(feature = "revelo")]
18    Revelo,
19}
20
21impl ProbeCache {
22    pub fn new() -> Self {
23        Self { cache: Arc::default(), engine: ProbeEngine::Ffprobe }
24    }
25
26    #[cfg(feature = "revelo")]
27    pub fn with_revelo() -> Self {
28        Self { cache: Arc::default(), engine: ProbeEngine::Revelo }
29    }
30
31    pub fn with_engine(engine: ProbeEngine) -> Self {
32        Self { cache: Arc::default(), engine }
33    }
34
35    /// Returns cached result or calls ffprobe and caches the result.
36    pub async fn probe(&self, path: &str) -> anyhow::Result<ProbeResult> {
37        {
38            let cache = self.cache.read().await;
39            if let Some(result) = cache.get(path) {
40                return Ok(result.clone());
41            }
42        }
43
44        let result = match self.engine {
45            ProbeEngine::Ffprobe => probe(path).await?,
46            #[cfg(feature = "revelo")]
47            ProbeEngine::Revelo => crate::probe_revelo(path).await?,
48        };
49
50        {
51            let mut cache = self.cache.write().await;
52            cache.insert(path.to_string(), result.clone());
53        }
54
55        Ok(result)
56    }
57}
58
59impl Default for ProbeCache {
60    fn default() -> Self {
61        Self::new()
62    }
63}