1use std::{collections::HashMap, path::PathBuf, sync::Arc};
2use tracing::debug;
3
4use crate::{CacheError, CacheResult};
5use tokio::sync::oneshot;
6
7#[derive(Debug)]
8pub enum CacheRequest {
9 CacheImage {
10 path: PathBuf,
11 response_tx: oneshot::Sender<CacheResult<()>>, },
13 GetImage {
14 path: PathBuf,
15 response_tx: oneshot::Sender<CacheResult<Arc<DynamicImage>>>,
16 },
17}
18
19pub struct CacheHandle {
21 request_tx: tokio::sync::mpsc::UnboundedSender<CacheRequest>,
22}
23
24impl CacheHandle {
25 pub fn new(
26 request_tx: tokio::sync::mpsc::UnboundedSender<CacheRequest>,
27 ) -> Self {
28 Self { request_tx }
29 }
30
31 pub fn get_image(&self, path: PathBuf) -> CacheResult<Arc<DynamicImage>> {
33 let (response_tx, response_rx) = oneshot::channel();
35
36 self.request_tx
38 .send(CacheRequest::GetImage { path, response_tx })
39 .map_err(|_| {
40 crate::CacheError::Config(
41 "Cache manager is shutdown".to_string(),
42 )
43 })?;
44
45 response_rx.blocking_recv().map_err(|_| {
47 crate::CacheError::Config(
48 "Cache manager stopped responding".to_string(),
49 )
50 })?
51 }
52
53 pub fn cache_image(&self, path: PathBuf) -> CacheResult<()> {
54 let (response_tx, _response_rx) = oneshot::channel();
55
56 self.request_tx
57 .send(CacheRequest::CacheImage { path, response_tx })
58 .map_err(|_| {
59 crate::CacheError::Config(
60 "Cache manager is shutdown".to_string(),
61 )
62 })?;
63
64 Ok(())
65 }
66}
67
68use image::DynamicImage;
69
70#[derive(Clone, Debug)]
71pub struct CacheConfig {
72 pub max_image_count: usize,
73 pub thread_count: usize,
74}
75
76impl Default for CacheConfig {
77 fn default() -> Self {
78 Self { max_image_count: 100, thread_count: 4 }
79 }
80}
81
82pub(crate) struct CacheState {
83 pub entries: HashMap<PathBuf, DynamicImage>,
84 pub lru_list: Vec<PathBuf>,
85}
86
87impl CacheState {
88 pub fn new() -> Self {
89 debug!("Initializing new cache state");
90
91 Self { entries: HashMap::new(), lru_list: Vec::new() }
92 }
93}
94
95impl CacheConfig {
96 const MAX_IMAGE_COUNT: usize = 1000;
97 const MAX_THREAD_COUNT: usize = 32;
98 const MIN_IMAGE_COUNT: usize = 10;
99 const MIN_THREAD_COUNT: usize = 1;
100
101 pub fn validate(&self) -> CacheResult<()> {
102 if self.thread_count < Self::MIN_THREAD_COUNT
103 || self.thread_count > Self::MAX_THREAD_COUNT
104 {
105 return Err(CacheError::Config(format!(
106 "Thread count must be between {} and {}",
107 Self::MIN_THREAD_COUNT,
108 Self::MAX_THREAD_COUNT
109 )));
110 }
111
112 if self.max_image_count < Self::MIN_IMAGE_COUNT
113 || self.max_image_count > Self::MAX_IMAGE_COUNT
114 {
115 return Err(CacheError::Config(format!(
116 "Max image count must be between {} and {}",
117 Self::MIN_IMAGE_COUNT,
118 Self::MAX_IMAGE_COUNT
119 )));
120 }
121
122 Ok(())
123 }
124}