MarkBase架构升级:Multi-Volume Virtual Tree + Dual-View Management + Git Remote修正
核心功能: - ✅ Categories/Series双视图管理(category_view.rs + import_markdown.rs) - ✅ FUSE Multi-Volume支持(tree_type参数) - ✅ SSH/SFTP/SCP/rsync协议完整实现(4042行) - ✅ NFS/SMB Module Phase 1-3完成 - ✅ Archive Module Phase 1-4完成(2916行) - ✅ Download Center API完整实现 - ✅ S3兼容API实现(560行) Git配置修正: - ✅ 删除错误origin(gitea.momentry.ddns.net) - ✅ 删除m5max128(指向机器名) - ✅ 设置origin = m5max128gitea.momentry.ddns.net/admin/markbase - ✅ 设置m4minigitea = m4minigitea.momentry.ddns.net/warren/markbase 数据清理: - ✅ 删除38个临时SQLite(保留accusys.sqlite、demo.sqlite) - ✅ 删除.bak、test_*.bin、调试脚本等临时文件 - ✅ 删除临时目录(build/、download files/、raid_test/等) - ✅ 更新.gitignore排除临时文件 架构优化: - 52个文件修改,2434行新增,4739行删除 - Workspace成员整合(16个crate) - 数据库状态:accusys.sqlite保留(主demo测试) 远程同步: - ✅ 准备推送到m5max128gitea(远程Gitea) - ✅ 准备推送到m4minigitea(本地Gitea)
This commit is contained in:
@@ -65,13 +65,21 @@ impl MarkBaseConfig {
|
||||
let config: MarkBaseConfig = toml::from_str(&content)?;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
|
||||
pub fn save(&self, path: &Path) -> Result<()> {
|
||||
// Create backup before saving
|
||||
if path.exists() {
|
||||
let backup_path = path.with_extension("toml.bak");
|
||||
std::fs::copy(path, &backup_path)?;
|
||||
log::info!("Backup created: {}", backup_path.display());
|
||||
}
|
||||
|
||||
let content = toml::to_string_pretty(self)?;
|
||||
std::fs::write(path, content)?;
|
||||
log::info!("Configuration saved to: {}", path.display());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn default_config() -> Self {
|
||||
Self {
|
||||
server: ServerConfig {
|
||||
@@ -98,7 +106,11 @@ impl MarkBaseConfig {
|
||||
default_password: "demo123".to_string(),
|
||||
},
|
||||
test: TestConfig {
|
||||
users: vec!["warren".to_string(), "momentry".to_string(), "demo".to_string()],
|
||||
users: vec![
|
||||
"warren".to_string(),
|
||||
"momentry".to_string(),
|
||||
"demo".to_string(),
|
||||
],
|
||||
password: "demo123".to_string(),
|
||||
login_test_iterations: 10,
|
||||
verify_test_iterations: 100,
|
||||
@@ -114,7 +126,7 @@ impl MarkBaseConfig {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn merge_env(&mut self) {
|
||||
if let Ok(host) = std::env::var("MB_HOST") {
|
||||
self.server.host = host;
|
||||
@@ -127,7 +139,7 @@ impl MarkBaseConfig {
|
||||
if let Ok(log_level) = std::env::var("MB_LOG_LEVEL") {
|
||||
self.server.log_level = log_level;
|
||||
}
|
||||
|
||||
|
||||
if let Ok(pg_host) = std::env::var("PG_HOST") {
|
||||
self.postgresql.host = pg_host;
|
||||
}
|
||||
@@ -145,7 +157,7 @@ impl MarkBaseConfig {
|
||||
if let Ok(pg_database) = std::env::var("PG_DATABASE") {
|
||||
self.postgresql.database = pg_database;
|
||||
}
|
||||
|
||||
|
||||
if let Ok(bcrypt_cost) = std::env::var("MB_BCRYPT_COST") {
|
||||
if let Ok(c) = bcrypt_cost.parse() {
|
||||
self.authentication.bcrypt_cost = c;
|
||||
@@ -157,7 +169,7 @@ impl MarkBaseConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn get(&self, key: &str) -> Option<String> {
|
||||
match key {
|
||||
"server.host" => Some(self.server.host.clone()),
|
||||
@@ -165,21 +177,27 @@ impl MarkBaseConfig {
|
||||
"server.log_level" => Some(self.server.log_level.clone()),
|
||||
"server.auth_db_path" => Some(self.server.auth_db_path.clone()),
|
||||
"server.users_db_dir" => Some(self.server.users_db_dir.clone()),
|
||||
|
||||
|
||||
"postgresql.host" => Some(self.postgresql.host.clone()),
|
||||
"postgresql.port" => Some(self.postgresql.port.to_string()),
|
||||
"postgresql.user" => Some(self.postgresql.user.clone()),
|
||||
"postgresql.password" => Some(self.postgresql.password.clone()),
|
||||
"postgresql.database" => Some(self.postgresql.database.clone()),
|
||||
"postgresql.connection_pool_size" => Some(self.postgresql.connection_pool_size.to_string()),
|
||||
|
||||
"postgresql.connection_pool_size" => {
|
||||
Some(self.postgresql.connection_pool_size.to_string())
|
||||
}
|
||||
|
||||
"authentication.bcrypt_cost" => Some(self.authentication.bcrypt_cost.to_string()),
|
||||
"authentication.token_validity_hours" => Some(self.authentication.token_validity_hours.to_string()),
|
||||
"authentication.token_validity_hours" => {
|
||||
Some(self.authentication.token_validity_hours.to_string())
|
||||
}
|
||||
"authentication.session_storage" => Some(self.authentication.session_storage.clone()),
|
||||
"authentication.max_sessions_per_user" => Some(self.authentication.max_sessions_per_user.to_string()),
|
||||
"authentication.max_sessions_per_user" => {
|
||||
Some(self.authentication.max_sessions_per_user.to_string())
|
||||
}
|
||||
"authentication.default_user" => Some(self.authentication.default_user.clone()),
|
||||
"authentication.default_password" => Some(self.authentication.default_password.clone()),
|
||||
|
||||
|
||||
"test.users" => Some(serde_json::to_string(&self.test.users).unwrap_or_default()),
|
||||
"test.password" => Some(self.test.password.clone()),
|
||||
"test.login_test_iterations" => Some(self.test.login_test_iterations.to_string()),
|
||||
@@ -187,16 +205,16 @@ impl MarkBaseConfig {
|
||||
"test.api_test_iterations" => Some(self.test.api_test_iterations.to_string()),
|
||||
"test.performance_report" => Some(self.test.performance_report.to_string()),
|
||||
"test.output_format" => Some(self.test.output_format.clone()),
|
||||
|
||||
|
||||
"logging.level" => Some(self.logging.level.clone()),
|
||||
"logging.file_path" => Some(self.logging.file_path.clone()),
|
||||
"logging.console_output" => Some(self.logging.console_output.to_string()),
|
||||
"logging.structured_logging" => Some(self.logging.structured_logging.to_string()),
|
||||
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn set(&mut self, key: &str, value: &str) -> Result<()> {
|
||||
match key {
|
||||
"server.host" => self.server.host = value.to_string(),
|
||||
@@ -204,60 +222,138 @@ impl MarkBaseConfig {
|
||||
"server.log_level" => self.server.log_level = value.to_string(),
|
||||
"server.auth_db_path" => self.server.auth_db_path = value.to_string(),
|
||||
"server.users_db_dir" => self.server.users_db_dir = value.to_string(),
|
||||
|
||||
|
||||
"postgresql.host" => self.postgresql.host = value.to_string(),
|
||||
"postgresql.port" => self.postgresql.port = value.parse()?,
|
||||
"postgresql.user" => self.postgresql.user = value.to_string(),
|
||||
"postgresql.password" => self.postgresql.password = value.to_string(),
|
||||
"postgresql.database" => self.postgresql.database = value.to_string(),
|
||||
"postgresql.connection_pool_size" => self.postgresql.connection_pool_size = value.parse()?,
|
||||
|
||||
"postgresql.connection_pool_size" => {
|
||||
self.postgresql.connection_pool_size = value.parse()?
|
||||
}
|
||||
|
||||
"authentication.bcrypt_cost" => self.authentication.bcrypt_cost = value.parse()?,
|
||||
"authentication.token_validity_hours" => self.authentication.token_validity_hours = value.parse()?,
|
||||
"authentication.session_storage" => self.authentication.session_storage = value.to_string(),
|
||||
"authentication.max_sessions_per_user" => self.authentication.max_sessions_per_user = value.parse()?,
|
||||
"authentication.token_validity_hours" => {
|
||||
self.authentication.token_validity_hours = value.parse()?
|
||||
}
|
||||
"authentication.session_storage" => {
|
||||
self.authentication.session_storage = value.to_string()
|
||||
}
|
||||
"authentication.max_sessions_per_user" => {
|
||||
self.authentication.max_sessions_per_user = value.parse()?
|
||||
}
|
||||
"authentication.default_user" => self.authentication.default_user = value.to_string(),
|
||||
"authentication.default_password" => self.authentication.default_password = value.to_string(),
|
||||
|
||||
"authentication.default_password" => {
|
||||
self.authentication.default_password = value.to_string()
|
||||
}
|
||||
|
||||
"test.password" => self.test.password = value.to_string(),
|
||||
"test.login_test_iterations" => self.test.login_test_iterations = value.parse()?,
|
||||
"test.verify_test_iterations" => self.test.verify_test_iterations = value.parse()?,
|
||||
"test.api_test_iterations" => self.test.api_test_iterations = value.parse()?,
|
||||
"test.performance_report" => self.test.performance_report = value.parse()?,
|
||||
"test.output_format" => self.test.output_format = value.to_string(),
|
||||
|
||||
|
||||
"logging.level" => self.logging.level = value.to_string(),
|
||||
"logging.file_path" => self.logging.file_path = value.to_string(),
|
||||
"logging.console_output" => self.logging.console_output = value.parse()?,
|
||||
"logging.structured_logging" => self.logging.structured_logging = value.parse()?,
|
||||
|
||||
|
||||
_ => return Err(anyhow::anyhow!("Invalid config key: {}", key)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn validate(&self) -> Result<()> {
|
||||
if self.server.port < 1024 {
|
||||
return Err(anyhow::anyhow!("Invalid server port: {}. Must be >= 1024", self.server.port));
|
||||
return Err(anyhow::anyhow!(
|
||||
"Invalid server port: {}. Must be >= 1024",
|
||||
self.server.port
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
if self.server.host.is_empty() {
|
||||
return Err(anyhow::anyhow!("server.host cannot be empty"));
|
||||
}
|
||||
|
||||
if self.server.auth_db_path.is_empty() {
|
||||
return Err(anyhow::anyhow!("server.auth_db_path cannot be empty"));
|
||||
}
|
||||
|
||||
if self.server.users_db_dir.is_empty() {
|
||||
return Err(anyhow::anyhow!("server.users_db_dir cannot be empty"));
|
||||
}
|
||||
|
||||
if self.postgresql.port == 0 {
|
||||
return Err(anyhow::anyhow!("Invalid PostgreSQL port: {}", self.postgresql.port));
|
||||
return Err(anyhow::anyhow!(
|
||||
"Invalid PostgreSQL port: {}",
|
||||
self.postgresql.port
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
if self.postgresql.host.is_empty() {
|
||||
return Err(anyhow::anyhow!("postgresql.host cannot be empty"));
|
||||
}
|
||||
|
||||
if self.postgresql.user.is_empty() {
|
||||
return Err(anyhow::anyhow!("postgresql.user cannot be empty"));
|
||||
}
|
||||
|
||||
if self.postgresql.database.is_empty() {
|
||||
return Err(anyhow::anyhow!("postgresql.database cannot be empty"));
|
||||
}
|
||||
|
||||
if self.postgresql.connection_pool_size == 0 {
|
||||
return Err(anyhow::anyhow!(
|
||||
"postgresql.connection_pool_size must be >= 1"
|
||||
));
|
||||
}
|
||||
|
||||
if self.authentication.bcrypt_cost < 4 || self.authentication.bcrypt_cost > 31 {
|
||||
return Err(anyhow::anyhow!("Invalid bcrypt_cost: {}. Must be 4-31", self.authentication.bcrypt_cost));
|
||||
return Err(anyhow::anyhow!(
|
||||
"Invalid bcrypt_cost: {}. Must be 4-31",
|
||||
self.authentication.bcrypt_cost
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
if self.authentication.token_validity_hours == 0 {
|
||||
return Err(anyhow::anyhow!("Invalid token_validity_hours: {}. Must be >= 1",
|
||||
self.authentication.token_validity_hours));
|
||||
return Err(anyhow::anyhow!(
|
||||
"Invalid token_validity_hours: {}. Must be >= 1",
|
||||
self.authentication.token_validity_hours
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
if self.authentication.default_user.is_empty() {
|
||||
return Err(anyhow::anyhow!("authentication.default_user cannot be empty"));
|
||||
}
|
||||
|
||||
if self.authentication.default_password.is_empty() {
|
||||
return Err(anyhow::anyhow!("authentication.default_password cannot be empty"));
|
||||
}
|
||||
|
||||
if self.authentication.max_sessions_per_user == 0 {
|
||||
return Err(anyhow::anyhow!(
|
||||
"authentication.max_sessions_per_user must be >= 1"
|
||||
));
|
||||
}
|
||||
|
||||
if self.test.users.is_empty() {
|
||||
return Err(anyhow::anyhow!("test.users must not be empty"));
|
||||
}
|
||||
|
||||
|
||||
if self.logging.level.is_empty() {
|
||||
return Err(anyhow::anyhow!("logging.level cannot be empty"));
|
||||
}
|
||||
|
||||
let valid_log_levels = ["trace", "debug", "info", "warn", "error", "off"];
|
||||
if !valid_log_levels.contains(&self.logging.level.as_str()) {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Invalid logging.level: {}. Must be one of: {}",
|
||||
self.logging.level,
|
||||
valid_log_levels.join(", ")
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user