use std::env;
use std::time::Duration;
mod mcp;
/// 前端可读取的应用配置。
///
/// 目前仅包含 UI 语言覆盖设置,来源于启动参数 `--ui-lang`:
/// - `"zh"`:强制使用中文 UI;
/// - `"en"`:强制使用英文 UI;
/// - `None`:未指定,由前端根据系统语言自行判定。
pub struct AppConfig {
pub ui_lang_override: Option<String>,
pub header_text_override: Option<String>,
}
/// 示例命令:用于验证前后端调用是否正常。
/// 该命令与 MCP 集成无关,可以在开发阶段用于简单测试。
#[tauri::command]
fn greet(name: &str) -> String {
format!("你好,{}!这是来自 Rust 的问候。", name)
}
/// 从启动参数中解析 UI 等待超时时间(单位:秒)。
///
/// - 参数格式:`--ui-timeout-seconds N`,其中 N 为整数秒;
/// - N > 0:返回 `Some(Duration::from_secs(N))`;
/// - 未传该参数、N <= 0 或解析失败:返回 `None`,表示不在 MCP 层做超时控制。
fn parse_ui_timeout_from_args() -> Option<Duration> {
let mut args = env::args().skip(1);
let mut ui_timeout: Option<Duration> = None;
while let Some(arg) = args.next() {
if arg == "--ui-timeout-seconds" {
if let Some(val) = args.next() {
if let Ok(secs) = val.parse::<i64>() {
if secs > 0 {
ui_timeout = Some(Duration::from_secs(secs as u64));
}
}
}
} else if let Some(rest) = arg.strip_prefix("--ui-timeout-seconds=") {
if let Ok(secs) = rest.parse::<i64>() {
if secs > 0 {
ui_timeout = Some(Duration::from_secs(secs as u64));
}
}
}
}
ui_timeout
}
/// 从启动参数中解析头部文案覆盖。
///
/// - 参数名:`--header-text`;
/// - 支持形式:`--header-text 值` 或 `--header-text=值`;
/// - 去除首尾空白后,若为空字符串则视为未设置(返回 `None`)。
fn parse_header_text_from_args() -> Option<String> {
let mut args = env::args().skip(1);
let mut header_text: Option<String> = None;
while let Some(arg) = args.next() {
if arg == "--ui-timeout-seconds" {
let _ = args.next();
continue;
}
if arg == "--ui-lang" {
let _ = args.next();
continue;
}
if arg == "--header-text" {
if let Some(val) = args.next() {
let trimmed = val.trim();
if !trimmed.is_empty() {
header_text = Some(trimmed.to_string());
}
}
} else if let Some(rest) = arg.strip_prefix("--header-text=") {
let trimmed = rest.trim();
if !trimmed.is_empty() {
header_text = Some(trimmed.to_string());
}
}
}
header_text
}
/// 从启动参数中解析 UI 语言设置。
///
/// - 参数名:`--ui-lang`;
/// - 支持形式:
/// - `--ui-lang zh` / `--ui-lang zh-CN` ⇒ `"zh"`;
/// - `--ui-lang en` / `--ui-lang en-US` ⇒ `"en"`;
/// - 若未传、或传入其他值(如 `jp`)则返回 `None`,由前端基于系统语言决定。
fn parse_ui_lang_from_args() -> Option<String> {
let mut args = env::args().skip(1);
let mut ui_lang: Option<String> = None;
while let Some(arg) = args.next() {
if arg == "--ui-timeout-seconds" {
// 跳过超时时间参数的值,由专用函数处理。
let _ = args.next();
continue;
}
if arg == "--ui-lang" {
if let Some(val) = args.next() {
let lower = val.to_ascii_lowercase();
if lower.starts_with("zh") {
ui_lang = Some("zh".to_string());
} else if lower.starts_with("en") {
ui_lang = Some("en".to_string());
}
}
} else if let Some(rest) = arg.strip_prefix("--ui-lang=") {
let lower = rest.to_ascii_lowercase();
if lower.starts_with("zh") {
ui_lang = Some("zh".to_string());
} else if lower.starts_with("en") {
ui_lang = Some("en".to_string());
}
}
}
ui_lang
}
/// 前端用于读取 UI 语言覆盖设置的命令。
///
/// 返回值为:
/// - `"zh"`:强制中文;
/// - `"en"`:强制英文;
/// - `null`:未设置,由前端自行根据系统语言判断。
#[tauri::command]
fn get_ui_lang_override(config: tauri::State<'_, AppConfig>) -> Option<String> {
config.ui_lang_override.clone()
}
/// 前端读取头部文案覆盖。
/// 返回值:
/// - `Some(String)`:使用该字符串替换默认 headerToolName;
/// - `None`:保持默认文案。
#[tauri::command]
fn get_header_text_override(config: tauri::State<'_, AppConfig>) -> Option<String> {
config.header_text_override.clone()
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
// 从启动参数中解析 UI 超时时间(单位:秒,大于 0 时生效)。
let ui_timeout = parse_ui_timeout_from_args();
// 从启动参数中解析 UI 语言覆盖设置。
let ui_lang_override = parse_ui_lang_from_args();
// 从启动参数中解析头部文案覆盖。
let header_text_override = parse_header_text_from_args();
// 创建 UI 桥接,用于在 rmcp 工具与 Tauri 命令之间共享一次性响应通道。
let ui_bridge = mcp::new_ui_bridge();
// 构造应用配置,并注入到 Tauri 全局状态中,供前端命令读取。
let app_config = AppConfig {
ui_lang_override,
header_text_override,
};
// 初始化窗口状态存储,负责窗口位置与尺寸持久化。
let window_state_store = mcp::window_state::WindowStateStore::initialize();
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
// 将 UI 桥接注入 Tauri 全局状态,供命令使用。
.manage(ui_bridge.clone())
.manage(window_state_store.clone())
// 注入应用配置(包括 UI 语言覆盖设置)。
.manage(app_config)
// 注册命令:包含示例 greet、MCP 交互用的 answer_interaction,
// 以及用于读取 UI 语言设置的 get_ui_lang_override。
.invoke_handler(tauri::generate_handler![
greet,
mcp::commands::answer_interaction,
mcp::commands::get_window_state,
mcp::commands::save_window_state,
get_ui_lang_override,
get_header_text_override
])
// 在应用启动时,启动 rmcp server 与 UI 管理任务。
.setup(move |app| {
let app_handle = app.handle().clone();
mcp::spawn_mcp_and_ui(
app_handle,
ui_bridge.clone(),
window_state_store.clone(),
ui_timeout,
);
Ok(())
})
.run(tauri::generate_context!())
.expect("运行 Tauri 应用时发生错误");
}