diff --git a/Cargo.lock b/Cargo.lock index f1b748e..86f3c1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -400,7 +400,6 @@ dependencies = [ "clap", "colored", "http", - "levenshtein", "log", "nom", "parsing", @@ -490,12 +489,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "levenshtein" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" - [[package]] name = "libc" version = "0.2.153" diff --git a/server/Cargo.toml b/server/Cargo.toml index 95135e1..578d3fd 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -17,7 +17,6 @@ chrono = "0.4.32" clap = { version = "4.0", features = ["derive"] } colored = "2.1.0" http = "1.0.0" -levenshtein = "1.0.5" nom = "7.1.3" log = "0.4.20" serde = { version = "1.0.195", features = ["derive"] } diff --git a/server/build.rs b/server/build.rs index 45100ab..39a6d67 100644 --- a/server/build.rs +++ b/server/build.rs @@ -6,8 +6,8 @@ use std::path::Path; fn main() { // TODO: configure cargo to rerun only if the database changes - println!("cargo::rerun-if-changed=../parsing/src/cpu/amd/input.json"); - println!("cargo::rerun-if-changed=../parsing/src/cpu/intel/chunks/*"); + // println!("cargo::rerun-if-changed=../parsing/src/cpu/amd/input.json"); + println!("cargo::rerun-if-changed=build.rs"); gen_amd_cpus(); gen_intel_cpus(); } @@ -32,7 +32,7 @@ fn gen_amd_cpus() { } write!( &mut generated_file, - "// This file was autogenerated by build.rs\npub static AMD_CPUS: phf::Map<&'static str, phf::Map<&'static str, &'static str>> = {}", + "// This file was autogenerated by build.rs\n#[rustfmt::skip]\n#[allow(clippy::all)]\npub static AMD_CPUS: phf::Map<&'static str, phf::Map<&'static str, &'static str>> = {}", generated_map.build() ) .unwrap(); @@ -59,7 +59,7 @@ fn gen_intel_cpus() { } write!( &mut generated_file, - "// This file was autogenerated by build.rs\npub static INTEL_CPUS: phf::Map<&'static str, phf::Map<&'static str, &'static str>> = {}", + "// This file was autogenerated by build.rs\n#[rustfmt::skip]\n#[allow(clippy::all)]\npub static INTEL_CPUS: phf::Map<&'static str, phf::Map<&'static str, &'static str>> = {}", generated_map.build() ) .unwrap(); diff --git a/server/src/handlers/mod.rs b/server/src/handlers/mod.rs new file mode 100644 index 0000000..7365c13 --- /dev/null +++ b/server/src/handlers/mod.rs @@ -0,0 +1,145 @@ +use crate::cpu::Cpu; +use crate::AppState; +use axum::extract::Query; +use axum::http::StatusCode; +use axum::{extract::State, Json}; +use log::{error, warn}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct UsbQuery { + pub identifier: String, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct UsbResponse { + pub vendor: Option, + pub device: Option, +} + +/// This handler accepts a `GET` request to `/api/usbs/?identifier`. +/// It relies on a globally shared [AppState] to re-use the usb cache. +pub async fn get_usb_handler( + State(state): State, + Query(query): Query, +) -> Result, StatusCode> { + // TODO: update docs + let results = state.usb_cache.find(&query.identifier); + match results { + Ok(r) => Ok(Json(UsbResponse { + vendor: r.0.map(|v| v.name), + device: r.1.map(|d| d.name), + })), + Err(e) => { + error!("usb handler error: {:?} caused by query: {:?}", e, query); + Err(StatusCode::NOT_FOUND) + } + } +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct GetPcieQuery { + identifier: String, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct PcieResponse { + pub vendor: Option, + pub device: Option, + pub subsystem: Option, +} + +/// This handler accepts a `GET` request to `/api/pcie/?identifier`. +/// It relies on a globally shared [AppState] to re-use the pcie cache +pub async fn get_pcie_handler( + State(state): State, + Query(query): Query, +) -> Result, StatusCode> { + let results = state.pcie_cache.find(&query.identifier); + match results { + Ok(r) => Ok(Json(PcieResponse { + vendor: r.0.map(|v| v.name), + device: r.1.map(|d| d.name), + subsystem: r.2.map(|s| s.name), + })), + Err(e) => { + error!("pcie handler error: {:?} caused by query: {:?}", e, query); + Err(StatusCode::NOT_FOUND) + } + } +} + +/// This handler accepts a `POST` request to `/api/pcie/`, with a body containing a serialized array of strings. +/// It relies on a globally shared [AppState] to re-use the pcie cache, and is largely identical to [get_pcie_handler], but +/// is intended for batching +pub async fn post_pcie_handler( + State(state): State, + Json(query): Json>, +) -> Result>>, StatusCode> { + let mut response: Vec> = Vec::with_capacity(16); + for entry in query { + match state.pcie_cache.find(&entry) { + Ok(r) => response.push(Some(PcieResponse { + vendor: r.0.map(|v| v.name), + device: r.1.map(|d| d.name), + subsystem: r.2.map(|s| s.name), + })), + Err(e) => { + warn!("post pcie handler error: when processing the device identifier {:?}, an error was returned: {:?}", entry, e); + response.push(None); + } + } + } + Ok(Json(response)) +} + +/// This handler accepts a `POST` request to `/api/usbs/`, with a body containing a serialized array of usb device identifier strings. +/// It relies on a globally shared [AppState] to re-use the pcie cache, and is largely identical to [get_usb_handler], but +/// is intended for batching +pub async fn post_usbs_handler( + State(state): State, + Json(query): Json>, +) -> Result>>, StatusCode> { + let mut response: Vec> = Vec::with_capacity(16); + for entry in query { + match state.usb_cache.find(&entry) { + Ok(r) => response.push(Some(UsbResponse { + vendor: r.0.map(|v| v.name), + device: r.1.map(|d| d.name), + })), + Err(e) => { + warn!("post usb handler error: when processing the device identifier {:?}, an error was returned: {:?}", entry, e); + response.push(None); + } + } + } + Ok(Json(response)) +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct CpuQuery { + pub name: String, +} + +/// This handler accepts a `GET` request to `/api/cpus/?name=[CPU_NAME]`. +/// It relies on a globally shared [AppState] to re-use the cpu cache, and responds to the request with a serialized [Cpu]. +/// It will always attempt to find a cpu, and should always return a cpu. The correctness of the return value is not guaranteed. +pub async fn get_cpu_handler( + State(mut state): State, + Query(query): Query, +) -> Result>, StatusCode> { + match state.cpu_cache.find(&query.name) { + Ok(c) => Ok(Json(Cpu { + name: c.name.to_string(), + attributes: c + .attributes + .iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect(), + })), + Err(e) => { + error!("cpu handler error {:?} caused by query {:?}", e, query); + Err(StatusCode::NOT_FOUND) + } + } +} diff --git a/server/src/main.rs b/server/src/main.rs index ac927f3..e3e9022 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,20 +1,20 @@ mod cpu; +mod handlers; -use axum::extract::Query; -use axum::http::{HeaderValue, StatusCode}; +use axum::http::HeaderValue; use axum::routing::post; -use axum::{extract::State, routing::get, Json, Router}; +use axum::{routing::get, Router}; use chrono::Local; use clap::builder::TypedValueParser; use clap::{Parser, ValueEnum}; use colored::*; -use cpu::{Cpu, CpuCache}; +use cpu::CpuCache; +use handlers::*; use http::{header, Method}; -use log::{error, info, warn}; +use log::info; use log::{Level, LevelFilter, Metadata, Record}; use parsing::pcie::PcieCache; use parsing::usb::UsbCache; -use serde::{Deserialize, Serialize}; use std::env; use tower_http::cors::CorsLayer; @@ -85,144 +85,6 @@ struct AppState { pub pcie_cache: PcieCache, } -#[derive(Debug, Deserialize, Serialize)] -struct UsbQuery { - pub identifier: String, -} - -#[derive(Debug, Deserialize, Serialize)] -struct UsbResponse { - pub vendor: Option, - pub device: Option, -} - -/// This handler accepts a `GET` request to `/api/usbs/?identifier`. -/// It relies on a globally shared [AppState] to re-use the usb cache. -async fn get_usb_handler( - State(state): State, - Query(query): Query, -) -> Result, StatusCode> { - // TODO: update docs - let results = state.usb_cache.find(&query.identifier); - match results { - Ok(r) => Ok(Json(UsbResponse { - vendor: r.0.map(|v| v.name), - device: r.1.map(|d| d.name), - })), - Err(e) => { - error!("usb handler error: {:?} caused by query: {:?}", e, query); - Err(StatusCode::NOT_FOUND) - } - } -} - -#[derive(Debug, Deserialize, Serialize)] -struct GetPcieQuery { - identifier: String, -} - -#[derive(Debug, Deserialize, Serialize)] -struct PcieResponse { - pub vendor: Option, - pub device: Option, - pub subsystem: Option, -} - -/// This handler accepts a `GET` request to `/api/pcie/?identifier`. -/// It relies on a globally shared [AppState] to re-use the pcie cache -async fn get_pcie_handler( - State(state): State, - Query(query): Query, -) -> Result, StatusCode> { - let results = state.pcie_cache.find(&query.identifier); - match results { - Ok(r) => Ok(Json(PcieResponse { - vendor: r.0.map(|v| v.name), - device: r.1.map(|d| d.name), - subsystem: r.2.map(|s| s.name), - })), - Err(e) => { - error!("pcie handler error: {:?} caused by query: {:?}", e, query); - Err(StatusCode::NOT_FOUND) - } - } -} - -/// This handler accepts a `POST` request to `/api/pcie/`, with a body containing a serialized array of strings. -/// It relies on a globally shared [AppState] to re-use the pcie cache, and is largely identical to [get_pcie_handler], but -/// is intended for batching -async fn post_pcie_handler( - State(state): State, - Json(query): Json>, -) -> Result>>, StatusCode> { - let mut response: Vec> = Vec::with_capacity(16); - for entry in query { - match state.pcie_cache.find(&entry) { - Ok(r) => response.push(Some(PcieResponse { - vendor: r.0.map(|v| v.name), - device: r.1.map(|d| d.name), - subsystem: r.2.map(|s| s.name), - })), - Err(e) => { - warn!("post pcie handler error: when processing the device identifier {:?}, an error was returned: {:?}", entry, e); - response.push(None); - } - } - } - Ok(Json(response)) -} - -/// This handler accepts a `POST` request to `/api/usbs/`, with a body containing a serialized array of usb device identifier strings. -/// It relies on a globally shared [AppState] to re-use the pcie cache, and is largely identical to [get_usb_handler], but -/// is intended for batching -async fn post_usbs_handler( - State(state): State, - Json(query): Json>, -) -> Result>>, StatusCode> { - let mut response: Vec> = Vec::with_capacity(16); - for entry in query { - match state.usb_cache.find(&entry) { - Ok(r) => response.push(Some(UsbResponse { - vendor: r.0.map(|v| v.name), - device: r.1.map(|d| d.name), - })), - Err(e) => { - warn!("post usb handler error: when processing the device identifier {:?}, an error was returned: {:?}", entry, e); - response.push(None); - } - } - } - Ok(Json(response)) -} - -#[derive(Debug, Deserialize, Serialize)] -struct CpuQuery { - pub name: String, -} - -/// This handler accepts a `GET` request to `/api/cpus/?name=[CPU_NAME]`. -/// It relies on a globally shared [AppState] to re-use the cpu cache, and responds to the request with a serialized [Cpu]. -/// It will always attempt to find a cpu, and should always return a cpu. The correctness of the return value is not guaranteed. -async fn get_cpu_handler( - State(mut state): State, - Query(query): Query, -) -> Result>, StatusCode> { - match state.cpu_cache.find(&query.name) { - Ok(c) => Ok(Json(Cpu { - name: c.name.to_string(), - attributes: c - .attributes - .iter() - .map(|(k, v)| (k.to_string(), v.to_string())) - .collect(), - })), - Err(e) => { - error!("cpu handler error {:?} caused by query {:?}", e, query); - Err(StatusCode::NOT_FOUND) - } - } -} - #[tokio::main] async fn main() -> Result<(), Box> { // initialize logging