Skip to content

Commit

Permalink
better error handling & new arg
Browse files Browse the repository at this point in the history
  • Loading branch information
gpskwlkr committed Mar 30, 2024
1 parent 3e92a6a commit 713f41f
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 24 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ Cargo.lock
*.pdb

shell.nix

*.zip
*.tar.gz
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "protondb-check"
version = "0.2.2"
version = "0.3.2"
edition = "2021"
license = "MIT"
description = "CLI tool for checking ProtonDB rating of your Steam games."
Expand Down
37 changes: 37 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Define the targets and their respective filenames
TARGET_LINUX = x86_64-unknown-linux-gnu
TARGET_WINDOWS = x86_64-pc-windows-gnu
OUT_DIR_LINUX = target/$(TARGET_LINUX)/release
OUT_DIR_WINDOWS = target/$(TARGET_WINDOWS)/release
PROJECT_NAME = protondb-check
TAR_FILE = $(PROJECT_NAME)_$(TARGET_LINUX).tar.gz
ZIP_FILE = $(PROJECT_NAME)_$(TARGET_WINDOWS).zip

# Default target
all: build pack

linux:
cargo build --release --target=$(TARGET_LINUX)
tar -czvf $(TAR_FILE) -C $(OUT_DIR_LINUX) $(PROJECT_NAME)

windows:
cargo build --release --target=$(TARGET_WINDOWS)
zip -r $(ZIP_FILE) $(OUT_DIR_WINDOWS)/$(PROJECT_NAME).exe

# Build the project for Linux and Windows
build:
cargo build --release --target=$(TARGET_LINUX)
cargo build --release --target=$(TARGET_WINDOWS)

# Pack the built binaries
pack:
tar -czvf $(TAR_FILE) -C $(OUT_DIR_LINUX) $(PROJECT_NAME)
zip -r $(ZIP_FILE) $(OUT_DIR_WINDOWS)/$(PROJECT_NAME).exe

# Clean up the build artifacts
clean:
cargo clean
rm -f $(TAR_FILE) $(ZIP_FILE)

.PHONY: all build pack clean

7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@ ProtonDB Checker.

# Available commands

> While `-p` or `-a` are both listed as not required, at least one should be provided.
| Command | Args | Required | Example |
| -------------- | ------------------- | -------- | ------------------------------------- |
| protondb-check | `-p` `--profile-id` | Yes | `protondb-check -p 76561198354374976` |
| protondb-check | `-p` `--profile-id` | No | `protondb-check -p 76561198354374976` |
| protondb-check | `-a` `--app-id` | No | `protondb-check -a 271590` |

# Install

Expand All @@ -52,7 +55,7 @@ You can install `protondb-check` via

`cargo install protondb-check`

