Files
csm/crates/server/src/config.rs
iven e99ea53eba feat: 全面重构前端UI及完善后端功能
前端重构:
- 重构Layout为左侧导航+顶栏的现代管理后台布局
- 重构设备管理页面(Devices.vue):左侧分组面板+右侧设备列表
- 重构设备详情(DeviceDetail.vue):集成硬件资产/软件资产/变更记录标签页
- 移除独立资产管理页面,功能合并至设备详情
- 重构Dashboard/登录/设置/告警/水印/上网管控等页面样式
- 新增全局CSS变量和统一样式系统
- 添加分组管理UI:新建/重命名/删除分组,移动设备到分组

后端完善:
- 新增分组CRUD API(groups.rs):创建/重命名/删除分组,设备分组移动
- 客户端硬件采集:完善GPU/主板/序列号/磁盘信息采集(Windows PowerShell)
- 客户端软件采集:通过Windows注册表读取已安装软件列表
- 新增SoftwareAssetReport消息类型(0x09)及处理链路
- 数据库新增upsert_software方法处理软件资产存储
- 服务端推送软件资产配置给新注册设备
- 修复密码修改功能,添加旧密码验证
2026-04-06 13:09:43 +08:00

135 lines
4.2 KiB
Rust

use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct AppConfig {
pub server: ServerConfig,
pub database: DatabaseConfig,
pub auth: AuthConfig,
pub retention: RetentionConfig,
#[serde(default)]
pub notify: NotifyConfig,
/// Token required for device registration. Empty = any token accepted.
#[serde(default)]
pub registration_token: String,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ServerConfig {
pub http_addr: String,
pub tcp_addr: String,
/// Allowed CORS origins. Empty = same-origin only (no CORS headers).
#[serde(default)]
pub cors_origins: Vec<String>,
/// Optional TLS configuration for the TCP listener.
#[serde(default)]
pub tls: Option<TlsConfig>,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct TlsConfig {
/// Path to the server certificate (PEM format)
pub cert_path: String,
/// Path to the server private key (PEM format)
pub key_path: String,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct DatabaseConfig {
pub path: String,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct AuthConfig {
pub jwt_secret: String,
#[serde(default = "default_access_ttl")]
pub access_token_ttl_secs: u64,
#[serde(default = "default_refresh_ttl")]
pub refresh_token_ttl_secs: u64,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct RetentionConfig {
#[serde(default = "default_status_history_days")]
pub status_history_days: u32,
#[serde(default = "default_usb_events_days")]
pub usb_events_days: u32,
#[serde(default = "default_asset_changes_days")]
pub asset_changes_days: u32,
#[serde(default = "default_alert_records_days")]
pub alert_records_days: u32,
#[serde(default = "default_audit_log_days")]
pub audit_log_days: u32,
}
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
pub struct NotifyConfig {
#[serde(default)]
pub smtp: Option<SmtpConfig>,
#[serde(default)]
pub webhook_urls: Vec<String>,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct SmtpConfig {
pub host: String,
pub port: u16,
pub username: String,
pub password: String,
pub from: String,
}
impl AppConfig {
pub async fn load(path: &str) -> Result<Self> {
if Path::new(path).exists() {
let content = tokio::fs::read_to_string(path).await?;
let config: AppConfig = toml::from_str(&content)?;
Ok(config)
} else {
let config = default_config();
// Write default config for reference
let toml_str = toml::to_string_pretty(&config)?;
tokio::fs::write(path, &toml_str).await?;
tracing::warn!("Created default config at {}", path);
Ok(config)
}
}
}
fn default_access_ttl() -> u64 { 1800 } // 30 minutes
fn default_refresh_ttl() -> u64 { 604800 } // 7 days
fn default_status_history_days() -> u32 { 7 }
fn default_usb_events_days() -> u32 { 90 }
fn default_asset_changes_days() -> u32 { 365 }
fn default_alert_records_days() -> u32 { 90 }
fn default_audit_log_days() -> u32 { 365 }
pub fn default_config() -> AppConfig {
AppConfig {
server: ServerConfig {
http_addr: "0.0.0.0:9998".into(),
tcp_addr: "0.0.0.0:9999".into(),
cors_origins: vec![],
tls: None,
},
database: DatabaseConfig {
path: "./csm.db".into(),
},
auth: AuthConfig {
jwt_secret: uuid::Uuid::new_v4().to_string(),
access_token_ttl_secs: default_access_ttl(),
refresh_token_ttl_secs: default_refresh_ttl(),
},
retention: RetentionConfig {
status_history_days: default_status_history_days(),
usb_events_days: default_usb_events_days(),
asset_changes_days: default_asset_changes_days(),
alert_records_days: default_alert_records_days(),
audit_log_days: default_audit_log_days(),
},
notify: NotifyConfig::default(),
registration_token: uuid::Uuid::new_v4().to_string(),
}
}