use std::path::{Path, PathBuf};
use laterite_ags4_core::error::CliError;
use laterite_ags4_core::transport as engine;
use crate::error::{Error, ErrorKind};
pub const DEFAULT_LEVEL: i32 = 9;
pub const DEFAULT_WORK_FACTOR: u8 = engine::SCRYPT_LOG_N;
fn map(err: &CliError, subject: &str) -> Error {
let kind = match err {
CliError::FileNotFound(_) => ErrorKind::Io,
_ => ErrorKind::Other,
};
Error::with_source(kind, subject.to_string(), err)
}
pub struct Packed {
bytes: u64,
ratio: f64,
elapsed_s: f64,
}
impl Packed {
#[must_use]
pub fn bytes(&self) -> u64 {
self.bytes
}
#[must_use]
pub fn ratio(&self) -> f64 {
self.ratio
}
#[must_use]
pub fn elapsed_secs(&self) -> f64 {
self.elapsed_s
}
}
pub struct Unpacked {
bytes: u64,
elapsed_s: f64,
}
impl Unpacked {
#[must_use]
pub fn bytes(&self) -> u64 {
self.bytes
}
#[must_use]
pub fn elapsed_secs(&self) -> f64 {
self.elapsed_s
}
}
pub struct Pack {
src: PathBuf,
dest: PathBuf,
level: i32,
}
pub fn pack(src: impl AsRef<Path>, dest: impl AsRef<Path>) -> Pack {
Pack {
src: src.as_ref().to_path_buf(),
dest: dest.as_ref().to_path_buf(),
level: DEFAULT_LEVEL,
}
}
impl Pack {
#[must_use]
pub fn level(mut self, level: i32) -> Pack {
self.level = level;
self
}
pub fn run(self) -> Result<Packed, Error> {
engine::pack(&self.src, &self.dest, self.level)
.map(|s| Packed {
bytes: s.bytes,
ratio: s.ratio,
elapsed_s: s.elapsed_s,
})
.map_err(|e| map(&e, &format!("cannot pack {}", self.src.display())))
}
}
pub struct PackBytes {
data: Vec<u8>,
level: i32,
}
pub fn pack_bytes(data: impl Into<Vec<u8>>) -> PackBytes {
PackBytes {
data: data.into(),
level: DEFAULT_LEVEL,
}
}
impl PackBytes {
#[must_use]
pub fn level(mut self, level: i32) -> PackBytes {
self.level = level;
self
}
pub fn run(self) -> Result<Vec<u8>, Error> {
engine::pack_bytes(&self.data, self.level)
.map_err(|e| map(&e, &format!("cannot pack {} bytes", self.data.len())))
}
}
pub fn unpack(src: impl AsRef<Path>, dest: impl AsRef<Path>) -> Result<Unpacked, Error> {
let src = src.as_ref();
engine::unpack(src, dest.as_ref())
.map(|s| Unpacked {
bytes: s.bytes,
elapsed_s: s.elapsed_s,
})
.map_err(|e| map(&e, &format!("cannot unpack {}", src.display())))
}
pub fn unpack_bytes(data: impl AsRef<[u8]>) -> Result<Vec<u8>, Error> {
let data = data.as_ref();
engine::unpack_bytes(data).map_err(|e| map(&e, &format!("cannot unpack {} bytes", data.len())))
}
pub struct Lock {
src: PathBuf,
dest: PathBuf,
password: String,
level: i32,
log_n: u8,
}
pub fn lock(src: impl AsRef<Path>, dest: impl AsRef<Path>, password: impl Into<String>) -> Lock {
Lock {
src: src.as_ref().to_path_buf(),
dest: dest.as_ref().to_path_buf(),
password: password.into(),
level: DEFAULT_LEVEL,
log_n: DEFAULT_WORK_FACTOR,
}
}
impl Lock {
#[must_use]
pub fn level(mut self, level: i32) -> Lock {
self.level = level;
self
}
#[must_use]
pub fn work_factor(mut self, log_n: u8) -> Lock {
self.log_n = log_n;
self
}
pub fn run(self) -> Result<Packed, Error> {
engine::lock(
&self.src,
&self.dest,
&self.password,
self.level,
self.log_n,
)
.map(|s| Packed {
bytes: s.bytes,
ratio: s.ratio,
elapsed_s: s.elapsed_s,
})
.map_err(|e| map(&e, &format!("cannot lock {}", self.src.display())))
}
}
pub struct LockBytes {
data: Vec<u8>,
password: String,
level: i32,
log_n: u8,
}
pub fn lock_bytes(data: impl Into<Vec<u8>>, password: impl Into<String>) -> LockBytes {
LockBytes {
data: data.into(),
password: password.into(),
level: DEFAULT_LEVEL,
log_n: DEFAULT_WORK_FACTOR,
}
}
impl LockBytes {
#[must_use]
pub fn level(mut self, level: i32) -> LockBytes {
self.level = level;
self
}
#[must_use]
pub fn work_factor(mut self, log_n: u8) -> LockBytes {
self.log_n = log_n;
self
}
pub fn run(self) -> Result<Vec<u8>, Error> {
engine::lock_bytes(&self.data, &self.password, self.level, self.log_n)
.map_err(|e| map(&e, &format!("cannot lock {} bytes", self.data.len())))
}
}
pub fn unlock(
src: impl AsRef<Path>,
dest: impl AsRef<Path>,
password: impl AsRef<str>,
) -> Result<Unpacked, Error> {
let src = src.as_ref();
engine::unlock(src, dest.as_ref(), password.as_ref())
.map(|s| Unpacked {
bytes: s.bytes,
elapsed_s: s.elapsed_s,
})
.map_err(|e| map(&e, &format!("cannot unlock {}", src.display())))
}
pub fn unlock_bytes(data: impl AsRef<[u8]>, password: impl AsRef<str>) -> Result<Vec<u8>, Error> {
let data = data.as_ref();
engine::unlock_bytes(data, password.as_ref())
.map_err(|e| map(&e, &format!("cannot unlock {} bytes", data.len())))
}
impl std::fmt::Debug for Pack {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Pack")
.field("src", &self.src)
.field("dest", &self.dest)
.field("level", &self.level)
.finish()
}
}
impl std::fmt::Debug for PackBytes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PackBytes")
.field("bytes", &self.data.len())
.field("level", &self.level)
.finish()
}
}
impl std::fmt::Debug for Lock {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Lock")
.field("src", &self.src)
.field("dest", &self.dest)
.field("password", &"<redacted>")
.field("level", &self.level)
.field("work_factor", &self.log_n)
.finish()
}
}
impl std::fmt::Debug for LockBytes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LockBytes")
.field("bytes", &self.data.len())
.field("password", &"<redacted>")
.field("level", &self.level)
.field("work_factor", &self.log_n)
.finish()
}
}
impl std::fmt::Debug for Packed {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Packed")
.field("bytes", &self.bytes)
.field("ratio", &self.ratio)
.field("elapsed_s", &self.elapsed_s)
.finish()
}
}
impl std::fmt::Debug for Unpacked {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Unpacked")
.field("bytes", &self.bytes)
.field("elapsed_s", &self.elapsed_s)
.finish()
}
}