use fs_extra::dir::get_size;
use serde::Serialize;
use showfile::show_path_in_file_manager;
use std::{
fs, io,
path::PathBuf,
time::{SystemTime, UNIX_EPOCH},
};
use tauri::{command, AppHandle, Runtime};
use tauri_plugin_shell::ShellExt;
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Metadata {
pub size: u64,
pub name: String,
pub extname: String,
pub is_dir: bool,
pub is_file: bool,
pub is_exist: bool,
pub is_symlink: bool,
pub is_absolute: bool,
pub is_relative: bool,
pub accessed_at: u128,
pub created_at: u128,
pub modified_at: u128,
}
#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MetadataOptions {
pub omit_size: Option<bool>,
}
#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct OpenOptions {
pub explorer: Option<bool>,
pub enter_dir: Option<bool>,
}
#[command]
pub async fn is_exist(path: PathBuf) -> bool {
path.exists()
}
#[command]
pub async fn is_dir(path: PathBuf) -> bool {
path.is_dir()
}
#[command]
pub async fn is_file(path: PathBuf) -> bool {
path.is_file()
}
#[command]
pub async fn size(path: PathBuf) -> u64 {
get_size(path).unwrap_or(0)
}
#[command]
pub async fn name(path: PathBuf) -> String {
path.file_stem()
.map(|name| name.to_string_lossy().to_string())
.unwrap_or_default()
}
#[command]
pub async fn extname(path: PathBuf) -> String {
path.extension()
.map(|extname| extname.to_string_lossy().to_string())
.unwrap_or_default()
}
fn system_time_to_unix_millis(time: io::Result<SystemTime>) -> u128 {
match time {
Ok(system_time) => system_time
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_millis())
.unwrap_or_default(),
Err(_) => 0,
}
}
#[command]
pub async fn metadata(path: PathBuf, options: Option<MetadataOptions>) -> Result<Metadata, String> {
let options = options.unwrap_or(MetadataOptions {
omit_size: Some(false),
});
let omit_size = options.omit_size.unwrap_or(false);
let size = match omit_size {
true => 0,
false => size(path.clone()).await,
};
let name = name(path.clone()).await;
let extname = extname(path.clone()).await;
let is_dir = path.is_dir();
let is_file = path.is_file();
let is_exist = path.exists();
let is_symlink = path.is_symlink();
let is_absolute = path.is_absolute();
let is_relative = path.is_relative();
let metadata = fs::metadata(path).map_err(|error| error.to_string())?;
let accessed_at = system_time_to_unix_millis(metadata.accessed());
let created_at = system_time_to_unix_millis(metadata.created());
let modified_at = system_time_to_unix_millis(metadata.modified());
Ok(Metadata {
size,
name,
extname,
is_dir,
is_file,
is_exist,
is_symlink,
is_absolute,
is_relative,
accessed_at,
created_at,
modified_at,
})
}
#[command]
pub async fn open<R: Runtime>(
app_handle: AppHandle<R>,
path: PathBuf,
options: Option<OpenOptions>,
) -> Result<(), String> {
let options = options.unwrap_or(OpenOptions {
explorer: Some(false),
enter_dir: Some(false),
});
let explorer = options.explorer.unwrap_or(false);
let enter_dir = options.enter_dir.unwrap_or(false);
if explorer && !(path.is_dir() && enter_dir) {
show_path_in_file_manager(path);
} else {
let _ = app_handle.shell().open(path.to_string_lossy(), None);
}
Ok(())
}