194 lines
4.8 KiB
Rust
194 lines
4.8 KiB
Rust
// IO error
|
|
// A wrapper around the tokio IO functions that adds the path to the error message, instead of the uninformative std::io::Error.
|
|
|
|
use std::{path::Path, io::Write};
|
|
|
|
use tempfile::NamedTempFile;
|
|
use tauri::async_runtime::spawn_blocking;
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum IOError {
|
|
#[error("{source}, path: {path}")]
|
|
IOPathError {
|
|
#[source]
|
|
source: std::io::Error,
|
|
path: String,
|
|
},
|
|
#[error(transparent)]
|
|
IOError(#[from] std::io::Error),
|
|
}
|
|
|
|
impl IOError {
|
|
pub fn from(source: std::io::Error) -> Self {
|
|
Self::IOError(source)
|
|
}
|
|
pub fn with_path(
|
|
source: std::io::Error,
|
|
path: impl AsRef<std::path::Path>,
|
|
) -> Self {
|
|
let path = path.as_ref();
|
|
|
|
Self::IOPathError {
|
|
source,
|
|
path: path.to_string_lossy().to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
// dunce canonicalize
|
|
pub fn canonicalize(
|
|
path: impl AsRef<std::path::Path>,
|
|
) -> Result<std::path::PathBuf, IOError> {
|
|
let path = path.as_ref();
|
|
dunce::canonicalize(path).map_err(|e| IOError::IOPathError {
|
|
source: e,
|
|
path: path.to_string_lossy().to_string(),
|
|
})
|
|
}
|
|
|
|
// read_dir
|
|
pub async fn read_dir(
|
|
path: impl AsRef<std::path::Path>,
|
|
) -> Result<tokio::fs::ReadDir, IOError> {
|
|
let path = path.as_ref();
|
|
tokio::fs::read_dir(path)
|
|
.await
|
|
.map_err(|e| IOError::IOPathError {
|
|
source: e,
|
|
path: path.to_string_lossy().to_string(),
|
|
})
|
|
}
|
|
|
|
// create_dir_all
|
|
pub async fn create_dir_all(
|
|
path: impl AsRef<std::path::Path>,
|
|
) -> Result<(), IOError> {
|
|
let path = path.as_ref();
|
|
tokio::fs::create_dir_all(path)
|
|
.await
|
|
.map_err(|e| IOError::IOPathError {
|
|
source: e,
|
|
path: path.to_string_lossy().to_string(),
|
|
})
|
|
}
|
|
|
|
// remove_dir_all
|
|
pub async fn remove_dir_all(
|
|
path: impl AsRef<std::path::Path>,
|
|
) -> Result<(), IOError> {
|
|
let path = path.as_ref();
|
|
tokio::fs::remove_dir_all(path)
|
|
.await
|
|
.map_err(|e| IOError::IOPathError {
|
|
source: e,
|
|
path: path.to_string_lossy().to_string(),
|
|
})
|
|
}
|
|
|
|
// read_to_string
|
|
pub async fn read_to_string(
|
|
path: impl AsRef<std::path::Path>,
|
|
) -> Result<String, IOError> {
|
|
let path = path.as_ref();
|
|
tokio::fs::read_to_string(path)
|
|
.await
|
|
.map_err(|e| IOError::IOPathError {
|
|
source: e,
|
|
path: path.to_string_lossy().to_string(),
|
|
})
|
|
}
|
|
|
|
// read
|
|
pub async fn read(
|
|
path: impl AsRef<std::path::Path>,
|
|
) -> Result<Vec<u8>, IOError> {
|
|
let path = path.as_ref();
|
|
tokio::fs::read(path)
|
|
.await
|
|
.map_err(|e| IOError::IOPathError {
|
|
source: e,
|
|
path: path.to_string_lossy().to_string(),
|
|
})
|
|
}
|
|
|
|
// write
|
|
pub async fn write(
|
|
path: impl AsRef<std::path::Path>,
|
|
data: impl AsRef<[u8]>,
|
|
) -> Result<(), IOError> {
|
|
let path = path.as_ref().to_owned();
|
|
let data = data.as_ref().to_owned();
|
|
spawn_blocking(move || {
|
|
let cloned_path = path.clone();
|
|
sync_write(data, path).map_err(|e| IOError::IOPathError {
|
|
source: e,
|
|
path: cloned_path.to_string_lossy().to_string(),
|
|
})
|
|
})
|
|
.await
|
|
.map_err(|_| {
|
|
std::io::Error::new(std::io::ErrorKind::Other, "background task failed")
|
|
})??;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn sync_write(
|
|
data: impl AsRef<[u8]>,
|
|
path: impl AsRef<Path>,
|
|
) -> Result<(), std::io::Error> {
|
|
let mut tempfile = NamedTempFile::new_in(path.as_ref().parent().ok_or_else(|| {
|
|
std::io::Error::new(
|
|
std::io::ErrorKind::Other,
|
|
"could not get parent directory for temporary file",
|
|
)
|
|
})?)?;
|
|
tempfile.write_all(data.as_ref())?;
|
|
let tmp_path = tempfile.into_temp_path();
|
|
let path = path.as_ref();
|
|
tmp_path.persist(path)?;
|
|
std::io::Result::Ok(())
|
|
}
|
|
// rename
|
|
pub async fn rename(
|
|
from: impl AsRef<std::path::Path>,
|
|
to: impl AsRef<std::path::Path>,
|
|
) -> Result<(), IOError> {
|
|
let from = from.as_ref();
|
|
let to = to.as_ref();
|
|
tokio::fs::rename(from, to)
|
|
.await
|
|
.map_err(|e| IOError::IOPathError {
|
|
source: e,
|
|
path: from.to_string_lossy().to_string(),
|
|
})
|
|
}
|
|
|
|
// copy
|
|
pub async fn copy(
|
|
from: impl AsRef<std::path::Path>,
|
|
to: impl AsRef<std::path::Path>,
|
|
) -> Result<u64, IOError> {
|
|
let from: &Path = from.as_ref();
|
|
let to = to.as_ref();
|
|
tokio::fs::copy(from, to)
|
|
.await
|
|
.map_err(|e| IOError::IOPathError {
|
|
source: e,
|
|
path: from.to_string_lossy().to_string(),
|
|
})
|
|
}
|
|
|
|
// remove file
|
|
pub async fn remove_file(
|
|
path: impl AsRef<std::path::Path>,
|
|
) -> Result<(), IOError> {
|
|
let path = path.as_ref();
|
|
tokio::fs::remove_file(path)
|
|
.await
|
|
.map_err(|e| IOError::IOPathError {
|
|
source: e,
|
|
path: path.to_string_lossy().to_string(),
|
|
})
|
|
}
|