Switch barcode flow to blocking IO and bump deps

Convert barcode types to i64 and add a manual input field. Remove the
tokio Runtime and use reqwest::blocking for Google Books. Adjust serial
handling (Sender<i64>, added logging, shorter recv timeout, clear port
on disconnect, and faster UI repaint to prevent "app not responding").
Bump reqwest to 0.13.1, serde_json to 1.0.148 and update Cargo.lock with
required TLS/quinn deps.
This commit is contained in:
Robin Löhn 2025-12-31 16:36:23 +01:00
commit 7d96d889ec
Signed by: robin
GPG key ID: 3628294D3FA576AD
7 changed files with 302 additions and 55 deletions

244
Cargo.lock generated
View file

@ -560,6 +560,28 @@ dependencies = [
"arrayvec",
]
[[package]]
name = "aws-lc-rs"
version = "1.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288"
dependencies = [
"aws-lc-sys",
"zeroize",
]
[[package]]
name = "aws-lc-sys"
version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1"
dependencies = [
"cc",
"cmake",
"dunce",
"fs_extra",
]
[[package]]
name = "barcode-analyser"
version = "0.1.0"
@ -573,7 +595,7 @@ dependencies = [
"log",
"open-library",
"openfoodfacts",
"reqwest 0.12.28",
"reqwest 0.13.1",
"serde",
"serde_json",
"serial",
@ -822,6 +844,15 @@ dependencies = [
"error-code",
]
[[package]]
name = "cmake"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
dependencies = [
"cc",
]
[[package]]
name = "codespan-reporting"
version = "0.12.0"
@ -1557,6 +1588,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "fs_extra"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "futures-channel"
version = "0.3.31"
@ -1649,8 +1686,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasm-bindgen",
]
[[package]]
@ -1660,9 +1699,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"r-efi",
"wasip2",
"wasm-bindgen",
]
[[package]]
@ -2513,6 +2554,12 @@ dependencies = [
"imgref",
]
[[package]]
name = "lru-slab"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
[[package]]
name = "malloc_buf"
version = "0.0.6"
@ -2655,10 +2702,10 @@ dependencies = [
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-probe 0.1.6",
"openssl-sys",
"schannel",
"security-framework",
"security-framework 2.11.1",
"security-framework-sys",
"tempfile",
]
@ -3171,6 +3218,12 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-probe"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391"
[[package]]
name = "openssl-sys"
version = "0.9.111"
@ -3512,6 +3565,62 @@ dependencies = [
"memchr",
]
[[package]]
name = "quinn"
version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
dependencies = [
"bytes",
"cfg_aliases",
"pin-project-lite",
"quinn-proto",
"quinn-udp",
"rustc-hash 2.1.1",
"rustls",
"socket2 0.6.1",
"thiserror 2.0.17",
"tokio",
"tracing",
"web-time",
]
[[package]]
name = "quinn-proto"
version = "0.11.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
dependencies = [
"aws-lc-rs",
"bytes",
"getrandom 0.3.4",
"lru-slab",
"rand 0.9.2",
"ring",
"rustc-hash 2.1.1",
"rustls",
"rustls-pki-types",
"slab",
"thiserror 2.0.17",
"tinyvec",
"tracing",
"web-time",
]
[[package]]
name = "quinn-udp"
version = "0.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
dependencies = [
"cfg_aliases",
"libc",
"once_cell",
"socket2 0.6.1",
"tracing",
"windows-sys 0.60.2",
]
[[package]]
name = "quote"
version = "1.0.42"
@ -3808,6 +3917,48 @@ dependencies = [
"web-sys",
]
[[package]]
name = "reqwest"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62"
dependencies = [
"base64 0.22.1",
"bytes",
"encoding_rs",
"futures-channel",
"futures-core",
"futures-util",
"h2 0.4.12",
"http 1.4.0",
"http-body 1.0.1",
"http-body-util",
"hyper 1.8.1",
"hyper-rustls",
"hyper-util",
"js-sys",
"log",
"mime",
"percent-encoding",
"pin-project-lite",
"quinn",
"rustls",
"rustls-pki-types",
"rustls-platform-verifier",
"serde",
"serde_json",
"sync_wrapper 1.0.2",
"tokio",
"tokio-rustls",
"tower",
"tower-http",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "rgb"
version = "0.8.52"
@ -3872,6 +4023,7 @@ version = "0.23.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
dependencies = [
"aws-lc-rs",
"once_cell",
"rustls-pki-types",
"rustls-webpki",
@ -3879,6 +4031,18 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rustls-native-certs"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
dependencies = [
"openssl-probe 0.2.0",
"rustls-pki-types",
"schannel",
"security-framework 3.5.1",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.4"
@ -3894,15 +4058,44 @@ version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
dependencies = [
"web-time",
"zeroize",
]
[[package]]
name = "rustls-platform-verifier"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784"
dependencies = [
"core-foundation 0.10.0",
"core-foundation-sys",
"jni",
"log",
"once_cell",
"rustls",
"rustls-native-certs",
"rustls-platform-verifier-android",
"rustls-webpki",
"security-framework 3.5.1",
"security-framework-sys",
"webpki-root-certs",
"windows-sys 0.61.2",
]
[[package]]
name = "rustls-platform-verifier-android"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
[[package]]
name = "rustls-webpki"
version = "0.103.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
dependencies = [
"aws-lc-rs",
"ring",
"rustls-pki-types",
"untrusted",
@ -3976,6 +4169,19 @@ dependencies = [
"security-framework-sys",
]
[[package]]
name = "security-framework"
version = "3.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef"
dependencies = [
"bitflags 2.10.0",
"core-foundation 0.10.0",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.15.0"
@ -4018,9 +4224,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.147"
version = "1.0.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6af14725505314343e673e9ecb7cd7e8a36aa9791eb936235a3567cc31447ae4"
checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da"
dependencies = [
"itoa",
"memchr",
@ -4505,6 +4711,21 @@ dependencies = [
"zerovec",
]
[[package]]
name = "tinyvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.48.0"
@ -5056,6 +5277,15 @@ dependencies = [
"web-sys",
]
[[package]]
name = "webpki-root-certs"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee3e3b5f5e80bc89f30ce8d0343bf4e5f12341c51f3e26cbeecbc7c85443e85b"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "weezl"
version = "0.1.12"
@ -6106,9 +6336,9 @@ dependencies = [
[[package]]
name = "zmij"
version = "0.1.9"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0095ecd462946aa3927d9297b63ef82fb9a5316d7a37d134eeb36e58228615a"
checksum = "e6d6085d62852e35540689d1f97ad663e3971fc19cf5eceab364d62c646ea167"
[[package]]
name = "zune-core"

View file

@ -35,8 +35,8 @@ strip = "debuginfo"
[dependencies]
tokio = { version = "1.48.0", features = ["full"] }
reqwest = { version = "0.12.28", features = ["json"] }
serde_json = "1.0.147"
reqwest = { version = "0.13.1", features = ["json", "blocking"] }
serde_json = "1.0.148"
serde = { version = "1.0.228", features = ["derive"] }
log = "0.4.29"
env_logger = "0.11.8"

View file

@ -12,7 +12,6 @@ use std::{
};
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
use tokio::runtime::Runtime;
#[derive(Default, Debug, PartialEq, EnumIter, Clone)]
enum ScannerSetting {
@ -29,9 +28,10 @@ pub struct BarcodeScanner {
open_food_facts_data: Data,
new_port: String,
pub port: String,
pub current_barcode: i32,
last_barcode: i32,
serial_rx: Option<mpsc::Receiver<i32>>,
pub current_barcode: i64,
man_barcode: String,
last_barcode: i64,
serial_rx: Option<mpsc::Receiver<i64>>,
serial_handle: Option<thread::JoinHandle<()>>,
}
@ -49,22 +49,27 @@ impl std::fmt::Display for ScannerSetting {
impl eframe::App for BarcodeScanner {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
let runtime = Runtime::new().unwrap();
egui_extras::install_image_loaders(ctx);
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Barcode Scanner");
// Get check if we got a new Barcode and get the needed data
if self.current_barcode != self.last_barcode {
info!("Getting new data for barcode: {}", self.current_barcode);
let openfoodfacts_future = get_open_food_facts_data(self.current_barcode);
let googlebookapi_future = get_google_book_data(self.current_barcode);
self.google_book_data = get_google_book_data(self.current_barcode);
self.open_food_facts_data = get_open_food_facts_data(self.current_barcode);
self.last_barcode = self.current_barcode;
self.open_food_facts_data = Runtime::block_on(&runtime, openfoodfacts_future);
self.google_book_data = Runtime::block_on(&runtime, googlebookapi_future);
}
// Display the current barcode
ui.label(format!("Barcode: {}", &self.last_barcode.to_string()));
if self.scanner_setting == ScannerSetting::Manual {
let man_barcode_field = ui.text_edit_singleline(&mut self.man_barcode);
if !man_barcode_field.has_focus()
&& !self.man_barcode.is_empty()
&& self.current_barcode.to_string() != self.man_barcode
{
self.current_barcode = self.man_barcode.trim().parse::<i64>().unwrap();
}
}
// Columns for data sources
ui.columns(2, |column| {
@ -106,12 +111,10 @@ impl eframe::App for BarcodeScanner {
let port = ui.text_edit_singleline(&mut self.new_port);
if !port.has_focus() && !self.new_port.is_empty() && self.new_port != self.port {
self.port = self.new_port.clone();
let (tx, rx) = mpsc::channel();
let (tx, rx) = mpsc::channel::<i64>();
let port_clone = self.port.clone();
self.serial_rx = Some(rx);
self.serial_handle = Some(thread::spawn(move || read_serial(port_clone, tx)));
// TODO!
// let task = tokio::spawn(async move { println!("Serial Port change") });
}
if self.port.is_empty() {
@ -123,13 +126,14 @@ impl eframe::App for BarcodeScanner {
// Check the recv if we got new data. If the recv is disconected we panic as this is not supose to happen
if self.scanner_setting == ScannerSetting::Serial && !self.port.is_empty() {
match &self.serial_rx {
Some(v) => match v.recv_timeout(Duration::from_secs(1)) {
Some(v) => match v.recv_timeout(Duration::from_millis(10)) {
Ok(recv) => {
self.current_barcode = recv;
}
Err(e) => {
if e == RecvTimeoutError::Disconnected {
panic!("Serial Port is inialized but no reciver is active");
self.port = String::new();
self.new_port = String::new();
}
}
},
@ -137,6 +141,6 @@ impl eframe::App for BarcodeScanner {
}
}
});
ctx.request_repaint_after(Duration::from_millis(100));
ctx.request_repaint_after(Duration::from_millis(50));
}
}

View file

@ -2,8 +2,8 @@ use serde::Serialize;
#[allow(unused)]
#[derive(Debug, Clone, Serialize)]
pub struct BookData<'a> {
pub title: &'a String,
pub struct BookData {
pub title: String,
pub authors: Vec<String>,
pub description: String,
}
@ -13,7 +13,7 @@ pub struct Data {
pub data: String,
}
impl<'a> std::fmt::Display for BookData<'a> {
impl std::fmt::Display for BookData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,

View file

@ -16,7 +16,11 @@ pub fn read_serial(port: String) {
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn read_serial(port: String, tx: mpsc::Sender<i32>) {
pub fn read_serial(port: String, tx: mpsc::Sender<i64>) {
info!("Your log level is set to info");
debug!("Your log level is set to debug");
warn!("Your log level is set to warn");
error!("Your log level is set to error");
let mut port = serial::open(&port).unwrap();
port
.reconfigure(&|settings| {
@ -30,15 +34,13 @@ pub fn read_serial(port: String, tx: mpsc::Sender<i32>) {
.unwrap();
loop {
port.set_timeout(Duration::from_millis(1000)).unwrap();
port.set_timeout(Duration::from_millis(1000000000)).unwrap();
let buf: &mut [u8; 14] = &mut [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
info!("Reading from Port");
port.read_exact(buf).unwrap();
let barcode_id = from_utf8(buf).unwrap();
debug!("{}", &barcode_id);
if let Ok(val) = barcode_id.trim().parse::<i32>() {
let _ = tx.send(val);
}
info!("{}", &barcode_id);
info!("Sending barcode: {}", &barcode_id);
let _ = tx.send(barcode_id.trim().parse::<i64>().unwrap());
}
}

View file

@ -1,5 +1,5 @@
use crate::app::bookdata::{BookData, Data};
use reqwest::Client;
use reqwest::blocking::Client;
use serde::{Deserialize, Serialize};
#[allow(unused)]
@ -30,46 +30,57 @@ struct ImageLinks {
smallThumbnail: Option<String>,
}
pub async fn get_google_book_data(ean13: i32) -> Data {
pub fn get_google_book_data(ean13: i64) -> Data {
let url = format!(
"https://www.googleapis.com/books/v1/volumes?q=isbn:{}",
ean13,
);
let cleint = Client::new();
let bookdata = cleint
.get(url)
let client = Client::new();
let result = client
.get(&url)
.send()
.await
.unwrap()
.json::<BookRoot>()
.await
.unwrap();
.and_then(|resp| resp.json::<BookRoot>());
Data {
has_data: true,
data: convert_to_string(bookdata.items.first().unwrap()).await,
match result {
Ok(bookroot) => {
if let Some(item) = bookroot.items.first() {
Data {
has_data: true,
data: convert_to_string(item),
}
} else {
Data {
has_data: false,
data: String::new(),
}
}
}
Err(_) => Data {
has_data: false,
data: String::new(),
},
}
}
async fn convert_to_string(data: &Item) -> String {
let mut data = data.clone();
fn convert_to_string(data: &Item) -> String {
let data = data.clone();
let bookdata = data.to_bookdata();
format!("{}", bookdata)
}
impl Item {
pub fn to_bookdata(&mut self) -> BookData<'_> {
pub fn to_bookdata(self) -> BookData {
let mut authors: Vec<String> = Vec::new();
let mut description = String::new();
if let Some(se) = self.volumeInfo.authors.take() {
if let Some(se) = self.volumeInfo.authors {
authors = se;
}
if let Some(se) = self.volumeInfo.description.take() {
if let Some(se) = self.volumeInfo.description {
description = se;
}
BookData {
title: &self.volumeInfo.title,
title: self.volumeInfo.title,
authors,
description,
}

View file

@ -4,7 +4,7 @@ use openfoodfacts as off;
use serde_json::{Value, json};
use std::collections::HashMap;
pub async fn get_open_food_facts_data(ean13: i32) -> Data {
pub fn get_open_food_facts_data(ean13: i64) -> Data {
let mut result = Data::default();
let client = off::v2().build().unwrap();
let data = client.product(ean13.to_string().as_str(), None).unwrap();