use std::{
path::{Path, PathBuf},
sync::Arc,
};
use serde::{Deserialize, Serialize};
use serde_flow::encoder::{bincode, FlowEncoder};
use crate::{
error::{OpsError, OpsResult},
operation::LoaderFn,
process::{constants::COPY_FILE_ID, Process},
};
const COPY_REMOVE_FILE: &str = "cp_rm";
#[derive(Serialize, Deserialize, Default)]
pub struct Op {
from: PathBuf,
to: PathBuf,
#[serde(skip)]
bytes: Vec<u8>,
}
impl Op {
pub fn new(from: &Path, to: &Path) -> OpsResult<Self> {
let mut object = Self {
from: from.to_path_buf(),
to: to.to_path_buf(),
bytes: Vec::new(),
};
object.bytes =
bincode::Encoder::serialize(&object).map_err(|_| OpsError::SerializeFailed)?;
Ok(object)
}
pub fn from_bytes(bytes: &[u8]) -> OpsResult<Self> {
let mut decoded: Op =
bincode::Encoder::deserialize(bytes).map_err(|_| OpsError::SerializeFailed)?;
decoded.bytes = bytes.to_vec();
Ok(decoded)
}
}
pub fn load(bytes: &[u8]) -> OpsResult<Box<dyn Process>> {
let value = Op::from_bytes(bytes)?;
Ok(Box::new(value))
}
pub fn loader() -> (u8, LoaderFn) {
(COPY_FILE_ID, Arc::new(load))
}
impl Process for Op {
#[inline]
fn prepare(&self) -> OpsResult<()> {
if self.to.exists() {
let remove_filename = format!("{}.{COPY_REMOVE_FILE}", self.to.to_string_lossy());
let remove_filename = Path::new(&remove_filename);
std::fs::rename(self.to.as_path(), remove_filename)?;
}
println!("Copy: Prepare");
Ok(())
}
#[inline]
fn run(&self) -> OpsResult<()> {
std::fs::copy(self.from.as_path(), self.to.as_path())?;
println!("Copy: Run");
Ok(())
}
#[inline]
fn clean(&self) -> OpsResult<()> {
let remove_filename = format!("{}.{COPY_REMOVE_FILE}", self.to.to_string_lossy());
let remove_filename = Path::new(&remove_filename);
if remove_filename.exists() {
std::fs::remove_file(remove_filename)?;
}
println!("Copy: Clean {}", remove_filename.to_string_lossy());
Ok(())
}
#[inline]
fn revert_prepare(&self) -> OpsResult<()> {
let remove_filename = format!("{}.{COPY_REMOVE_FILE}", self.to.to_string_lossy());
let remove_filename = Path::new(&remove_filename);
if remove_filename.exists() {
std::fs::rename(remove_filename, self.to.as_path())?;
}
Ok(())
}
#[inline]
fn revert_run(&self) -> OpsResult<()> {
let remove_filename = format!("{}.{COPY_REMOVE_FILE}", self.to.to_string_lossy());
let remove_filename = Path::new(&remove_filename);
let _ = std::fs::remove_file(self.to.as_path());
std::fs::rename(remove_filename, self.to.as_path())?;
Ok(())
}
#[inline]
fn id() -> u8 {
COPY_FILE_ID
}
#[inline]
fn as_bytes(&self) -> &[u8] {
&self.bytes
}
}