From e0315538a36be9ef558392264052da366db576a2 Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Sun, 19 Nov 2023 20:28:55 +0100 Subject: [PATCH] Add some error handling --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/index.html | 2 +- src/main.rs | 55 ++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 973f903..da8ed39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,6 +47,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + [[package]] name = "async-trait" version = "0.1.74" @@ -171,6 +177,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "elwa-dc" version = "0.1.0" dependencies = [ + "anyhow", "axum", "base64", "log", diff --git a/Cargo.toml b/Cargo.toml index e0c5214..0721848 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" dummy = [] [dependencies] +anyhow = "1.0.75" axum = "0.6.20" base64 = "0.21.5" log = "0.4.20" diff --git a/src/index.html b/src/index.html index 518ecf1..37d3aee 100644 --- a/src/index.html +++ b/src/index.html @@ -29,7 +29,7 @@

Zustand

Isolationsmessung: {11}

-

Gerätetemperatur: {12}

+

Gerätetemperatur: {12} °C

Status: {13}

DC Trenner: {14}

DC Relais: {15}

diff --git a/src/main.rs b/src/main.rs index 582b75d..47b68b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,10 @@ -use axum::{response::Html, routing::get, Router}; +use anyhow::Context; +use axum::{ + http::StatusCode, + response::{Html, IntoResponse, Response}, + routing::get, + Router, +}; use strum::{EnumIter, IntoEnumIterator}; #[derive(EnumIter, Debug)] @@ -68,6 +74,27 @@ struct Status<'a> { seriennummer: &'a str, } +struct AppError(anyhow::Error); + +impl IntoResponse for AppError { + fn into_response(self) -> Response { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Internal Server Error:\n{:?}", self.0), + ) + .into_response() + } +} + +impl From for AppError +where + E: Into, +{ + fn from(err: E) -> Self { + Self(err.into()) + } +} + #[tokio::main] async fn main() { let app = Router::new().route("/", get(handler)); @@ -78,10 +105,10 @@ async fn main() { .unwrap(); } -async fn handler() -> Html { +async fn handler() -> Result, AppError> { log::info!("Fetch new data"); - let data = read_device(); + let data = read_device().context("Could not retrieve device data")?; let data_string = std::str::from_utf8(&data).unwrap(); let mut status = Status::default(); @@ -127,7 +154,7 @@ async fn handler() -> Html { } } - Html(format!( + Ok(Html(format!( include_str!("index.html"), status.wassertemp, status.wassertemp_min, @@ -149,32 +176,34 @@ async fn handler() -> Html { status.betriebstag, status.firmware, status.seriennummer, - )) + ))) } #[cfg(not(feature = "dummy"))] -fn read_device() -> Vec { +fn read_device() -> anyhow::Result> { use std::io::{BufRead, BufReader}; use std::time::Duration; let mut port = serialport::new("/dev/ttyUSB0", 9600) - .timeout(Duration::from_secs(5)) + .timeout(Duration::from_millis(100)) .open() - .expect("Failed to open port"); + .context("Could not open serial device port")?; - write!(&mut port, "rs\r\n").expect("Write failed!"); + write!(&mut port, "rs\r\n").context("Could not write to serial connection")?; let mut reader = BufReader::new(port); let mut data: Vec = Vec::new(); - reader.read_until(b'\n', &mut data).expect("Found no data!"); + reader + .read_until(b'\n', &mut data) + .context("Could not read from serial connection")?; - data + Ok(data) } #[cfg(feature = "dummy")] -fn read_device() -> Vec { +fn read_device() -> anyhow::Result> { use base64::{engine::general_purpose, Engine as _}; const SAMPLE_OUTPUT: &str = "ZHIJVjEuMzEJMzUJMTIJMQkxCTEJMjM1CTE3NQkyNDUJNzU5CTY1MAkyNQk5MAkxODkuNQkxOTAuMDMJMS4xNDM1CTIxNy4yOQk3NzgJOTE3MjUJMAktNwk3LjkJNTI1CTM2OAkzNTgJMjQwCTEJMTIwMTAwMjMwMjEwMDAyMwk3NTkJNg0K"; - general_purpose::STANDARD.decode(SAMPLE_OUTPUT).unwrap() + Ok(general_purpose::STANDARD.decode(SAMPLE_OUTPUT)?) }