All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			
		
			
				
	
	
		
			149 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
use crate::constants;
 | 
						|
use crate::devices::device::DeviceId;
 | 
						|
use crate::energy::energy_actor;
 | 
						|
use crate::ota::ota_manager;
 | 
						|
use crate::ota::ota_update::OTAPlatform;
 | 
						|
use crate::server::WebEnergyActor;
 | 
						|
use crate::server::custom_error::HttpResult;
 | 
						|
use actix_multipart::form::MultipartForm;
 | 
						|
use actix_multipart::form::tempfile::TempFile;
 | 
						|
use actix_web::{HttpResponse, web};
 | 
						|
 | 
						|
pub async fn supported_platforms() -> HttpResult {
 | 
						|
    Ok(HttpResponse::Ok().json(OTAPlatform::supported_platforms()))
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Debug, MultipartForm)]
 | 
						|
pub struct UploadForm {
 | 
						|
    #[multipart(rename = "firmware")]
 | 
						|
    firmware: Vec<TempFile>,
 | 
						|
}
 | 
						|
 | 
						|
#[derive(serde::Deserialize)]
 | 
						|
pub struct SpecificOTAVersionPath {
 | 
						|
    platform: OTAPlatform,
 | 
						|
    version: semver::Version,
 | 
						|
}
 | 
						|
 | 
						|
/// Upload a new firmware update
 | 
						|
pub async fn upload_firmware(
 | 
						|
    MultipartForm(form): MultipartForm<UploadForm>,
 | 
						|
    path: web::Path<SpecificOTAVersionPath>,
 | 
						|
) -> 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."))
 | 
						|
}
 | 
						|
 | 
						|
/// Download a firmware update
 | 
						|
pub async fn download_firmware(path: web::Path<SpecificOTAVersionPath>) -> HttpResult {
 | 
						|
    if !ota_manager::update_exists(path.platform, &path.version)? {
 | 
						|
        return Ok(HttpResponse::NotFound().json("The requested firmware update was not found!"));
 | 
						|
    }
 | 
						|
 | 
						|
    let firmware = ota_manager::get_ota_update(path.platform, &path.version)?;
 | 
						|
 | 
						|
    Ok(HttpResponse::Ok()
 | 
						|
        .content_type("application/octet-stream")
 | 
						|
        .append_header((
 | 
						|
            "content-disposition",
 | 
						|
            format!(
 | 
						|
                "attachment; filename=\"{}-{}.bin\"",
 | 
						|
                path.platform, path.version
 | 
						|
            ),
 | 
						|
        ))
 | 
						|
        .body(firmware))
 | 
						|
}
 | 
						|
 | 
						|
/// Delete an uploaded firmware update
 | 
						|
pub async fn delete_update(path: web::Path<SpecificOTAVersionPath>) -> HttpResult {
 | 
						|
    if !ota_manager::update_exists(path.platform, &path.version)? {
 | 
						|
        return Ok(HttpResponse::NotFound().json("The requested firmware update was not found!"));
 | 
						|
    }
 | 
						|
 | 
						|
    ota_manager::delete_update(path.platform, &path.version)?;
 | 
						|
 | 
						|
    Ok(HttpResponse::Accepted().finish())
 | 
						|
}
 | 
						|
 | 
						|
/// Get the list of all OTA updates
 | 
						|
pub async fn list_all_ota() -> HttpResult {
 | 
						|
    Ok(HttpResponse::Ok().json(ota_manager::get_all_ota_updates()?))
 | 
						|
}
 | 
						|
 | 
						|
#[derive(serde::Deserialize)]
 | 
						|
pub struct ListOTAPath {
 | 
						|
    platform: OTAPlatform,
 | 
						|
}
 | 
						|
 | 
						|
/// List OTA software updates for a given platform
 | 
						|
pub async fn list_updates_platform(path: web::Path<ListOTAPath>) -> HttpResult {
 | 
						|
    let list = ota_manager::get_ota_updates_for_platform(path.platform)?;
 | 
						|
 | 
						|
    Ok(HttpResponse::Ok().json(list))
 | 
						|
}
 | 
						|
 | 
						|
#[derive(serde::Deserialize)]
 | 
						|
pub struct SetDesiredDeviceVersion {
 | 
						|
    devices: Option<Vec<DeviceId>>,
 | 
						|
    platform: Option<OTAPlatform>,
 | 
						|
    version: semver::Version,
 | 
						|
}
 | 
						|
 | 
						|
pub async fn set_desired_version(
 | 
						|
    actor: WebEnergyActor,
 | 
						|
    body: web::Json<SetDesiredDeviceVersion>,
 | 
						|
) -> HttpResult {
 | 
						|
    if body.devices.is_none() && body.platform.is_none() {
 | 
						|
        return Ok(
 | 
						|
            HttpResponse::BadRequest().json("Must specify one filter to select target devices!")
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    let devices = actor.send(energy_actor::GetDeviceLists).await?;
 | 
						|
 | 
						|
    for d in devices {
 | 
						|
        // Filter per platform
 | 
						|
        if let Some(p) = body.platform
 | 
						|
            && d.info.reference != p.to_string()
 | 
						|
        {
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        // Filter per device
 | 
						|
        if let Some(ids) = &body.devices
 | 
						|
            && !ids.contains(&d.id)
 | 
						|
        {
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        actor
 | 
						|
            .send(energy_actor::SetDesiredVersion(
 | 
						|
                d.id,
 | 
						|
                Some(body.version.clone()),
 | 
						|
            ))
 | 
						|
            .await??;
 | 
						|
    }
 | 
						|
 | 
						|
    Ok(HttpResponse::Ok().finish())
 | 
						|
}
 |