Skip to main content

yggdrasil/api/settings/
system.rs

1// 与 posts 模块一致:Dioxus `#[server]` 宏触发 deprecated/unit/too_many_arguments
2// 提示,按项目惯例放行(限流/运行器等配置项天然参数多)。
3#![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;
9use crate::models::settings::SystemInfo;
10
11// ============================================================================
12// 系统启动配置(只读展示)
13// ============================================================================
14
15/// 读取系统启动配置的只读快照(面板展示用)。
16///
17/// 这些值在进程启动时读取,不可运行时修改。密钥类仅展示是否已设置。
18#[server(GetSystemInfo, "/api")]
19pub async fn get_system_info() -> Result<SystemInfo, ServerFnError> {
20    let _user = get_current_admin_user().await?;
21
22    #[cfg(feature = "server")]
23    {
24        // 脱敏 DATABASE_URL:隐藏密码,仅保留 scheme://host:port/dbname。
25        let database_url_masked = {
26            let url = std::env::var("DATABASE_URL").unwrap_or_default();
27            // 简单脱敏:如果含 @(即含密码),截取 @ 之后的部分 + scheme 前缀。
28            if let Some(at_pos) = url.find('@') {
29                let scheme_end = url.find("://").unwrap_or(0);
30                let after = &url[at_pos + 1..];
31                format!("{}://{}", &url[..scheme_end], after)
32            } else {
33                url
34            }
35        };
36
37        Ok(SystemInfo {
38            database_url_masked,
39            rust_log: std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string()),
40            db_pool_size: std::env::var("DB_POOL_SIZE")
41                .ok()
42                .and_then(|s| s.parse().ok())
43                .unwrap_or(20),
44            statement_timeout_secs: std::env::var("STATEMENT_TIMEOUT_SECS")
45                .ok()
46                .and_then(|s| s.parse().ok())
47                .unwrap_or(30),
48            ssr_cache_secs: std::env::var("SSR_CACHE_SECS")
49                .ok()
50                .and_then(|s| s.parse().ok())
51                .unwrap_or(3600),
52            compression_algorithms: std::env::var("COMPRESSION_ALGORITHMS").unwrap_or_default(),
53            expose_version_headers: std::env::var("EXPOSE_VERSION_HEADERS")
54                .map(|v| !matches!(v.as_str(), "0" | "false" | "no" | "off"))
55                .unwrap_or(true),
56            docker_socket_path: std::env::var("DOCKER_SOCKET_PATH")
57                .unwrap_or_else(|_| "/var/run/docker.sock".to_string()),
58            mcp_token_enc_key_set: std::env::var("MCP_TOKEN_ENC_KEY")
59                .map(|v| !v.is_empty())
60                .unwrap_or(false),
61            migrate_startup_timeout_secs: std::env::var("MIGRATE_STARTUP_TIMEOUT_SECS")
62                .ok()
63                .and_then(|s| s.parse().ok())
64                .unwrap_or(30),
65            sysinfo_sample_secs: std::env::var("SYSINFO_SAMPLE_SECS")
66                .ok()
67                .and_then(|s| s.parse().ok())
68                .unwrap_or(0.5),
69        })
70    }
71
72    #[cfg(not(feature = "server"))]
73    {
74        Ok(SystemInfo {
75            database_url_masked: String::new(),
76            rust_log: String::new(),
77            db_pool_size: 0,
78            statement_timeout_secs: 0,
79            ssr_cache_secs: 0,
80            compression_algorithms: String::new(),
81            expose_version_headers: false,
82            docker_socket_path: String::new(),
83            mcp_token_enc_key_set: false,
84            migrate_startup_timeout_secs: 0,
85            sysinfo_sample_secs: 0.0,
86        })
87    }
88}