diff --git a/Cargo.lock b/Cargo.lock index 22fb771..aa579f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -189,7 +189,7 @@ name = "checkin-label" version = "0.1.0" dependencies = [ "brother-ql-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hackgt-nfc 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "hackgt-nfc 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rocket 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rocket_contrib 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rusb 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -591,7 +591,7 @@ dependencies = [ [[package]] name = "hackgt-nfc" -version = "0.3.5" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "graphql_client 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2223,7 +2223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum graphql_client_codegen 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dbbd911d25d37c6113fecbde95619869117a1903dad9dc0b94bbf1ac4c3d2747" "checksum graphql_query_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0d251ffd6428a2a6a0fde38539a3858816fa2aa70bcfcc0a16968c93d51d0c7" "checksum h2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9433d71e471c1736fd5a61b671fc0b148d7a2992f666c958d03cd8feb3b88d1" -"checksum hackgt-nfc 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fd892d72a848fe5d16d0fb6ff95408bb1b119a3f6812860282c712aef2277367" +"checksum hackgt-nfc 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "03bbbd715ddb6a31c5446b43da525ca394e9a7d2824516be478dc5d8bae09490" "checksum handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d82e5750d8027a97b9640e3fefa66bbaf852a35228e1c90790efd13c4b09c166" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" diff --git a/Cargo.toml b/Cargo.toml index aae6acc..6a71fc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] brother-ql-rs = "0.2.1" -hackgt-nfc = "0.3.6" +hackgt-nfc = "0.4.2" rocket = "0.4" serde = "1.0.104" rusb = "0.5.5" diff --git a/fonts/Raleway Bold.ttf b/fonts/Raleway Bold.ttf new file mode 100644 index 0000000..156d4a1 Binary files /dev/null and b/fonts/Raleway Bold.ttf differ diff --git a/render.png b/render.png deleted file mode 100644 index 8ac5660..0000000 Binary files a/render.png and /dev/null differ diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 0000000..ff17e10 --- /dev/null +++ b/src/api.rs @@ -0,0 +1,32 @@ +// use rocket_contrib::json::{ Json, JsonValue }; + +// #[derive(Deserialize)] +// pub struct DeviceRenameAction { +// username: String, +// name: String, +// } +// #[post("/device/rename", format = "json", data = "")] +// pub fn rename_device(request: Json, db: State) -> Result { +// let response = match Device::find_one(db.clone(), Some(doc! { "username": &request.username }), None)? { +// Some(device) => { +// device.update( +// db.clone(), +// None, +// doc! { "$set": { +// "friendly_name": request.name.clone(), +// } }, +// None +// )?; +// json!({ +// "success": true, +// }) +// }, +// None => { +// json!({ +// "success": false, +// "error": "Device not found", +// }) +// } +// }; +// Ok(response) +// } diff --git a/src/main.rs b/src/main.rs index 1703167..91223e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ #![feature(proc_macro_hygiene, decl_macro, never_type)] #[macro_use] extern crate rocket; -#[macro_use] extern crate rocket_contrib; +// #[macro_use] extern crate rocket_contrib; use rocket::State; use rocket_contrib::serve::StaticFiles; use rocket_contrib::templates::Template; @@ -10,16 +10,20 @@ use serde::Serialize; use hackgt_nfc::api::CheckinAPI; use hackgt_nfc::nfc::{ handle_cards, NFCBadge }; -use brother_ql_rs::printer::constants::label_data; use brother_ql_rs::printer::{ printers, ThermalPrinter }; use brother_ql_rs::text::TextRasterizer; +use std::fs::{ self, File }; +use std::io::Write; +use std::path::PathBuf; use std::collections::HashMap; use std::sync::{ Arc, RwLock }; +mod api; + type Threaded = Arc>; type ReaderAssignmentState = Threaded>; -type PrintersState = Threaded>>; +type PrintersState = Threaded>; // Maps a unique reader name to a printer's serial number #[derive(Debug)] @@ -29,6 +33,11 @@ struct PrinterAssignment { assigned_printer: Option, } +struct Printer { + device: ThermalPrinter, + rasterizer: TextRasterizer, +} + #[get("/")] fn index(reader_assignments: State, printers: State) -> Template { #[derive(Debug, Serialize)] @@ -42,9 +51,9 @@ fn index(reader_assignments: State, printers: State, printers: State Result { + let resources_directory = "./resources"; + + let font = include_bytes!("../fonts/Raleway Bold.ttf"); + let font_path = format!("{}/font.ttf", resources_directory); + let logo = include_bytes!("../logos/HackGT Mono.png"); + let logo_path = format!("{}/logo.png", resources_directory); + + let _ = fs::remove_dir_all(resources_directory); + fs::create_dir(resources_directory)?; + + let mut buffer = File::create(&font_path)?; + buffer.write_all(font)?; + let mut buffer = File::create(&logo_path)?; + buffer.write_all(logo)?; + + Ok(ResourcesPaths { + font: font_path, + logo: logo_path, + }) +} + fn main() { + let username = env!("CHECKIN_USERNAME"); + let password = env!("CHECKIN_PASSWORD"); + let url = env!("CHECKIN_URL"); + let api = CheckinAPI::login(username, password, url).expect("Failed to login to check in"); + + let resource_paths = setup_data().expect("Error extracting resources"); + + // TODO: update continuously let printers: HashMap = printers() .into_iter() .map(|device| { - let printer = ThermalPrinter::new(device).expect("Could not create printer"); - (printer.serial_number.clone(), printer) + let device = ThermalPrinter::new(device).expect("Could not create printer"); + + let mut rasterizer = TextRasterizer::new( + device.current_label().unwrap(), + PathBuf::from(&resource_paths.font) + ); + rasterizer.set_second_row_image(PathBuf::from(&resource_paths.logo)); + + (device.serial_number.clone(), Printer { + device, + rasterizer + }) }) .collect(); + if printers.len() == 0 { + panic!("No printers connected!"); + } + else { + println!("Found {} printer(s) and assigning readers in round-robin fashion", printers.len()); + } let printers: PrintersState = Arc::new(RwLock::new(printers)); let reader_assignments: ReaderAssignmentState = Arc::new(RwLock::new(HashMap::new())); - // let mut rasterizer = TextRasterizer::new( - // printers[0].current_label().unwrap(), - // PathBuf::from("./fonts/Space Mono Bold.ttf") - // ); - // rasterizer.set_second_row_image(PathBuf::from("./logos/HackGT Mono.png")); - - // let lines = rasterizer.rasterize("Hello, world!", None, 1.2, false); - // if let Err(err) = printers[0].print(lines) { - // eprintln!("Error during printing: {:?}", err); - // } - - // let username = env!("CHECKIN_USERNAME"); - // let password = env!("CHECKIN_PASSWORD"); - - // let api = CheckinAPI::login(username, password).expect("Failed to login to check in"); - let mut threads = Vec::new(); + let reader_assignments_tap_handler = Arc::clone(&reader_assignments); let reader_assignments_reader_handler = Arc::clone(&reader_assignments); + let printers_tap_handler = Arc::clone(&printers); + let printers_reader_handler = Arc::clone(&printers); let handler_thread = handle_cards(move |card, reader, _reader_index| { - dbg!(reader); - // handler_manager.get(*printer_id.unwrap(), move |printer| { - // let badge = NFCBadge::new(&card); - // badge.set_buzzer(false).unwrap(); - - // match badge.get_user_id() { - // Ok(id) => { - // match api.check_in(&id, "badge_label") { - // Ok((_success, user, _tag)) => { - // let major = user.questions.into_iter().find(|q| q.name == "major").map(|q| q.value.unwrap()); - // let major = major.as_ref().map(String::as_str); - - // let lines = rasterizer.rasterize(&user.name, dbg!(major), 1.2); - // if let Err(err) = printer.print(lines) { - // eprintln!("Error during printing: {:?}", err); - // } - // }, - // Err(hackgt_nfc::api::Error::Message("Invalid user ID on badge")) => { - // eprintln!("User ID <{}> does not exist", &id); - // }, - // Err(err) => { - // eprintln!("API error: {:?}", err); - // } - // }; - // }, - // Err(err) => { - // eprintln!("Error getting user ID: {:?}", err); - // } - // }; - // }); + let badge = NFCBadge::new(&card); + badge.set_buzzer(false).unwrap(); + + match badge.get_user_id() { + Ok(id) => { + match api.check_in(&id, "badge_label") { + Ok((_success, user, _tag)) => { + let reader_assignments = reader_assignments_tap_handler.read().unwrap(); + let printers = printers_tap_handler.read().unwrap(); + + let reader_name = reader.to_string_lossy().to_string(); + if let Some(serial_number) = reader_assignments + .get(&reader_name) + .map(|assignment| assignment.assigned_printer.as_ref()) + .flatten() + { + if let Some(printer) = printers.get(serial_number) { + let lines = printer.rasterizer.rasterize(&user.name, None, 1.0, false); + if let Err(err) = printer.device.print(lines) { + eprintln!("Error during printing: {:?}", err); + } + } + else { + eprintln!("No printer with serial number {}", &serial_number); + } + } + else { + eprintln!("No assignment for reader {}", &reader_name); + } + }, + Err(hackgt_nfc::api::Error::Message("Invalid user ID on badge")) => { + eprintln!("User ID <{}> does not exist", &id); + }, + Err(err) => { + eprintln!("API error: {:?}", err); + } + }; + }, + Err(err) => { + eprintln!("Error getting user ID: {:?}", err); + } + }; + }, move |reader, added| { let mut reader_assignments = reader_assignments_reader_handler.write().unwrap(); + let printers = printers_reader_handler.read().unwrap(); + + let next_printer_index = reader_assignments.len() % printers.len(); + // .iter() iterates in arbitrary order but printers never changes (TODO) so it's fine + let (next_printer_serial_number, _) = printers.iter().nth(next_printer_index).unwrap(); + let reader_name = reader.to_string_lossy().to_string(); reader_assignments .entry(reader_name.clone()) @@ -149,35 +214,37 @@ fn main() { .or_insert(PrinterAssignment { reader_connected: added, name: reader_name, - assigned_printer: None, + assigned_printer: Some(next_printer_serial_number.to_string()), }); }); threads.push(handler_thread); - let reader_assignments_server = Arc::clone(&reader_assignments); - let printers = Arc::clone(&printers); - let server_thread = std::thread::spawn(move || { - rocket::ignite() - .attach(Template::fairing()) - .mount("/", routes![index]) - // .mount("/api", routes![ - // api::initialize, - // api::create_credentials, - // api::get_tag, - // api::authorize_device, - // api::reject_device, - // api::force_renew_device, - // api::delete_device, - // api::rename_device, - // api::set_tag, - // ]) - .mount("/css", StaticFiles::from("src/ui/css")) - .mount("/js", StaticFiles::from("src/ui/js")) - .manage(reader_assignments_server) - .manage(printers) - .launch(); - }); - threads.push(server_thread); + // TODO: pack server dependencies into executable and reenable + + // let reader_assignments_server = Arc::clone(&reader_assignments); + // let printers = Arc::clone(&printers); + // let server_thread = std::thread::spawn(move || { + // rocket::ignite() + // .attach(Template::fairing()) + // .mount("/", routes![index]) + // // .mount("/api", routes![ + // // api::initialize, + // // api::create_credentials, + // // api::get_tag, + // // api::authorize_device, + // // api::reject_device, + // // api::force_renew_device, + // // api::delete_device, + // // api::rename_device, + // // api::set_tag, + // // ]) + // .mount("/css", StaticFiles::from("src/ui/css")) + // .mount("/js", StaticFiles::from("src/ui/js")) + // .manage(reader_assignments_server) + // .manage(printers) + // .launch(); + // }); + // threads.push(server_thread); for thread in threads { thread.join().unwrap();