156 lines
4.2 KiB
Rust
156 lines
4.2 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use std::fs;
|
|
use std::fs::File;
|
|
use std::io::{Read, Write};
|
|
use std::path::{Path, PathBuf};
|
|
use tauri::{Emitter, Window};
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct FileItem {
|
|
pub name: String,
|
|
pub path: String,
|
|
pub is_dir: bool,
|
|
pub size: Option<u64>,
|
|
}
|
|
|
|
/// List files in a directory.
|
|
///
|
|
/// # Errors
|
|
/// Returns an error if the path does not exist or cannot be read.
|
|
#[tauri::command]
|
|
pub fn list_files(path: &str) -> Result<Vec<FileItem>, String> {
|
|
let base_path = Path::new(path);
|
|
let mut files = Vec::new();
|
|
|
|
if !base_path.exists() {
|
|
return Err("Path does not exist".into());
|
|
}
|
|
|
|
for entry in fs::read_dir(base_path).map_err(|e| e.to_string())? {
|
|
let entry = entry.map_err(|e| e.to_string())?;
|
|
let path = entry.path();
|
|
let metadata = entry.metadata().ok();
|
|
|
|
let name = path
|
|
.file_name()
|
|
.and_then(|n| n.to_str())
|
|
.unwrap_or("")
|
|
.to_string();
|
|
|
|
let size = metadata.as_ref().map(std::fs::Metadata::len);
|
|
let is_dir = metadata.is_some_and(|m| m.is_dir());
|
|
|
|
files.push(FileItem {
|
|
name,
|
|
path: path.to_str().unwrap_or("").to_string(),
|
|
is_dir,
|
|
size,
|
|
});
|
|
}
|
|
|
|
files.sort_by(|a, b| {
|
|
if a.is_dir && !b.is_dir {
|
|
std::cmp::Ordering::Less
|
|
} else if !a.is_dir && b.is_dir {
|
|
std::cmp::Ordering::Greater
|
|
} else {
|
|
a.name.to_lowercase().cmp(&b.name.to_lowercase())
|
|
}
|
|
});
|
|
|
|
Ok(files)
|
|
}
|
|
|
|
/// Upload a file to the specified destination.
|
|
///
|
|
/// # Errors
|
|
/// Returns an error if the source file is invalid or the copy operation fails.
|
|
#[tauri::command]
|
|
pub fn upload_file(window: Window, src_path: &str, dest_path: &str) -> Result<(), String> {
|
|
let src = PathBuf::from(src_path);
|
|
let dest_dir = PathBuf::from(dest_path);
|
|
let dest = dest_dir.join(src.file_name().ok_or("Invalid source file")?);
|
|
|
|
if !dest_dir.exists() {
|
|
fs::create_dir_all(&dest_dir).map_err(|e| e.to_string())?;
|
|
}
|
|
|
|
let mut source_file = File::open(&src).map_err(|e| e.to_string())?;
|
|
let mut dest_file = File::create(&dest).map_err(|e| e.to_string())?;
|
|
let file_size = source_file.metadata().map_err(|e| e.to_string())?.len();
|
|
|
|
let mut buffer = [0; 8192];
|
|
let mut total_read: u64 = 0;
|
|
|
|
loop {
|
|
let bytes_read = source_file.read(&mut buffer).map_err(|e| e.to_string())?;
|
|
if bytes_read == 0 {
|
|
break;
|
|
}
|
|
dest_file
|
|
.write_all(&buffer[..bytes_read])
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
total_read += bytes_read as u64;
|
|
|
|
let progress = if file_size > 0 {
|
|
(total_read * 100) / file_size
|
|
} else {
|
|
100
|
|
};
|
|
|
|
window
|
|
.emit("upload_progress", progress)
|
|
.map_err(|e| e.to_string())?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Create a new folder at the specified path.
|
|
///
|
|
/// # Errors
|
|
/// Returns an error if the folder already exists or cannot be created.
|
|
#[tauri::command]
|
|
pub fn create_folder(path: &str, name: &str) -> Result<(), String> {
|
|
let full_path = Path::new(path).join(name);
|
|
|
|
if full_path.exists() {
|
|
return Err("Folder already exists".into());
|
|
}
|
|
|
|
fs::create_dir(&full_path).map_err(|e| e.to_string())?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Delete a file or folder at the specified path.
|
|
///
|
|
/// # Errors
|
|
/// Returns an error if the path does not exist or the item cannot be deleted.
|
|
#[tauri::command]
|
|
pub fn delete_path(path: &str) -> Result<(), String> {
|
|
let target = Path::new(path);
|
|
|
|
if !target.exists() {
|
|
return Err("Path does not exist".into());
|
|
}
|
|
|
|
if target.is_dir() {
|
|
fs::remove_dir_all(target).map_err(|e| e.to_string())?;
|
|
} else {
|
|
fs::remove_file(target).map_err(|e| e.to_string())?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Get the user's home directory path.
|
|
///
|
|
/// # Errors
|
|
/// Returns an error if the home directory cannot be determined.
|
|
#[tauri::command]
|
|
pub fn get_home_dir() -> Result<String, String> {
|
|
dirs::home_dir()
|
|
.and_then(|p| p.to_str().map(String::from))
|
|
.ok_or_else(|| "Could not determine home directory".into())
|
|
}
|