6ef9d95172
- 创建 packages/desktop 模块 - 实现 Tauri 2.0 + React 桌面应用 - 复用 Web 前端代码 - 添加系统托盘功能 - 实现本地文件访问命令 - 配置 Vite + Tauri 集成 - 更新 .gitignore 添加 Rust/Tauri 相关规则
119 lines
2.8 KiB
Rust
119 lines
2.8 KiB
Rust
use serde::Serialize;
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
use std::sync::mpsc;
|
|
use tauri_plugin_dialog::DialogExt;
|
|
|
|
#[derive(Serialize)]
|
|
pub struct AppInfo {
|
|
pub name: String,
|
|
pub version: String,
|
|
pub tauri_version: String,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn get_app_info() -> AppInfo {
|
|
AppInfo {
|
|
name: "AI Assistant".to_string(),
|
|
version: env!("CARGO_PKG_VERSION").to_string(),
|
|
tauri_version: tauri::VERSION.to_string(),
|
|
}
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn open_directory_dialog(app: tauri::AppHandle) -> Result<Option<String>, String> {
|
|
let (tx, rx) = mpsc::channel();
|
|
|
|
app.dialog()
|
|
.file()
|
|
.set_title("Select Working Directory")
|
|
.pick_folder(move |path| {
|
|
let _ = tx.send(path);
|
|
});
|
|
|
|
match rx.recv() {
|
|
Ok(Some(path)) => Ok(Some(path.to_string())),
|
|
Ok(None) => Ok(None),
|
|
Err(e) => Err(e.to_string()),
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct FileContent {
|
|
pub path: String,
|
|
pub content: String,
|
|
pub size: u64,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn read_local_file(path: String) -> Result<FileContent, String> {
|
|
let path_buf = PathBuf::from(&path);
|
|
|
|
if !path_buf.exists() {
|
|
return Err(format!("File not found: {}", path));
|
|
}
|
|
|
|
let metadata = fs::metadata(&path_buf).map_err(|e| e.to_string())?;
|
|
|
|
if metadata.len() > 10 * 1024 * 1024 {
|
|
return Err("File too large (max 10MB)".to_string());
|
|
}
|
|
|
|
let content = fs::read_to_string(&path_buf).map_err(|e| e.to_string())?;
|
|
|
|
Ok(FileContent {
|
|
path,
|
|
content,
|
|
size: metadata.len(),
|
|
})
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct DirectoryEntry {
|
|
pub name: String,
|
|
pub path: String,
|
|
pub is_dir: bool,
|
|
pub size: u64,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn list_directory(path: String) -> Result<Vec<DirectoryEntry>, String> {
|
|
let path_buf = PathBuf::from(&path);
|
|
|
|
if !path_buf.exists() {
|
|
return Err(format!("Directory not found: {}", path));
|
|
}
|
|
|
|
if !path_buf.is_dir() {
|
|
return Err(format!("Not a directory: {}", path));
|
|
}
|
|
|
|
let mut entries = Vec::new();
|
|
|
|
let read_dir = fs::read_dir(&path_buf).map_err(|e| e.to_string())?;
|
|
|
|
for entry in read_dir {
|
|
let entry = entry.map_err(|e| e.to_string())?;
|
|
let metadata = entry.metadata().map_err(|e| e.to_string())?;
|
|
|
|
entries.push(DirectoryEntry {
|
|
name: entry.file_name().to_string_lossy().to_string(),
|
|
path: entry.path().to_string_lossy().to_string(),
|
|
is_dir: metadata.is_dir(),
|
|
size: metadata.len(),
|
|
});
|
|
}
|
|
|
|
entries.sort_by(|a, b| {
|
|
if a.is_dir == b.is_dir {
|
|
a.name.to_lowercase().cmp(&b.name.to_lowercase())
|
|
} else if a.is_dir {
|
|
std::cmp::Ordering::Less
|
|
} else {
|
|
std::cmp::Ordering::Greater
|
|
}
|
|
});
|
|
|
|
Ok(entries)
|
|
}
|