yggdrasil/api/settings/
webp.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::WebpSettings;
14
15#[cfg(feature = "server")]
25pub(crate) async fn seed_webp_settings_from_env(
26 client: &tokio_postgres::Client,
27) -> Result<(), AppError> {
28 use crate::models::settings as m;
29
30 let mut seeds: Vec<(&'static str, String)> = Vec::new();
31
32 if let Ok(v) = std::env::var("WEBP_QUALITY") {
33 match v.trim().parse::<f32>() {
34 Ok(q) => seeds.push((
35 "webp_quality",
36 m::WebpSettings::clamp_quality(q).to_string(),
37 )),
38 Err(_) => tracing::warn!("WEBP_QUALITY={v:?} 非法(期望浮点数),跳过"),
39 }
40 }
41 if let Ok(v) = std::env::var("WEBP_METHOD") {
42 match v.trim().parse::<u32>() {
43 Ok(n) => seeds.push(("webp_method", m::WebpSettings::clamp_method(n).to_string())),
44 Err(_) => tracing::warn!("WEBP_METHOD={v:?} 非法(期望非负整数),跳过"),
45 }
46 }
47
48 for (key, value) in seeds {
49 client
50 .execute(
51 "INSERT INTO settings (key, value) VALUES ($1, $2) ON CONFLICT (key) DO NOTHING",
52 &[&key, &value],
53 )
54 .await
55 .map_err(AppError::query)?;
56 tracing::info!("WebP 配置已从环境变量播种: {key}={value}(仅键缺失时生效)");
57 }
58 Ok(())
59}
60
61#[cfg(feature = "server")]
66pub(crate) async fn load_webp_settings(
67 client: &tokio_postgres::Client,
68) -> Result<WebpSettings, AppError> {
69 use crate::models::settings as m;
70
71 async fn read_key(
72 client: &tokio_postgres::Client,
73 key: &str,
74 ) -> Result<Option<String>, AppError> {
75 let row = client
76 .query_opt("SELECT value FROM settings WHERE key = $1", &[&key])
77 .await
78 .map_err(AppError::query)?;
79 Ok(row.map(|r| r.get::<_, String>("value")))
80 }
81
82 let quality = read_key(client, "webp_quality")
83 .await?
84 .and_then(|v| v.parse().ok())
85 .map(m::WebpSettings::clamp_quality)
86 .unwrap_or(m::DEFAULT_WEBP_QUALITY);
87 let method = read_key(client, "webp_method")
88 .await?
89 .and_then(|v| v.parse().ok())
90 .map(m::WebpSettings::clamp_method)
91 .unwrap_or(m::DEFAULT_WEBP_METHOD);
92
93 Ok(WebpSettings { quality, method })
94}
95
96#[server(GetWebpSettings, "/api")]
98pub async fn get_webp_settings() -> Result<WebpSettings, ServerFnError> {
99 let _user = get_current_admin_user().await?;
100
101 #[cfg(feature = "server")]
102 {
103 let client = get_conn().await.map_err(AppError::db_conn)?;
104 let s = load_webp_settings(&client)
105 .await
106 .map_err(ServerFnError::from)?;
107 Ok(s)
108 }
109
110 #[cfg(not(feature = "server"))]
111 {
112 Ok(WebpSettings::default())
113 }
114}
115
116#[server(UpdateWebpSettings, "/api")]
121pub async fn update_webp_settings(
122 quality: f32,
123 method: u32,
124) -> Result<WebpSettings, ServerFnError> {
125 let _user = get_current_admin_user().await?;
126
127 let quality = WebpSettings::clamp_quality(quality);
128 let method = WebpSettings::clamp_method(method);
129
130 #[cfg(feature = "server")]
131 {
132 let client = get_conn().await.map_err(AppError::db_conn)?;
133
134 for (key, value) in [
135 ("webp_quality", quality.to_string()),
136 ("webp_method", method.to_string()),
137 ] {
138 client
139 .execute(
140 "INSERT INTO settings (key, value, updated_at) VALUES ($1, $2, NOW())
141 ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW()",
142 &[&key, &value],
143 )
144 .await
145 .map_err(AppError::query)?;
146 }
147
148 tracing::info!(
149 "WebP settings updated (需重启生效): quality={}, method={}",
150 quality,
151 method
152 );
153 }
154
155 Ok(WebpSettings { quality, method })
156}