Updates
All checks were successful
Build Project / test (push) Successful in 5m58s

This commit is contained in:
2025-01-19 15:43:04 +01:00
parent e19a11d5f3
commit e5339f7c6c
5 changed files with 47 additions and 26 deletions

View File

@@ -5,7 +5,7 @@ meta {
}
get {
url: http://localhost:8484/device
url: http://localhost:8282/device
body: none
auth: none
}

View File

@@ -5,7 +5,7 @@ meta {
}
put {
url: http://localhost:8282/firmware/waterlevel/INA233/1.0.0
url: http://localhost:8282/firmware/waterlevel/INA226/1.0.3
body: multipartForm
auth: none
}

View File

@@ -7,7 +7,7 @@ use dotenvy::dotenv;
use log::{debug, error, info};
use schemas::{BoardConfig, BoardType, Device, OTAConfiguration, OTAConfigurationList};
use sqlx::types::mac_address::MacAddress;
use util::parse_mac_address;
use util::{get_files, parse_mac_address};
mod database;
mod schemas;
@@ -15,6 +15,8 @@ mod util;
struct AppState {
db: Database,
firmwares_path: PathBuf,
hostname: String
}
#[post("/telemetry/{device_id}")]
@@ -124,16 +126,17 @@ async fn get_devices(data: web::Data<AppState>) -> impl Responder {
HttpResponse::Ok().json(devices)
}
#[put("/firmware/{product}/{config}/{version}")]
async fn upload_firmware(path: web::Path<(String, String, String)>, body: web::Bytes) -> impl Responder {
let (product, config, version) = path.into_inner();
let version = version.replace(".", "_");
let firmware_root_path = PathBuf::from(env::var("FIMRWARE_FOLDER").unwrap_or("./firmware".to_string()));
#[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_folder = firmware_root_path.join(&product).join(&config);
let firmware_path = firmware_folder.join(format!("ver_{}", &version)).with_extension("bin");
let firmware_root_path = &data.firmwares_path;
info!("Uploading firmware with product: {product}, config: {config} and version: {version} to {firmware_path:?}");
let firmware_folder = firmware_root_path.join(&device);
let firmware_path = firmware_folder.join(format!("firmware_{config}_{version}")).with_extension("bin");
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;
@@ -142,18 +145,32 @@ async fn upload_firmware(path: web::Path<(String, String, String)>, body: web::B
HttpResponse::Ok().body(format!("Firmware version {} uploaded successfully", version))
}
#[get("/firmware/{product}/{config}/{version}")]
async fn get_firmware_json(path: web::Path<(String, String, String)>) -> impl Responder {
let (product, config, version) = path.into_inner();
let version = version.replace(".", "_");
let mut configs = Vec::new();
#[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![]} )
}
HttpResponse::Ok().json(OTAConfigurationList{configurations: configs} )
}
// #[get("/firmware/{product}/{config}/{version}")]
// async fn get_firmware_json(path: web::Path<(String, String, String)>, data: web::Data<AppState>) -> impl Responder {
// let (product, config, version) = path.into_inner();
// let version = version.replace(".", "-");
// match get_files(&data.firmwares_path, &data.hostname) {
// Ok(cfg) => HttpResponse::Ok().json(OTAConfigurationList{configurations: cfg} ),
// Err(e) => HttpResponse::InternalServerError().body(e.to_string())
// }
// }
#[get("/firmware/waterlevel/firmware_INA233_1.0.0.bin")]
async fn serve_firmware() -> impl Responder {
let file_path = PathBuf::from("./firmware/waterlevel/firmware_INA233_1.0.0.bin");
@@ -178,6 +195,7 @@ async fn main() -> std::io::Result<()> {
env_logger::init();
info!("Starting");
let db_url = match env::var("DATABASE_URL") {
Ok(url) => url,
Err(e) => {
@@ -192,7 +210,7 @@ async fn main() -> std::io::Result<()> {
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(AppState { db: db.clone() }))
.app_data(web::Data::new(AppState { db: db.clone(), firmwares_path: PathBuf::from("./fw"), hostname: "127.0.0.1".to_string() }))
.app_data(web::PayloadConfig::new(256 * 1024 * 1024)) //256MB
.service(receive_telemetry)
.service(get_telemetry)

View File

@@ -1,3 +1,5 @@
use std::path::PathBuf;
use chrono::NaiveDateTime;
use serde::{ser::SerializeStruct, Deserialize, Serialize};
use sqlx::types::mac_address::MacAddress;
@@ -89,4 +91,4 @@ pub enum BoardType {
pub enum BoardConfig {
INA226,
INA233
}
}

View File

@@ -52,12 +52,13 @@ pub fn get_files(root_path: &PathBuf, hostname: &str) -> Result<Vec<OTAConfigura
let entries = fs::read_dir(root_path)?;
for entry in entries.flatten() {
info!("Reading entry: {entry:?}");
let path = entry.path();
if path.is_file() {
println!("File: {:?}", path);
info!("processing file: {:?}", path);
// Splits the filename at the underscores. This is safe to do as names get sanitized on upload and are only uploaded by the pipeline
let split_name: Vec<_> = path.file_name().ok_or(GetFilesError::Filename)?.to_str().ok_or(GetFilesError::Filename)?.split("_").collect();
let version = split_name[2].strip_suffix(".bin").ok_or(GetFilesError::Extension)?;
let version = split_name[2].strip_suffix(".bin").ok_or(GetFilesError::Extension)?.replace("-", ".");
let board_config = BoardConfig::from_str(split_name[1])?;
let board_type = BoardType::from_str(&product_name).unwrap();
let version_replaced = version.replace(".", "_");
@@ -85,8 +86,8 @@ mod tests {
let expected_2 = OTAConfiguration{ version: "4.5.6".to_string(), url: "example.com/firmware/waterlevel/INA226/4_5_6.bin".to_string(), board: Some(BoardType::Waterlevel), config: Some(BoardConfig::INA226) };
let loaded_configs = get_files(&PathBuf::from("./test/waterlevel"), "example.com").unwrap();
assert_eq!(loaded_configs[0], expected_1);
assert_eq!(loaded_configs[1], expected_2);
assert_eq!(loaded_configs[1], expected_1);
assert_eq!(loaded_configs[0], expected_2);
}
#[test]