use super::{
args::{Restore, SortOrder},
fails::BoxedResult,
helpers::IntegerHelpers,
};
use glob::{PatternError, glob};
use log::error;
use std::{fmt, fs::File, io::prelude::*, path::Path, path::PathBuf};
use zip::ZipArchive;
type Decompressor = ZipArchive<File>;
#[derive(Debug)]
pub(crate) struct ArchiveReader {
pub archive: Decompressor,
pub entry_index: usize,
}
pub(crate) struct Docs {
pub json: String,
pub archive: String,
pub entry: String,
}
impl Restore {
pub(crate) fn find_archives(&self) -> Result<Vec<PathBuf>, PatternError> {
let wilcard = self.get_pattern();
let listed = glob(&wilcard)?;
let mut found = listed.filter_map(Result::ok).collect::<Vec<_>>();
if self.order != SortOrder::None {
found.sort_unstable();
}
if self.order == SortOrder::Desc {
found.reverse();
}
Ok(found)
}
pub(crate) fn get_pattern(&self) -> String {
let wilcard: String = match &self.search {
Some(pat) => {
if pat.ends_with(".zip") || pat.contains('*') {
pat.to_owned()
} else {
format!("{}*", pat)
}
}
None => format!("{}*.zip", self.options.core),
};
let mut path = self.transfer.dir.clone();
path.push(wilcard);
let res = path.to_str().unwrap();
res.to_string()
}
pub(crate) fn get_update_url(&self) -> String {
let parts: Vec<String> = vec![
self.options.get_core_handler_url("/update/json/docs?overwrite=true"),
self.flush.as_param("&"),
self.transfer.get_param("&"),
];
parts.concat()
}
}
impl ArchiveReader {
pub(crate) fn open_archive(archive_path: &Path) -> BoxedResult<Decompressor> {
let zipfile = File::open(archive_path)?;
let res = ZipArchive::new(zipfile)?;
Ok(res)
}
pub(crate) fn create_reader(archive_path: &Path) -> BoxedResult<ArchiveReader> {
let success = Self::open_archive(archive_path);
match success {
Err(cause) => Err(cause),
Ok(zip) => Ok(ArchiveReader { archive: zip, entry_index: 0 }),
}
}
pub(crate) fn get_archive_file_count(archive_path: &Path) -> Option<usize> {
let success = Self::open_archive(archive_path);
match success {
Err(_) => None,
Ok(archive) => {
let file_count = archive.len();
Some(file_count)
}
}
}
}
impl Iterator for ArchiveReader {
type Item = (String, String);
fn next(&mut self) -> Option<Self::Item> {
let file_count = self.archive.len();
if self.entry_index >= file_count {
return None;
}
let mut compressed = self.archive.by_index(self.entry_index).unwrap();
let zip_name = compressed.name().to_string();
let mut zip_contents = String::new();
let reading = compressed.read_to_string(&mut zip_contents);
match reading {
Err(cause) => {
error!("error reading archive #{} {}: {}", self.entry_index + 1, zip_name, cause);
None
}
Ok(_) => {
self.entry_index += 1;
Some((zip_name, zip_contents))
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let num_steps = self.archive.len();
if num_steps == 0 {
(0, None)
} else {
let max: usize = num_steps.to_usize();
(0, Some(max))
}
}
}
impl Docs {
pub(crate) fn new(archive_name: String, entry_name: String, documents: String) -> Self {
Docs { archive: archive_name, entry: entry_name, json: documents }
}
}
impl fmt::Display for Docs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "archive: {} file: {}", self.archive, self.entry)
}
}
impl fmt::Debug for Docs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let txt = if self.json.len() > 400 { &self.json[0..400] } else { &self.json };
write!(f, "archive: {} file: {}\nJson: {}", self.archive, self.entry, txt)
}
}