Files
zclaw_openfang/desktop/src-tauri/src/classroom_commands/mod.rs
iven e10549a1b9 fix: 发布前审计 Batch 2 — Debug遮蔽 + unwrap + 静默吞错 + MCP锁 + 索引 + Config验证
安全:
- LlmConfig 自定义 Debug impl,api_key 显示为 "***REDACTED***"
- tsconfig.json 移除 ErrorBoundary.tsx 排除项(安全关键组件)
- billing/handlers.rs Response builder unwrap → map_err 错误传播
- classroom_commands/mod.rs db_path.parent().unwrap() → ok_or_else

静默吞错:
- approvals.rs 3处 warn→error(审批状态丢失是严重事件)
- events.rs publish() 添加 Event dropped debug 日志
- mcp_transport.rs eprintln→tracing::warn (僵尸进程风险)
- zclaw-growth sqlite.rs 4处迁移:区分 duplicate column name 与真实错误

MCP Transport:
- 合并 stdin+stdout 为单一 Mutex<TransportHandles>
- send_request write-then-read 原子化,防止并发响应错配

数据库:
- 新迁移 20260418000001: idx_rle_created_at + idx_billing_sub_plan + idx_ki_created_by

配置验证:
- SaaSConfig::load() 添加 jwt_expiration_hours>=1, max_connections>0, min<=max
2026-04-18 14:09:36 +08:00

68 lines
2.4 KiB
Rust

//! Classroom generation and interaction commands
//!
//! Tauri commands for the OpenMAIC-style interactive classroom:
//! - Generate classroom (4-stage pipeline with progress events)
//! - Multi-agent chat
//! - Export (HTML/Markdown/JSON)
use std::sync::Arc;
use tokio::sync::Mutex;
use tauri::Manager;
use zclaw_kernel::generation::Classroom;
pub mod chat;
pub mod export;
pub mod generate;
pub mod persist;
// ---------------------------------------------------------------------------
// Shared state types
// ---------------------------------------------------------------------------
/// In-memory classroom store: classroom_id → Classroom
pub type ClassroomStore = Arc<Mutex<std::collections::HashMap<String, Classroom>>>;
/// Active generation tasks: topic → progress
pub type GenerationTasks = Arc<Mutex<std::collections::HashMap<String, zclaw_kernel::generation::GenerationProgress>>>;
// Re-export chat state type
// Re-export chat state type — used by lib.rs to construct managed state
#[allow(unused_imports)]
pub use chat::ChatStore;
pub use persist::ClassroomPersistence;
// ---------------------------------------------------------------------------
// State constructors
// ---------------------------------------------------------------------------
pub fn create_classroom_state() -> ClassroomStore {
Arc::new(Mutex::new(std::collections::HashMap::new()))
}
pub fn create_generation_tasks() -> GenerationTasks {
Arc::new(Mutex::new(std::collections::HashMap::new()))
}
/// Create and initialize the classroom persistence layer, loading saved data.
pub async fn init_persistence(
app_handle: &tauri::AppHandle,
store: &ClassroomStore,
chat_store: &ChatStore,
) -> Result<ClassroomPersistence, String> {
let app_dir = app_handle
.path()
.app_data_dir()
.map_err(|e| format!("Failed to get app data dir: {}", e))?;
let db_path = app_dir.join("classroom").join("classrooms.db");
let db_dir = db_path.parent()
.ok_or_else(|| "Invalid classroom database path: no parent directory".to_string())?;
std::fs::create_dir_all(db_dir)
.map_err(|e| format!("Failed to create classroom dir: {}", e))?;
let persistence: ClassroomPersistence = ClassroomPersistence::open(db_path).await?;
let loaded = persistence.load_all(store, chat_store).await?;
tracing::info!("[ClassroomPersistence] Loaded {} classrooms from SQLite", loaded);
Ok(persistence)
}