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 {
29 request_tx,
30 }
31 }
32
33 pub fn get_image(&self, path: PathBuf) -> CacheResult<Arc<DynamicImage>> {
35 let (response_tx, response_rx) = oneshot::channel();
37
38 self.request_tx
40 .send(CacheRequest::GetImage {
41 path,
42 response_tx,
43 })
44 .map_err(|_| {
45 crate::CacheError::Config(
46 "Cache manager is shutdown".to_string(),
47 )
48 })?;
49
50 response_rx.blocking_recv().map_err(|_| {
52 crate::CacheError::Config(
53 "Cache manager stopped responding".to_string(),
54 )
55 })?
56 }
57
58 pub fn cache_image(&self, path: PathBuf) -> CacheResult<()> {
59 let (response_tx, _response_rx) = oneshot::channel();
60
61 self.request_tx
62 .send(CacheRequest::CacheImage {
63 path,
64 response_tx,
65 })
66 .map_err(|_| {
67 crate::CacheError::Config(
68 "Cache manager is shutdown".to_string(),
69 )
70 })?;
71
72 Ok(())
73 }
74}
75
76use image::DynamicImage;
77
78#[derive(Clone)]
79pub struct CacheConfig {
80 pub max_image_count: usize,
81 pub thread_count: usize,
82}
83
84impl Default for CacheConfig {
85 fn default() -> Self {
86 Self {
87 max_image_count: 100, thread_count: 4
88 }
89 }
90}
91
92pub(crate) struct CacheState {
93 pub entries: HashMap<PathBuf, DynamicImage>,
94 pub lru_list: Vec<PathBuf>,
95}
96
97impl CacheState {
98 pub fn new() -> Self {
99 debug!("Initializing new cache state");
100
101 Self {
102 entries: HashMap::new(), lru_list: Vec::new()
103 }
104 }
105}
106
107impl CacheConfig {
108 const MAX_IMAGE_COUNT: usize = 1000;
109 const MAX_THREAD_COUNT: usize = 32;
110 const MIN_IMAGE_COUNT: usize = 10;
111 const MIN_THREAD_COUNT: usize = 1;
112
113 pub fn validate(&self) -> CacheResult<()> {
114 if self.thread_count < Self::MIN_THREAD_COUNT
115 || self.thread_count > Self::MAX_THREAD_COUNT
116 {
117 return Err(CacheError::Config(format!(
118 "Thread count must be between {} and {}",
119 Self::MIN_THREAD_COUNT,
120 Self::MAX_THREAD_COUNT
121 )));
122 }
123
124 if self.max_image_count < Self::MIN_IMAGE_COUNT
125 || self.max_image_count > Self::MAX_IMAGE_COUNT
126 {
127 return Err(CacheError::Config(format!(
128 "Max image count must be between {} and {}",
129 Self::MIN_IMAGE_COUNT,
130 Self::MAX_IMAGE_COUNT
131 )));
132 }
133
134 Ok(())
135 }
136}