yggdrasil/api/settings/
image_cache.rs1#![allow(clippy::unused_unit, deprecated, clippy::too_many_arguments)]
4
5use dioxus::prelude::*;
6
7#[cfg(feature = "server")]
8use crate::api::auth::get_current_admin_user;
9#[cfg(feature = "server")]
10use crate::api::error::AppError;
11#[cfg(feature = "server")]
12use crate::db::pool::get_conn;
13use crate::models::settings::ImageCacheSettings;
14#[cfg(feature = "server")]
16use crate::cache::invalidate_image_cache_settings;
17
18#[cfg(feature = "server")]
26pub(crate) async fn seed_image_cache_settings_from_env(
27 client: &tokio_postgres::Client,
28) -> Result<(), AppError> {
29 let mut seeds: Vec<(&'static str, String)> = Vec::new();
30
31 if let Ok(v) = std::env::var("IMAGE_DISK_CACHE_MAX_MB") {
32 match v.trim().parse::<u32>() {
33 Ok(n) => seeds.push((
34 "image_disk_cache_max_mb",
35 crate::models::settings::ImageCacheSettings::clamp_max_mb(n).to_string(),
36 )),
37 Err(_) => tracing::warn!("IMAGE_DISK_CACHE_MAX_MB={v:?} 非法(期望正整数),跳过"),
38 }
39 }
40 if let Ok(v) = std::env::var("IMAGE_DISK_CACHE_MAX_AGE_HOURS") {
41 match v.trim().parse::<u32>() {
42 Ok(n) => seeds.push((
43 "image_disk_cache_max_age_hours",
44 crate::models::settings::ImageCacheSettings::clamp_max_age_hours(n).to_string(),
45 )),
46 Err(_) => {
47 tracing::warn!("IMAGE_DISK_CACHE_MAX_AGE_HOURS={v:?} 非法(期望正整数),跳过")
48 }
49 }
50 }
51
52 super::insert_env_seeds(client, seeds).await
53}
54
55#[cfg(feature = "server")]
57pub(crate) async fn load_image_cache_settings(
58 client: &tokio_postgres::Client,
59) -> Result<crate::models::settings::ImageCacheSettings, AppError> {
60 let values = super::load_setting_values(
61 client,
62 &["image_disk_cache_max_mb", "image_disk_cache_max_age_hours"],
63 )
64 .await?;
65
66 let disk_cache_max_mb = values
67 .get("image_disk_cache_max_mb")
68 .and_then(|v| v.parse().ok())
69 .map(crate::models::settings::ImageCacheSettings::clamp_max_mb)
70 .unwrap_or(crate::models::settings::DEFAULT_IMAGE_DISK_CACHE_MAX_MB);
71 let disk_cache_max_age_hours = values
72 .get("image_disk_cache_max_age_hours")
73 .and_then(|v| v.parse().ok())
74 .map(crate::models::settings::ImageCacheSettings::clamp_max_age_hours)
75 .unwrap_or(crate::models::settings::DEFAULT_IMAGE_DISK_CACHE_MAX_AGE_HOURS);
76
77 Ok(crate::models::settings::ImageCacheSettings {
78 disk_cache_max_mb,
79 disk_cache_max_age_hours,
80 })
81}
82
83#[cfg(feature = "server")]
85pub(crate) async fn runtime_image_cache_settings() -> crate::models::settings::ImageCacheSettings {
86 if let Some(s) = crate::cache::get_image_cache_settings().await {
87 return s;
88 }
89 let fallback = crate::models::settings::ImageCacheSettings::default();
90 if std::env::var("DATABASE_URL").is_err() {
93 return fallback;
94 }
95 match get_conn().await {
96 Ok(client) => match load_image_cache_settings(&client).await {
97 Ok(s) => {
98 crate::cache::set_image_cache_settings(s.clone()).await;
99 s
100 }
101 Err(e) => {
102 tracing::warn!("读取图片缓存配置失败,回退默认值:{e:?}");
103 fallback
104 }
105 },
106 Err(e) => {
107 tracing::warn!("获取连接读取图片缓存配置失败,回退默认值:{e:?}");
108 fallback
109 }
110 }
111}
112
113#[server(GetImageCacheSettings, "/api")]
115pub async fn get_image_cache_settings() -> Result<ImageCacheSettings, ServerFnError> {
116 let _user = get_current_admin_user().await?;
117
118 #[cfg(feature = "server")]
119 {
120 let client = get_conn().await.map_err(AppError::db_conn)?;
121 let s = load_image_cache_settings(&client)
122 .await
123 .map_err(ServerFnError::from)?;
124 crate::cache::set_image_cache_settings(s.clone()).await;
125 Ok(s)
126 }
127
128 #[cfg(not(feature = "server"))]
129 {
130 Ok(ImageCacheSettings::default())
131 }
132}
133
134#[server(UpdateImageCacheSettings, "/api")]
136pub async fn update_image_cache_settings(
137 disk_cache_max_mb: u32,
138 disk_cache_max_age_hours: u32,
139) -> Result<ImageCacheSettings, ServerFnError> {
140 let _user = get_current_admin_user().await?;
141
142 let disk_cache_max_mb = ImageCacheSettings::clamp_max_mb(disk_cache_max_mb);
143 let disk_cache_max_age_hours =
144 ImageCacheSettings::clamp_max_age_hours(disk_cache_max_age_hours);
145
146 #[cfg(feature = "server")]
147 {
148 let client = get_conn().await.map_err(AppError::db_conn)?;
149
150 for (key, value) in [
151 ("image_disk_cache_max_mb", disk_cache_max_mb.to_string()),
152 (
153 "image_disk_cache_max_age_hours",
154 disk_cache_max_age_hours.to_string(),
155 ),
156 ] {
157 client
158 .execute(
159 "INSERT INTO settings (key, value, updated_at) VALUES ($1, $2, NOW())
160 ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW()",
161 &[&key, &value],
162 )
163 .await
164 .map_err(AppError::query)?;
165 }
166
167 invalidate_image_cache_settings();
168 tracing::info!(
169 "Image cache settings updated: max_mb={}, max_age_hours={}",
170 disk_cache_max_mb,
171 disk_cache_max_age_hours
172 );
173 }
174
175 Ok(ImageCacheSettings {
176 disk_cache_max_mb,
177 disk_cache_max_age_hours,
178 })
179}