Add a route to upload update to the platform
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
use crate::devices::device::{DeviceId, DeviceRelayID};
|
||||
use crate::ota::ota_update::OTAPlatform;
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@ -296,12 +297,14 @@ impl AppConfig {
|
||||
|
||||
/// Get the directory that will store OTA updates
|
||||
pub fn ota_dir(&self) -> PathBuf {
|
||||
self.logs_dir().join("ota")
|
||||
self.storage_path().join("ota")
|
||||
}
|
||||
|
||||
/// Get the directory that will store OTA updates of a given device reference
|
||||
pub fn ota_of_device(&self, dev_ref: &str) -> PathBuf {
|
||||
self.ota_dir().join(dev_ref)
|
||||
/// Get the path to the file that will contain an OTA update
|
||||
pub fn path_ota_update(&self, platform: OTAPlatform, version: &semver::Version) -> PathBuf {
|
||||
self.ota_dir()
|
||||
.join(platform.to_string())
|
||||
.join(version.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,9 @@ pub const MAX_INACTIVITY_DURATION: u64 = 3600;
|
||||
/// Maximum session duration (1 day)
|
||||
pub const MAX_SESSION_DURATION: u64 = 3600 * 24;
|
||||
|
||||
/// Maximum firmware size (in bytes)
|
||||
pub const MAX_FIRMWARE_SIZE: usize = 50 * 1000 * 1000;
|
||||
|
||||
/// List of routes that do not require authentication
|
||||
pub const ROUTES_WITHOUT_AUTH: [&str; 2] =
|
||||
["/web_api/server/config", "/web_api/auth/password_auth"];
|
||||
|
@ -1 +1,2 @@
|
||||
pub mod ota_manager;
|
||||
pub mod ota_update;
|
||||
|
24
central_backend/src/ota/ota_manager.rs
Normal file
24
central_backend/src/ota/ota_manager.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::ota::ota_update::OTAPlatform;
|
||||
use crate::utils::files_utils;
|
||||
|
||||
/// Check out whether a given update exists or not
|
||||
pub fn update_exists(platform: OTAPlatform, version: &semver::Version) -> anyhow::Result<bool> {
|
||||
Ok(AppConfig::get()
|
||||
.path_ota_update(platform, version)
|
||||
.is_file())
|
||||
}
|
||||
|
||||
/// Save a new firmware update
|
||||
pub fn save_update(
|
||||
platform: OTAPlatform,
|
||||
version: &semver::Version,
|
||||
update: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let path = AppConfig::get().path_ota_update(platform, version);
|
||||
files_utils::create_directory_if_missing(path.parent().unwrap())?;
|
||||
|
||||
std::fs::write(path, update)?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,5 +1,22 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum OTAPlatform {
|
||||
#[serde(rename = "Wt32-Eth01")]
|
||||
Wt32Eth01,
|
||||
}
|
||||
|
||||
impl Display for OTAPlatform {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let s = serde_json::to_string(&self).unwrap().replace('"', "");
|
||||
write!(f, "{s}")
|
||||
}
|
||||
}
|
||||
|
||||
/// Single OTA update information
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||
pub struct OTAUpdate {
|
||||
platform: OTAPlatform,
|
||||
version: semver::Version,
|
||||
file_size: usize,
|
||||
}
|
||||
|
@ -185,6 +185,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
|
||||
"/web_api/ota/supported_platforms",
|
||||
web::get().to(ota_controller::supported_platforms),
|
||||
)
|
||||
.route(
|
||||
"/web_api/ota/{platform}/{version}",
|
||||
web::post().to(ota_controller::upload_firmware),
|
||||
)
|
||||
// TODO : upload a new software update
|
||||
// TODO : list ota software update per platform
|
||||
// TODO : download a OTA file
|
||||
|
@ -1,7 +1,51 @@
|
||||
use crate::constants;
|
||||
use crate::ota::ota_manager;
|
||||
use crate::ota::ota_update::OTAPlatform;
|
||||
use crate::server::custom_error::HttpResult;
|
||||
use actix_web::HttpResponse;
|
||||
use actix_multipart::form::tempfile::TempFile;
|
||||
use actix_multipart::form::MultipartForm;
|
||||
use actix_web::{web, HttpResponse};
|
||||
|
||||
pub async fn supported_platforms() -> HttpResult {
|
||||
Ok(HttpResponse::Ok().json(vec![OTAPlatform::Wt32Eth01]))
|
||||
}
|
||||
|
||||
#[derive(Debug, MultipartForm)]
|
||||
pub struct UploadForm {
|
||||
#[multipart(rename = "firmware")]
|
||||
firmware: Vec<TempFile>,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct UploadPath {
|
||||
platform: OTAPlatform,
|
||||
version: semver::Version,
|
||||
}
|
||||
|
||||
pub async fn upload_firmware(
|
||||
MultipartForm(form): MultipartForm<UploadForm>,
|
||||
path: web::Path<UploadPath>,
|
||||
) -> HttpResult {
|
||||
if ota_manager::update_exists(path.platform, &path.version)? {
|
||||
return Ok(HttpResponse::Conflict()
|
||||
.json("A firmware with the same version has already been uploaded on the platform!"));
|
||||
}
|
||||
|
||||
let Some(file) = form.firmware.first() else {
|
||||
return Ok(HttpResponse::BadRequest().json("No firmware specified!"));
|
||||
};
|
||||
|
||||
if file.size == 0 {
|
||||
return Ok(HttpResponse::BadRequest().json("Uploaded file is empty!"));
|
||||
}
|
||||
|
||||
if file.size > constants::MAX_FIRMWARE_SIZE {
|
||||
return Ok(HttpResponse::BadRequest().json("Uploaded file is too heavy!"));
|
||||
}
|
||||
|
||||
let content = std::fs::read(file.file.path())?;
|
||||
|
||||
ota_manager::save_update(path.platform, &path.version, &content)?;
|
||||
|
||||
Ok(HttpResponse::Accepted().body("OTA update successfully saved."))
|
||||
}
|
||||
|
Reference in New Issue
Block a user