use crate::db::DB;
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
use std::os::unix::io::FromRawFd;
pub struct UnixFileLoader<'a>(pub &'a std::path::PathBuf);
impl<'a> UnixFileLoader<'a> {
pub fn new(filename: &'a std::path::PathBuf) -> Self {
Self(filename)
}
pub async fn load<T>(&self) -> T
where
T: DB + Serialize + for<'de> Deserialize<'de> + Default,
{
self.load_with_locking().await.unwrap_or_default()
}
async fn load_with_locking<T>(&self) -> Result<T, anyhow::Error>
where
T: DB + Serialize + for<'de> Deserialize<'de>,
{
unsafe {
let fd = nix::libc::open(
std::ffi::CString::from_vec_unchecked(self.0.to_str().unwrap().as_bytes().to_vec())
.as_ptr(),
nix::libc::O_RDONLY,
);
if fd < 0 {
return Err(anyhow!(std::ffi::CStr::from_ptr(nix::libc::strerror(
nix::errno::errno()
))
.to_str()
.unwrap()
.to_string()));
}
if nix::libc::flock(fd, nix::libc::LOCK_EX) != 0 {
return Err(anyhow!(std::ffi::CStr::from_ptr(nix::libc::strerror(
nix::errno::errno()
))
.to_str()
.unwrap()
.to_string()));
}
Ok(ciborium::from_reader(std::fs::File::from_raw_fd(fd))?)
}
}
pub async fn dump<T>(&self, mut db: T) -> Result<(), anyhow::Error>
where
T: DB + Serialize + for<'de> Deserialize<'de>,
{
unsafe {
let fd = nix::libc::open(
std::ffi::CString::from_vec_unchecked(self.0.to_str().unwrap().as_bytes().to_vec())
.as_ptr(),
nix::libc::O_WRONLY | nix::libc::O_TRUNC | nix::libc::O_CREAT,
);
if fd < 0 {
return Err(anyhow!(std::ffi::CStr::from_ptr(nix::libc::strerror(
nix::errno::errno()
))
.to_str()
.unwrap()
.to_string()));
}
if nix::libc::flock(fd, nix::libc::LOCK_EX) != 0 {
return Err(anyhow!(std::ffi::CStr::from_ptr(nix::libc::strerror(
nix::errno::errno()
))
.to_str()
.unwrap()
.to_string()));
}
if nix::libc::chmod(
std::ffi::CString::from_vec_unchecked(self.0.to_str().unwrap().as_bytes().to_vec())
.as_ptr(),
nix::libc::S_IRUSR | nix::libc::S_IWUSR,
) != 0
{
return Err(anyhow!(std::ffi::CStr::from_ptr(nix::libc::strerror(
nix::errno::errno()
))
.to_str()
.unwrap()
.to_string()));
}
db.update_recurrence().await?;
Ok(ciborium::into_writer(&db, std::fs::File::from_raw_fd(fd))?)
}
}
}