Can download a copy of storage
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is failing
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	continuous-integration/drone/push Build is failing
				
			This commit is contained in:
		@@ -4,6 +4,7 @@ use actix_web::HttpResponse;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::fmt::{Display, Formatter};
 | 
			
		||||
use std::io::ErrorKind;
 | 
			
		||||
use zip::result::ZipError;
 | 
			
		||||
 | 
			
		||||
/// Custom error to ease controller writing
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
@@ -109,6 +110,18 @@ impl From<openssl::error::ErrorStack> for HttpErr {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ZipError> for HttpErr {
 | 
			
		||||
    fn from(value: ZipError) -> Self {
 | 
			
		||||
        HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<walkdir::Error> for HttpErr {
 | 
			
		||||
    fn from(value: walkdir::Error) -> Self {
 | 
			
		||||
        HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<HttpResponse> for HttpErr {
 | 
			
		||||
    fn from(value: HttpResponse) -> Self {
 | 
			
		||||
        HttpErr::HTTPResponse(value)
 | 
			
		||||
 
 | 
			
		||||
@@ -243,6 +243,11 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
 | 
			
		||||
                "/web_api/relay/{id}/status",
 | 
			
		||||
                web::get().to(relays_controller::status_single),
 | 
			
		||||
            )
 | 
			
		||||
            // Management API
 | 
			
		||||
            .route(
 | 
			
		||||
                "/web_api/management/download_storage",
 | 
			
		||||
                web::get().to(management_controller::download_storage),
 | 
			
		||||
            )
 | 
			
		||||
            // Devices API
 | 
			
		||||
            .route(
 | 
			
		||||
                "/devices_api/utils/time",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										66
									
								
								central_backend/src/server/web_api/management_controller.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								central_backend/src/server/web_api/management_controller.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
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()))
 | 
			
		||||
}
 | 
			
		||||
@@ -2,6 +2,7 @@ pub mod auth_controller;
 | 
			
		||||
pub mod devices_controller;
 | 
			
		||||
pub mod energy_controller;
 | 
			
		||||
pub mod logging_controller;
 | 
			
		||||
pub mod management_controller;
 | 
			
		||||
pub mod ota_controller;
 | 
			
		||||
pub mod relays_controller;
 | 
			
		||||
pub mod server_controller;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user