Files
iot-cloud-api/src/firmware_api.rs
Tobias Maier 0257434b26
Some checks failed
Build Project / test (push) Failing after 6m9s
Test
2025-02-06 17:27:59 +00:00

86 lines
3.1 KiB
Rust

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<AppState>,
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<AppState>, path: web::Path<String>) -> 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<AppState>,
) -> 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")
}
}