or using prebuilt binaries on the [Releases]() page.
or using prebuilt binaries on the [Releases](https://github.com/gpskwlkr/protondb-check/releases) page.

## MacOS

Expand Down
21 changes: 17 additions & 4 deletions src/args.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use clap::{Parser, Subcommand};
use anyhow::{anyhow, Result, Context};

#[derive(Subcommand)]
enum Command {
Expand All @@ -8,12 +9,24 @@ enum Command {
#[command(author, version, about, long_about = None)]
pub struct Args {
/// Steam profile ID
#[arg(short = 'p', long = "profile-id", required = true)]
pub profile_id: String,
#[arg(short = 'p', long = "profile-id", required = false)]
pub profile_id: Option<String>,

///
#[arg(short = 'a', long = "app-id", required = false)]
pub app_id: Option<u32>,
}

impl Args {
pub fn new() -> Self {
Args::parse()
pub fn new() -> Result<Self> {
Ok(Args::parse())
}

pub fn validate_args(&self) -> Result<(), anyhow::Error> {
if self.profile_id.is_none() && self.app_id.is_none() {
return Err(anyhow!("Either --profile-id or --app-id must be provided")).with_context(|| "validate_args");
}

Ok(())
}
}
38 changes: 30 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
use args::Args;
use itertools::Itertools;
use anyhow::anyhow;
use anyhow::{anyhow, Result, Context};

mod structs;
mod utils;
mod args;

fn main() -> Result<(), anyhow::Error> {
use terminal_menu::{menu, label, button, run, mut_menu};
fn main() -> Result<()> {
let args = Args::new()?;

args.validate_args()?;

if args.app_id.is_some() {
handle_app_id(args)?;
} else {
handle_profile_id(args)?;
}

Ok(())
}

fn handle_profile_id(args: Args) -> Result<()> {

let args = args::Args::new();
use terminal_menu::{menu, label, button, run, mut_menu};

let steam_profile_id:u64 = match args.profile_id.parse() {
let steam_profile_id:u64 = match args.profile_id.unwrap().parse() {
Ok(value) => value,
Err(_error) => {
return Err(anyhow!("Please provide valid Steam profile ID."))
return Err(anyhow!("Please provide valid Steam profile ID.")).with_context(|| "handle_profile_id")
}
};

Expand All @@ -37,10 +51,18 @@ fn main() -> Result<(), anyhow::Error> {
{
let mm = mut_menu(&menu);
let game = games_list.get(mm.selected_item_name()).unwrap();
let proton_response = utils::check_proton_db(&game.app_id);
let proton_response = utils::check_proton_db(&game.app_id)?;

utils::output(&proton_response, &game.app_id, &game.name);
utils::output(&proton_response, &game.app_id, Some(&game.name));
}

Ok(())
}

fn handle_app_id(args: Args) -> Result<()> {
let app_id = args.app_id.unwrap();
let proton_response = utils::check_proton_db(&app_id)?;
utils::output(&proton_response, &app_id, None);

Ok(())
}
26 changes: 17 additions & 9 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::HashMap;
use reqwest::blocking::get;
use anyhow::anyhow;
use anyhow::{anyhow, Result, Context};

use crate::structs::{GamesList, Game, ProtonAPIResponse};

Expand All @@ -12,13 +12,13 @@ const KNOWN_NOT_GAMES: &[u32] = &[

const PROTON_API_URL: &str = "https://www.protondb.com/api/v1/reports/summaries/";

pub fn get_games_list(steam_id: u64) -> Result<HashMap<String, Game>, anyhow::Error> {
pub fn get_games_list(steam_id: u64) -> Result<HashMap<String, Game>> {
let url = format!("https://steamcommunity.com/profiles/{}/games?tab=all&xml=1", steam_id);
let response = get(url).unwrap();
let xml_string = response.text().unwrap();
let games_list: GamesList = match serde_xml_rs::from_str(&xml_string) {
Ok(value) => value,
Err(_error) => return Err(anyhow!("Unable to retrieve Steam data. Is Steam profile ID valid?"))
Err(_error) => return Err(anyhow!("Unable to retrieve Steam data. Is Steam profile ID valid?")).with_context(|| "get_games_list")
};

let game_map: HashMap<String, Game> = games_list.games.game.into_iter()
Expand All @@ -29,18 +29,26 @@ pub fn get_games_list(steam_id: u64) -> Result<HashMap<String, Game>, anyhow::Er
Ok(game_map)
}

pub fn check_proton_db(app_id: &u32) -> ProtonAPIResponse {
pub fn check_proton_db(app_id: &u32) -> Result<ProtonAPIResponse> {
let url = format!("{}{}.json", PROTON_API_URL, app_id);
let response_text = get(url).unwrap().text().unwrap();
let api_response: ProtonAPIResponse = serde_json::from_str(&response_text).expect("Failed to deserialize JSON");
let api_response = match serde_json::from_str(&response_text) {
Ok(value) => value,
Err(_error) => return Err(anyhow!("Unable to retrieve data. Possibly not found in ProtonDB")).with_context(|| "check_proton_db")
};

api_response
Ok(api_response)
}

pub fn output(response: &ProtonAPIResponse, app_id: &u32, game: &str) {
pub fn output(response: &ProtonAPIResponse, app_id: &u32, game: Option<&str>) {
println!("----------------------");
println!("App ID: {}", app_id);
println!("Game: {}", game);
if let Some(game_name) = game
{
println!("Game: {}", game_name);
} else {
println!("Note: game name couldn't be fetched in this mode.");
}
println!("General Tier: {}", response.tier);
println!("Trending Tier: {}", response.trending_tier);
println!("Success chance: {}%", calculate_percent(response.score));
Expand All @@ -51,6 +59,6 @@ fn calculate_percent(score: f32) -> f32 {
if score >= 1.00 {
score
} else {
((score * 100.0) as i32) as f32 / 100.0 * 100.0
((score * 100.0) as i32) as f32
}
}

0 comments on commit 713f41f

Please sign in to comment.