Fixed clippy, updated dependencies
Some checks failed
Build Project / test (push) Failing after 9m3s
Some checks failed
Build Project / test (push) Failing after 9m3s
This commit is contained in:
14
Cargo.toml
14
Cargo.toml
@@ -1,23 +1,23 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "iot-cloud"
|
name = "iot-cloud"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-service = "2.0.2"
|
actix-service = "2.0"
|
||||||
actix-web = "4.4.0"
|
actix-web = "4.11"
|
||||||
chrono = { version = "0.4.31", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
dotenvy = "0.15"
|
dotenvy = "0.15"
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
log = "0.4.20"
|
log = "0.4"
|
||||||
semver = "1.0.25"
|
semver = "1.0.25"
|
||||||
serde = "1.0.188"
|
serde = "1.0.188"
|
||||||
sqlx = { version = "0.8", features = [ "runtime-tokio", "tls-rustls", "postgres", "migrate", "chrono", "mac_address"] }
|
sqlx = { version = "0.8", features = [ "runtime-tokio", "tls-rustls", "postgres", "migrate", "chrono", "mac_address"] }
|
||||||
sqlx-cli = "0.8"
|
sqlx-cli = "0.8"
|
||||||
strum = { version = "0.26.3", features = ["derive"] }
|
strum = { version = "0.27", features = ["derive"] }
|
||||||
thiserror = "1.0"
|
thiserror = "2.0"
|
||||||
tokio = { version = "1", features = ["fs", "rt-multi-thread"] }
|
tokio = { version = "1", features = ["fs", "rt-multi-thread"] }
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl Database {
|
|||||||
Database { conn_pool: pool }
|
Database { conn_pool: pool }
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Failed to connect to the database: {:?}", err);
|
error!("Failed to connect to the database: {err:?}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ impl Database {
|
|||||||
match migrate!().run(&self.conn_pool).await {
|
match migrate!().run(&self.conn_pool).await {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error when running migrations {}", e);
|
error!("Error when running migrations {e}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -65,12 +65,13 @@ impl Database {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub async fn update_display_name(
|
pub async fn update_display_name(
|
||||||
&self,
|
&self,
|
||||||
device_id: &MacAddress,
|
device_id: &MacAddress,
|
||||||
display_name: &str,
|
display_name: &str,
|
||||||
) -> Result<(), DatabaseError> {
|
) -> Result<(), DatabaseError> {
|
||||||
info!("Adding Displayname {display_name} to Device with ID {device_id}");
|
info!("Updating Displayname to {display_name} for Device with ID {device_id}");
|
||||||
query!(
|
query!(
|
||||||
"UPDATE Devices SET display_name = $1 WHERE id = $2;",
|
"UPDATE Devices SET display_name = $1 WHERE id = $2;",
|
||||||
display_name,
|
display_name,
|
||||||
@@ -93,7 +94,7 @@ impl Database {
|
|||||||
let exists = match exists_result {
|
let exists = match exists_result {
|
||||||
Ok(res) => res.count > Some(0),
|
Ok(res) => res.count > Some(0),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Error checking table existence: {:?}", err);
|
error!("Error checking table existence: {err:?}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ async fn receive_telemetry(
|
|||||||
data: web::Data<AppState>,
|
data: web::Data<AppState>,
|
||||||
telemetry_message: web::Json<TelemetryMessageFromDevice>,
|
telemetry_message: web::Json<TelemetryMessageFromDevice>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
info!("POST - telementry - Processing device id {}", device_id);
|
info!("POST - telementry - Processing device id {device_id}");
|
||||||
let Ok(mac_converted) = parse_mac_address(&device_id) else {
|
let Ok(mac_converted) = parse_mac_address(&device_id) else {
|
||||||
return HttpResponse::InternalServerError();
|
return HttpResponse::InternalServerError();
|
||||||
};
|
};
|
||||||
@@ -21,10 +21,10 @@ async fn receive_telemetry(
|
|||||||
match data.db.create_device_if_not_exists(&mac_converted).await {
|
match data.db.create_device_if_not_exists(&mac_converted).await {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error creating new device: {}", e);
|
error!("Error creating new device: {e}");
|
||||||
return HttpResponse::InternalServerError();
|
return HttpResponse::InternalServerError();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
match data
|
match data
|
||||||
.db
|
.db
|
||||||
@@ -33,7 +33,7 @@ async fn receive_telemetry(
|
|||||||
{
|
{
|
||||||
Ok(()) => HttpResponse::Created(),
|
Ok(()) => HttpResponse::Created(),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("adding Telemetry message to DB failed \n{}", e);
|
error!("adding Telemetry message to DB failed \n{e}");
|
||||||
HttpResponse::InternalServerError()
|
HttpResponse::InternalServerError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ async fn receive_telemetry(
|
|||||||
|
|
||||||
#[get("/telemetry/{device_id}")]
|
#[get("/telemetry/{device_id}")]
|
||||||
async fn get_telemetry(device_id: web::Path<String>, data: web::Data<AppState>) -> impl Responder {
|
async fn get_telemetry(device_id: web::Path<String>, data: web::Data<AppState>) -> impl Responder {
|
||||||
info!("GET - telementry - Processing device id {}", device_id);
|
info!("GET - telementry - Processing device id {device_id}");
|
||||||
let Ok(mac_converted) = parse_mac_address(&device_id) else {
|
let Ok(mac_converted) = parse_mac_address(&device_id) else {
|
||||||
return HttpResponse::InternalServerError().finish();
|
return HttpResponse::InternalServerError().finish();
|
||||||
};
|
};
|
||||||
@@ -49,7 +49,7 @@ async fn get_telemetry(device_id: web::Path<String>, data: web::Data<AppState>)
|
|||||||
let messages = match data.db.get_telemetry_for_id(&mac_converted).await {
|
let messages = match data.db.get_telemetry_for_id(&mac_converted).await {
|
||||||
Ok(msgs) => msgs,
|
Ok(msgs) => msgs,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Getting Telemetry Messages from DB failed \n{}", e);
|
error!("Getting Telemetry Messages from DB failed \n{e}");
|
||||||
return HttpResponse::InternalServerError().finish();
|
return HttpResponse::InternalServerError().finish();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -62,7 +62,7 @@ async fn receive_value(
|
|||||||
data: web::Data<AppState>,
|
data: web::Data<AppState>,
|
||||||
value_message: web::Json<ValueMessageFromDevice>,
|
value_message: web::Json<ValueMessageFromDevice>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
info!("POST - value - Processing device id {}", device_id);
|
info!("POST - value - Processing device id {device_id}");
|
||||||
let Ok(mac_converted) = parse_mac_address(&device_id) else {
|
let Ok(mac_converted) = parse_mac_address(&device_id) else {
|
||||||
return HttpResponse::InternalServerError();
|
return HttpResponse::InternalServerError();
|
||||||
};
|
};
|
||||||
@@ -70,15 +70,15 @@ async fn receive_value(
|
|||||||
match data.db.create_device_if_not_exists(&mac_converted).await {
|
match data.db.create_device_if_not_exists(&mac_converted).await {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error creating new device: {}", e);
|
error!("Error creating new device: {e}");
|
||||||
return HttpResponse::InternalServerError();
|
return HttpResponse::InternalServerError();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
match data.db.add_value(&value_message, &mac_converted).await {
|
match data.db.add_value(&value_message, &mac_converted).await {
|
||||||
Ok(()) => HttpResponse::Created(),
|
Ok(()) => HttpResponse::Created(),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("adding Telemetry message to DB failed \n{}", e);
|
error!("adding Telemetry message to DB failed \n{e}");
|
||||||
HttpResponse::InternalServerError()
|
HttpResponse::InternalServerError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ async fn receive_value(
|
|||||||
|
|
||||||
#[get("/value/{device_id}")]
|
#[get("/value/{device_id}")]
|
||||||
async fn get_value(device_id: web::Path<String>, data: web::Data<AppState>) -> impl Responder {
|
async fn get_value(device_id: web::Path<String>, data: web::Data<AppState>) -> impl Responder {
|
||||||
info!("GET - value - Processing device id {}", device_id);
|
info!("GET - value - Processing device id {device_id}");
|
||||||
let Ok(mac_converted) = parse_mac_address(&device_id) else {
|
let Ok(mac_converted) = parse_mac_address(&device_id) else {
|
||||||
return HttpResponse::InternalServerError().finish();
|
return HttpResponse::InternalServerError().finish();
|
||||||
};
|
};
|
||||||
@@ -94,7 +94,7 @@ async fn get_value(device_id: web::Path<String>, data: web::Data<AppState>) -> i
|
|||||||
let messages = match data.db.get_values_for_id(&mac_converted).await {
|
let messages = match data.db.get_values_for_id(&mac_converted).await {
|
||||||
Ok(msgs) => msgs,
|
Ok(msgs) => msgs,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Getting Values from DB failed \n{}", e);
|
error!("Getting Values from DB failed \n{e}");
|
||||||
return HttpResponse::InternalServerError().finish();
|
return HttpResponse::InternalServerError().finish();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -107,7 +107,7 @@ async fn get_devices(data: web::Data<AppState>) -> impl Responder {
|
|||||||
let devices = match data.db.get_devices().await {
|
let devices = match data.db.get_devices().await {
|
||||||
Ok(devs) => devs,
|
Ok(devs) => devs,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Getting Devices from DB failed \n{}", e);
|
error!("Getting Devices from DB failed \n{e}");
|
||||||
return HttpResponse::InternalServerError().finish();
|
return HttpResponse::InternalServerError().finish();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,18 +38,18 @@ async fn upload_firmware(
|
|||||||
.with_extension("bin");
|
.with_extension("bin");
|
||||||
|
|
||||||
if firmware_path.is_file() {
|
if firmware_path.is_file() {
|
||||||
warn!("{service} with product: {device}, config: {config} and version: {version} at path {firmware_path:?} already exists, cant upload");
|
warn!("{service} with product: {device}, config: {config} and version: {version} at path {} already exists, cant upload", firmware_path.display());
|
||||||
return HttpResponse::Conflict().body(format!("{firmware_path:?}"));
|
return HttpResponse::Conflict().body(format!("{}", firmware_path.display()));
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Uploading {service} with product: {device}, config: {config} and version: {version} to {firmware_path:?}");
|
info!("Uploading {service} with product: {device}, config: {config} and version: {version} to {}", firmware_path.display());
|
||||||
|
|
||||||
fs::create_dir_all(&firmware_folder).unwrap();
|
fs::create_dir_all(&firmware_folder).unwrap();
|
||||||
let x = tokio::fs::write(&firmware_path, &body).await;
|
let x = tokio::fs::write(&firmware_path, &body).await;
|
||||||
debug!("{x:?}");
|
debug!("{x:?}");
|
||||||
|
|
||||||
debug!("pruning now");
|
debug!("pruning now");
|
||||||
prune_files(firmware_folder, service, 3);
|
prune_files(&firmware_folder, &service, 3);
|
||||||
|
|
||||||
HttpResponse::Ok().body(format!("Firmware version {version} uploaded successfully"))
|
HttpResponse::Ok().body(format!("Firmware version {version} uploaded successfully"))
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ async fn serve_firmware(
|
|||||||
let file_path = fw_root_path.join(&file_path);
|
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:?}");
|
info!("Requested firmware for product: {product}, config: {config} and version: {version}, expected to be stored at {}", file_path.display());
|
||||||
|
|
||||||
if file_path.exists() {
|
if file_path.exists() {
|
||||||
info!("File exists, serving download now");
|
info!("File exists, serving download now");
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ async fn main() -> std::io::Result<()> {
|
|||||||
firmwares_path: PathBuf::from(firmware_path.clone()),
|
firmwares_path: PathBuf::from(firmware_path.clone()),
|
||||||
hostname: external_url.clone(),
|
hostname: external_url.clone(),
|
||||||
}))
|
}))
|
||||||
.app_data(web::PayloadConfig::new(1 * 1024 * 1024 * 1024)) //1GB
|
.app_data(web::PayloadConfig::new(2 * 1024 * 1024 * 1024)) //1GB
|
||||||
.service(device_telemetry_api::receive_telemetry)
|
.service(device_telemetry_api::receive_telemetry)
|
||||||
.service(device_telemetry_api::get_telemetry)
|
.service(device_telemetry_api::get_telemetry)
|
||||||
.service(device_telemetry_api::receive_value)
|
.service(device_telemetry_api::receive_value)
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ pub enum BoardType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize, EnumString, PartialEq, Debug, Display)]
|
#[derive(serde::Serialize, EnumString, PartialEq, Debug, Display)]
|
||||||
#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
|
#[strum(ascii_case_insensitive, serialize_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum BoardConfig {
|
pub enum BoardConfig {
|
||||||
INA226,
|
INA226,
|
||||||
INA233,
|
INA233,
|
||||||
@@ -105,6 +105,7 @@ pub struct AppState {
|
|||||||
pub hostname: String,
|
pub hostname: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct DeviceMetadata {
|
pub struct DeviceMetadata {
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
|
|||||||
20
src/util.rs
20
src/util.rs
@@ -1,4 +1,4 @@
|
|||||||
use std::{cmp::Reverse, fs, path::PathBuf};
|
use std::{fs, path::PathBuf};
|
||||||
|
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
@@ -47,7 +47,7 @@ pub fn get_files(
|
|||||||
root_path: &PathBuf,
|
root_path: &PathBuf,
|
||||||
hostname: &str,
|
hostname: &str,
|
||||||
) -> Result<Vec<OTAConfiguration>, GetFilesError> {
|
) -> Result<Vec<OTAConfiguration>, GetFilesError> {
|
||||||
info!("Getting all files from path {root_path:?}");
|
info!("Getting all files from path {}", root_path.display());
|
||||||
let mut configs = Vec::new();
|
let mut configs = Vec::new();
|
||||||
let product_name = root_path
|
let product_name = root_path
|
||||||
.file_name()
|
.file_name()
|
||||||
@@ -59,7 +59,7 @@ pub fn get_files(
|
|||||||
info!("Reading entry: {entry:?}");
|
info!("Reading entry: {entry:?}");
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
info!("processing file: {:?}", path);
|
info!("processing file: {}", path.display());
|
||||||
// Splits the filename at the underscores. This is safe to do as names get sanitized on upload and are only uploaded by the pipeline
|
// 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
|
let split_name: Vec<_> = path
|
||||||
.file_name()
|
.file_name()
|
||||||
@@ -81,22 +81,22 @@ pub fn get_files(
|
|||||||
let fw_url =
|
let fw_url =
|
||||||
format!("{hostname}/{service}/{board_type}/{board_config}/{version_replaced}.bin");
|
format!("{hostname}/{service}/{board_type}/{board_config}/{version_replaced}.bin");
|
||||||
let cfg = OTAConfiguration {
|
let cfg = OTAConfiguration {
|
||||||
version: version,
|
version,
|
||||||
url: fw_url,
|
url: fw_url,
|
||||||
board: Some(board_type),
|
board: Some(board_type),
|
||||||
config: Some(board_config),
|
config: Some(board_config),
|
||||||
};
|
};
|
||||||
configs.push(cfg);
|
configs.push(cfg);
|
||||||
} else if path.is_dir() {
|
} else if path.is_dir() {
|
||||||
println!("Directory: {path:?}");
|
println!("Directory: {}", path.display());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(configs)
|
Ok(configs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prune_files(path: PathBuf, service: Services, keep_last: usize) {
|
pub fn prune_files(path: &PathBuf, service: &Services, keep_last: usize) {
|
||||||
let Ok(mut config_list) = get_files(&path, "irrelevant") else {
|
let Ok(mut config_list) = get_files(path, "irrelevant") else {
|
||||||
error!("failed to get file list for pruning");
|
error!("failed to get file list for pruning");
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
@@ -110,7 +110,7 @@ pub fn prune_files(path: PathBuf, service: Services, keep_last: usize) {
|
|||||||
if let Err(e) = fs::remove_file(&path_to_remove) {
|
if let Err(e) = fs::remove_file(&path_to_remove) {
|
||||||
error!("Failed to delete {path_to_remove}, {e:?}");
|
error!("Failed to delete {path_to_remove}, {e:?}");
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,13 +122,13 @@ mod tests {
|
|||||||
fn test_file_loading() {
|
fn test_file_loading() {
|
||||||
let expected_1 = OTAConfiguration {
|
let expected_1 = OTAConfiguration {
|
||||||
version: Version::parse("1.2.3").unwrap(),
|
version: Version::parse("1.2.3").unwrap(),
|
||||||
url: "example.com/firmware/waterlevel/INA233/1_2_3.bin".to_string(),
|
url: "example.com/firmware/waterlevel/INA233/1-2-3.bin".to_string(),
|
||||||
board: Some(BoardType::Waterlevel),
|
board: Some(BoardType::Waterlevel),
|
||||||
config: Some(BoardConfig::INA233),
|
config: Some(BoardConfig::INA233),
|
||||||
};
|
};
|
||||||
let expected_2 = OTAConfiguration {
|
let expected_2 = OTAConfiguration {
|
||||||
version: Version::parse("4.5.6").unwrap(),
|
version: Version::parse("4.5.6").unwrap(),
|
||||||
url: "example.com/firmware/waterlevel/INA226/4_5_6.bin".to_string(),
|
url: "example.com/firmware/waterlevel/INA226/4-5-6.bin".to_string(),
|
||||||
board: Some(BoardType::Waterlevel),
|
board: Some(BoardType::Waterlevel),
|
||||||
config: Some(BoardConfig::INA226),
|
config: Some(BoardConfig::INA226),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user