use cynic::{GraphQlResponse, QueryBuilder}; use serde::{Deserialize, Serialize}; use std::path::Path; pub mod search_games; pub use search_games::*; pub mod tournament_sets; pub use tournament_sets::*; use schema::schema; // Types // HACK: Unfortunately, start.gg seems to use integers for its ID type, whereas // cynic always assumes that IDs are strings. To get around that, we define a // new scalar type that serializes to u64. #[derive(cynic::Scalar, Debug, Copy, Clone)] pub struct ID(pub u64); // Wrapper types to differentiate between different types of IDs #[derive(Debug, Copy, Clone)] pub struct VideogameId(pub u64); #[derive(Debug, Copy, Clone)] pub struct EntrantId(pub u64); #[derive(cynic::Scalar, Debug, Clone)] pub struct Timestamp(pub u64); // Auth key pub fn get_auth_key(config_dir: &Path) -> Option { use std::env::{var, VarError}; use std::fs::read_to_string; match var("AUTH_KEY") { Ok(key) => Some(key), Err(VarError::NotUnicode(_)) => panic!("Invalid authorization key"), Err(VarError::NotPresent) => { let mut auth_file = config_dir.to_owned(); auth_file.push("auth.txt"); read_to_string(auth_file).ok().and_then(|s| { let trimmed = s.trim(); if trimmed.is_empty() { None } else { Some(trimmed.to_owned()) } }) } } } // Query machinery pub trait QueryUnwrap: 'static + QueryBuilder { type VarsUnwrapped; type Unwrapped; fn wrap_vars(vars: Self::VarsUnwrapped) -> Vars; fn unwrap_response(response: GraphQlResponse) -> Option; } // Generic function for running start.gg queries pub fn run_query( vars: Builder::VarsUnwrapped, auth: &str, ) -> Option where Builder: QueryUnwrap, Vars: Serialize, for<'de> Builder: Deserialize<'de>, { use cynic::http::ReqwestBlockingExt; let query = Builder::build(Builder::wrap_vars(vars)); let response = reqwest::blocking::Client::new() .post("https://api.start.gg/gql/alpha") .header("Authorization", String::from("Bearer ") + auth) .run_graphql(query); Builder::unwrap_response(response.unwrap()) }