// Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] extern crate serial; use reqwest::Client; use serde::Deserialize; use serial::prelude::*; use std::io; use std::str::from_utf8; use std::time::Duration; #[derive(Debug)] struct BookData { title: String, authors: Vec, thumbnail: String, description: String, } #[allow(unused)] #[derive(Debug, Deserialize)] struct BookRoot { items: Vec, } #[allow(unused, non_snake_case)] #[derive(Debug, Deserialize)] struct Item { volumeInfo: VolumeInfo, } #[allow(unused, non_snake_case)] #[derive(Debug, Deserialize)] struct VolumeInfo { title: String, authors: Option>, description: Option, imageLinks: Option, } #[allow(unused, non_snake_case)] #[derive(Debug, Deserialize)] struct ImageLinks { thumbnail: Option, smallThumbnail: Option, } #[tokio::main] async fn main() { booklooker_lib::run(); let mut port = serial::open("/dev/ttyACM0").unwrap(); interact(&mut port).await.unwrap(); } async fn interact(port: &mut T) -> io::Result<()> { port.reconfigure(&|settings| { settings.set_baud_rate(serial::Baud9600)?; settings.set_char_size(serial::Bits8); settings.set_parity(serial::ParityNone); settings.set_stop_bits(serial::Stop1); settings.set_flow_control(serial::FlowNone); Ok(()) })?; port.set_timeout(Duration::from_millis(1000000000))?; loop { let buf: &mut [u8; 14] = &mut [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; port.read_exact(buf).unwrap(); let barcode_id = from_utf8(buf).unwrap(); println!("{}", &barcode_id); if barcode_id.starts_with("978") { get_book_data(barcode_id.to_string()).await; } } } async fn get_book_data(isbn: String) { let lookup_url = format!( "https://www.googleapis.com/books/v1/volumes?q=isbn:{}", isbn ); let cleint = Client::new(); let book_data = cleint .get(lookup_url) .send() .await .unwrap() .json::() .await .unwrap(); let book_metadata: Vec = book_data.items.into_iter().map(BookData::from).collect(); println!("{}", &book_metadata[0]); } impl From for BookData { fn from(item: Item) -> Self { let info = item.volumeInfo; BookData { title: info.title, authors: info.authors.unwrap_or_default(), description: info.description.as_deref().unwrap_or("").to_string(), thumbnail: info .imageLinks .as_ref() .and_then(|links| links.thumbnail.as_deref()) .unwrap_or("") .to_string(), } } } impl std::fmt::Display for BookData { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "Title: {}\nAuthors: {}\nDescription: {}\nThumbnail: {}", self.title, if self.authors.is_empty() { "Unknown".to_string() } else { self.authors.join(", ") }, if self.description.is_empty() { "No description available".to_string() } else { self.description.clone() }, self.thumbnail ) } }