Skip to content

Commit

Permalink
feat: added pcie stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
zleyyij committed Feb 17, 2024
1 parent e93f90c commit 6029d92
Show file tree
Hide file tree
Showing 6 changed files with 426 additions and 45 deletions.
35 changes: 32 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,46 @@ curl "http://localhost:3000/api/cpus/?name=Intel%20Core%20i9-9900k"
```

### USB
To interact with the USB API, submit a `GET` request to `/api/cpus/?name=[USB_IDENTIFIER_STRING]`, where `[USB_IDENTIFIER_STRING]` is a valid USB encoded string.
To interact with the USB API, submit a `GET` request to `/api/usbs/?identifier=[USB_IDENTIFIER_STRING]`, where `[USB_IDENTIFIER_STRING]` is a valid [USB identifier](https://learn.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-usb-devices).

The endpoint will return a structure that looks like this:
```json
{
"vendor": "string | null",
"vendor": "string",
"device": "string | null",
}
```

Responses:<br>
| Code | Meaning |
| -- | -- |
| `404` | No USB info was found with the given identifier |


Here's an example curl request:
```
curl "http://127.0.0.1:3000/api/usbs/?identifier=USB%5CVID_1532%26PID_0084%26MI_03%5C6%2638C0FA5D%260%260003"
```
```

### PCIe
To interact with the PCIe API, submit a `GET` request to `/api/pcie/?identifier=[PCIE_IDENTIFIER_STRING]`, where `[PCIE_IDENTIFIER_STRING]` is a valid [PCIe identifier](https://learn.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-pci-devices).

The endpoint will return a structure that looks like this:
```json
{
"vendor": "string",
"device": "string | null",
"subsystem": "string | null"
}
```

Responses:<br>
| Code | Meaning |
| -- | -- |
| `404` | No PCIe info was found with the given identifier |


Here's an example curl request:
```
curl "http://127.0.0.1:3000/api/pcie/?identifier=PCI%5CVEN_8086%26DEV_7A4D%26SUBSYS_00000000%26REV_11%5C3%2611583659%260%26A9%0A"
```
4 changes: 1 addition & 3 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ impl CpuCache {
/// Search the input string for the section that refers to the model of a CPU.
/// For example, given an input string of "AMD Ryzen 5 3600", it would try to return "3600"
fn find_model(input: &str) -> String {
// TODO: some models have spaces in them, eg "5600 PRO"
let mut best_fit = "";
let mut high_score: isize = -10;
for token in input.split(' ') {
Expand Down Expand Up @@ -142,7 +141,6 @@ fn find_model(input: &str) -> String {
let i_tag = tokens.filter(|t| t.len() == 2 && t.starts_with('i')).nth(0);
if let Some(t) = i_tag {
return format!("{}-{}M", t, best_fit);

}
}
}
Expand Down Expand Up @@ -210,7 +208,7 @@ mod tests {
),
(
"Intel® Core™ i7-620M Processor",
"Intel(R) Core(TM) i7 CPU M 620 @ 2.67Ghz"
"Intel(R) Core(TM) i7 CPU M 620 @ 2.67Ghz",
),
];

Expand Down
4 changes: 3 additions & 1 deletion src/cpu/intel/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use nom::bytes::complete::{tag, take_until};
use nom::sequence::{delimited, terminated};
use nom::IResult;

use crate::NomError;

/// Everything deserialized by the lexer
#[derive(Debug)]
pub struct LexerOutput<'a> {
Expand Down Expand Up @@ -79,7 +81,7 @@ fn read_record(input: &str) -> IResult<&str, Vec<&str>> {
fn read_section(input: &str) -> IResult<&str, &str> {
// read a line and discard it, the actual "header", then read until there are two newlines in a row
// this is nasty and could definitely be cleaned up a lot
let combinator_output: Result<(&str, &str), nom::Err<_>> = delimited(
let combinator_output: Result<(&str, &str), NomError> = delimited(
// read a whole line, this is discarded
terminated(take_until::<_, _, nom::error::Error<_>>("\n"), tag("\n")),
// read until two newlines in a row
Expand Down
54 changes: 47 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
mod cpu;
mod usb;
mod pcie;
mod usb;

use axum::extract::Query;
use axum::http::HeaderValue;
use axum::http::{HeaderValue, StatusCode};
use axum::{extract::State, routing::get, Json, Router};
use chrono::Local;
use clap::Parser;
use colored::*;
use cpu::{Cpu, CpuCache};
use log::info;
use log::{Level, LevelFilter, Metadata, Record};
use pcie::PcieCache;
use serde::{Deserialize, Serialize};
use std::env;
use tower_http::cors::CorsLayer;
use usb::UsbCache;

/// Because the error that nom uses is rather lengthy and unintuitive, it's defined here
/// to simplify handling
pub type NomError<'a> = nom::Err<nom::error::Error<&'a str>>;
/// https://docs.rs/log/latest/log/#implementing-a-logger
struct SimpleLogger;

Expand Down Expand Up @@ -58,6 +63,7 @@ static LOGGER: SimpleLogger = SimpleLogger;
struct AppState {
pub cpu_cache: CpuCache,
pub usb_cache: UsbCache,
pub pcie_cache: PcieCache,
}

#[derive(Debug, Deserialize, Serialize)]
Expand All @@ -76,13 +82,45 @@ struct UsbResponse {
async fn get_usb_handler(
State(state): State<AppState>,
Query(query): Query<UsbQuery>,
) -> Json<UsbResponse> {
) -> Result<Json<UsbResponse>, StatusCode> {
// TODO: update docs
let results = state.usb_cache.find(&query.identifier);
Json(UsbResponse {
vendor: results.0.map(|v| v.name),
device: results.1.map(|d| d.name),
})
match results {
Ok(r) => Ok(Json(UsbResponse {
vendor: r.0.map(|v| v.name),
device: r.1.map(|d| d.name),
})),
Err(_) => Err(StatusCode::NOT_FOUND),
}
}

#[derive(Debug, Deserialize, Serialize)]
struct PcieQuery {
identifier: String,
}

#[derive(Debug, Deserialize, Serialize)]
struct PcieResponse {
pub vendor: Option<String>,
pub device: Option<String>,
pub subsystem: Option<String>,
}

/// 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<AppState>,
Query(query): Query<PcieQuery>,
) -> Result<Json<PcieResponse>, 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(_) => Err(StatusCode::NOT_FOUND),
}
}

#[derive(Debug, Deserialize, Serialize)]
Expand Down Expand Up @@ -113,10 +151,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let app = Router::new()
.route("/api/cpus/", get(get_cpu_handler))
.route("/api/usbs/", get(get_usb_handler))
.route("/api/pcie", get(get_pcie_handler))
.layer(CorsLayer::new().allow_origin("*".parse::<HeaderValue>().unwrap()))
.with_state(AppState {
cpu_cache: CpuCache::new(),
usb_cache: UsbCache::new(),
pcie_cache: PcieCache::new(),
});

let mut port: String = String::from("3000");
Expand Down
Loading

0 comments on commit 6029d92

Please sign in to comment.