use std::{fs, path::PathBuf}; use actix_web::{get, put, web, HttpResponse, Responder}; use log::{debug, info, warn}; use crate::{schemas::{AppState, OTAConfigurationList}, util::get_files}; // Upload Firmware file #[put("/firmware/{device}/{config}/{version}")] async fn upload_firmware( data: web::Data, path: web::Path<(String, String, String)>, body: web::Bytes, ) -> impl Responder { let (device, config, version) = path.into_inner(); let version = version.replace('.', "-"); let firmware_root_path = &data.firmwares_path; let firmware_folder = firmware_root_path.join(&device); let firmware_path = firmware_folder .join(format!("firmware_{config}_{version}")) .with_extension("bin"); if firmware_path.is_file() { warn!("Firmware with product: {device}, config: {config} and version: {version} at path {firmware_path:?} already exists, cant upload"); return HttpResponse::Conflict().body(format!("{firmware_path:?}")); } info!("Uploading firmware with product: {device}, config: {config} and version: {version} to {firmware_path:?}"); fs::create_dir_all(&firmware_folder).unwrap(); let x = tokio::fs::write(&firmware_path, &body).await; debug!("{x:?}"); HttpResponse::Ok().body(format!( "Firmware version {version} uploaded successfully" )) } #[get("/firmware/{device}")] async fn get_firmware_json(data: web::Data, path: web::Path) -> impl Responder { let device = path.into_inner(); let fw_path = &data.firmwares_path.join(device); if fw_path.is_dir() { match get_files(fw_path, &data.hostname) { Ok(cfg) => HttpResponse::Ok().json(OTAConfigurationList { configurations: cfg, }), Err(e) => HttpResponse::InternalServerError().body(e.to_string()), } } else { HttpResponse::Ok().json(OTAConfigurationList { configurations: vec![], }) } } #[get("/firmware/{product}/{config}/{version}.bin")] async fn serve_firmware( path: web::Path<(String, String, String)>, data: web::Data, ) -> impl Responder { let (product, config, version) = path.into_inner(); let version = version.replace(['.', '_'], "-"); let fw_root_path = &data.firmwares_path; let file_path = PathBuf::from(format!("{product}/firmware_{config}_{version}.bin")); let file_path = fw_root_path.join(&file_path); info!("Requested firmware for product: {product}, config: {config} and version: {version}, expected to be stored at {file_path:?}"); if file_path.exists() { info!("File exists, serving download now"); HttpResponse::Ok() .content_type("application/octet-stream") .insert_header(( "Content-Disposition", format!("attachment; filename=\"{product}_{config}_{version}.bin\""), )) .body(std::fs::read(file_path).unwrap_or_else(|_| Vec::new())) } else { warn!("File does not exist"); HttpResponse::NotFound().body("Firmware version not found") } }