This commit is contained in:
@@ -5,7 +5,7 @@ meta {
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8484/device
|
||||
url: http://localhost:8282/device
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
56
src/main.rs
56
src/main.rs
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user