67 lines
2.2 KiB
Rust
67 lines
2.2 KiB
Rust
use crate::app_config::AppConfig;
|
|
use crate::server::custom_error::HttpResult;
|
|
use crate::utils::time_utils::current_day;
|
|
use actix_web::HttpResponse;
|
|
use anyhow::Context;
|
|
use std::fs::File;
|
|
use std::io::{Cursor, Read, Write};
|
|
use walkdir::WalkDir;
|
|
use zip::write::SimpleFileOptions;
|
|
|
|
/// Download a full copy of the storage data
|
|
pub async fn download_storage() -> HttpResult {
|
|
let mut zip_buff = Cursor::new(Vec::new());
|
|
let mut zip = zip::ZipWriter::new(&mut zip_buff);
|
|
|
|
let options = SimpleFileOptions::default()
|
|
.compression_method(zip::CompressionMethod::Bzip2)
|
|
.unix_permissions(0o700);
|
|
|
|
let storage = AppConfig::get().storage_path();
|
|
|
|
let mut file_buff = Vec::new();
|
|
for entry in WalkDir::new(&storage) {
|
|
let entry = entry?;
|
|
|
|
let path = entry.path();
|
|
let name = path.strip_prefix(&storage).unwrap();
|
|
let path_as_string = name
|
|
.to_str()
|
|
.map(str::to_owned)
|
|
.with_context(|| format!("{name:?} Is a Non UTF-8 Path"))?;
|
|
|
|
// Write file or directory explicitly
|
|
// Some unzip tools unzip files with directory paths correctly, some do not!
|
|
if path.is_file() {
|
|
log::debug!("adding file {path:?} as {name:?} ...");
|
|
zip.start_file(path_as_string, options)?;
|
|
let mut f = File::open(path)?;
|
|
|
|
f.read_to_end(&mut file_buff)?;
|
|
zip.write_all(&file_buff)?;
|
|
file_buff.clear();
|
|
} else if !name.as_os_str().is_empty() {
|
|
// Only if not root! Avoids path spec / warning
|
|
// and mapname conversion failed error on unzip
|
|
log::debug!("adding dir {path_as_string:?} as {name:?} ...");
|
|
zip.add_directory(path_as_string, options)?;
|
|
}
|
|
}
|
|
|
|
// Inject runtime configuration
|
|
zip.start_file("/app_config.json", options)?;
|
|
zip.write_all(&serde_json::to_vec_pretty(&AppConfig::get())?)?;
|
|
|
|
zip.finish()?;
|
|
|
|
let filename = format!("storage-{}.zip", current_day());
|
|
|
|
Ok(HttpResponse::Ok()
|
|
.content_type("application/zip")
|
|
.insert_header((
|
|
"content-disposition",
|
|
format!("attachment; filename=\"{filename}\""),
|
|
))
|
|
.body(zip_buff.into_inner()))
|
|
}
|