steam_webapi_rust_sdk/lib.rs
1//! # Steam Web API Rust SDK
2//!
3//! `steam-webapi-rust-sdk` is a set of utility functions to access Steam Web API.
4//!
5//! In order to use this library make sure to set STEAM_WEB_API_KEY system environment variable.
6//!
7//! The library itself tries to minimize number of networks calls through the caching relevant
8//! responses to the 'steam-webapi-cache' folder.
9//!
10//! There is already prebuilt cache for all steam apps, in order to use it,
11//! simply clone [steam-webapi-cache](https://github.com/bohdaq/steam-webapi-cache)
12//! into the root folder of your project.
13
14use crate::idota2match_570::get_match_history::ResponseMatchHistory;
15use crate::isteam_apps::get_app_list::SteamApp;
16use crate::store_steampowered_com::appdetails::SteamAppDetails;
17
18pub mod util;
19pub mod isteam_apps;
20pub mod store_steampowered_com;
21pub mod idota2match_570;
22
23#[cfg(test)]
24mod tests;
25
26/// Retrieves details for the given app id from the local cache. It may return an error
27/// if requested resource is absent, malformed or not readable from local cache.
28///
29/// # Examples
30///
31/// ```
32/// let app_id = 570;
33/// let boxed_result = steam_webapi_rust_sdk::get_cached_app_details(app_id);
34/// if boxed_result.is_ok() {
35/// let app_details = boxed_result.unwrap();
36/// println!("result is ok for {} app id {}", app_details.name, app_details.app_id);
37///
38/// } else {
39/// let error_message = boxed_result.err().unwrap();
40/// println!("{} {}", error_message, app_id);
41///
42/// };
43/// ```
44pub fn get_cached_app_details(app_id: i64) -> Result<SteamAppDetails, String> {
45 let boxed_result = store_steampowered_com::appdetails::get_cached(app_id);
46 boxed_result
47}
48
49/// Retrieves details for the given app id. It will make an API call to Steam and cache response.
50/// It may return an error if API responded with error response. As an example it may be exceeding
51/// the limit of calls from one IP address or if the response contains not valid UTF-8 characters.
52/// Usually Steam API allows 200 requests from single IP address within 5 minutes range.
53///
54/// # Examples
55///
56/// ```
57/// let app_id = 570;
58/// let boxed_result = steam_webapi_rust_sdk::get_app_details(app_id);
59/// if boxed_result.is_ok() {
60/// let app_details = boxed_result.unwrap();
61/// println!("result is ok for {} app id {}", app_details.name, app_details.app_id);
62///
63/// } else {
64/// let error_message = boxed_result.err().unwrap();
65/// println!("{} {}", error_message, app_id);
66///
67/// let is_steam_unsuccessful_response = error_message == "steampowered api returned failed response";
68/// let is_invalid_utf8_sequence = error_message == "invalid utf-8 sequence";
69/// let no_response_from_api = error_message == "no response from API";
70/// let exceeded_api_calls_limit = (!is_steam_unsuccessful_response && !is_invalid_utf8_sequence) || no_response_from_api;
71///
72/// // you can do a retry or continue execution...
73/// };
74/// ```
75pub fn get_app_details(app_id: i64) -> Result<SteamAppDetails, String> {
76 let boxed_result = store_steampowered_com::appdetails::get(app_id);
77 boxed_result
78}
79
80/// Retrieves list of apps available on Steam. Each item consists of 2 fields: appid and name
81///
82/// # Examples
83///
84/// ```
85/// let steam_app_list = steam_webapi_rust_sdk::get_app_list().unwrap();
86///
87/// assert!(steam_app_list.len()>0);
88/// let steam_app = steam_app_list.get(0).unwrap();
89/// assert!(steam_app.appid > 0);
90///
91/// assert!(steam_app.name.len() > 0);
92/// ```
93pub fn get_app_list() -> Result<Vec<SteamApp>, String> {
94 let boxed_result = isteam_apps::get_app_list::get();
95 boxed_result
96}
97
98
99/// Retrieves list of apps available on Steam. First tries to get it from local cache.
100/// Each item consists of 2 fields: appid and name
101///
102/// # Examples
103///
104/// ```
105/// let steam_app_list = steam_webapi_rust_sdk::get_cached_app_list().unwrap();
106///
107/// assert!(steam_app_list.len()>0);
108/// let steam_app = steam_app_list.get(0).unwrap();
109/// assert!(steam_app.appid > 0);
110///
111/// assert!(steam_app.name.len() > 0);
112/// ```
113pub fn get_cached_app_list() -> Result<Vec<SteamApp>, String> {
114 let boxed_result = isteam_apps::get_app_list::get_cached();
115 boxed_result
116}
117
118/// Retrieves list of matches from Dota2
119///
120/// # Examples
121///
122/// ```
123/// let boxed_dota2_match_list = steam_webapi_rust_sdk::get_dota2_match_history(
124/// Some(76561197960361544),
125/// None,
126/// None,
127/// None,
128/// None,
129/// None,
130/// None
131/// );
132///
133/// assert!(boxed_dota2_match_list.is_ok());
134/// if boxed_dota2_match_list.is_ok() {
135/// let dota2_match_list = boxed_dota2_match_list.unwrap();
136/// assert!(dota2_match_list.matches.len()>0);
137/// }
138///
139/// ```
140pub fn get_dota2_match_history(account_id: Option<i64>,
141 game_mode: Option<u8>,
142 skill: Option<u8>,
143 min_players: Option<u32>,
144 start_at_match_id: Option<i64>,
145 matches_requested: Option<u32>,
146 tournament_games_only: Option<bool>)
147 -> Result<ResponseMatchHistory, String> {
148 idota2match_570::get_dota2_match_history(
149 account_id,
150 game_mode,
151 skill,
152 min_players,
153 start_at_match_id,
154 matches_requested,
155 tournament_games_only
156 )
157
158}
159
160/// Converts given 32 bit Steam account id to 64 bit
161///
162/// # Examples
163///
164/// ```
165/// use steam_webapi_rust_sdk::convert_32bit_account_id_to_64bit;
166///
167/// let _32bit_id = 95816;
168/// let converted = convert_32bit_account_id_to_64bit(_32bit_id);
169///
170/// let expected_id = 76561197960361544;
171/// assert_eq!(expected_id, converted);
172///
173/// ```
174pub fn convert_32bit_account_id_to_64bit(account_id_32bit: i64) -> i64 {
175 let valves_magic_constant = 76561197960265728;
176 let mut converted_to_64_bit = account_id_32bit;
177 converted_to_64_bit += valves_magic_constant;
178 converted_to_64_bit
179}
180
181
182/// Converts given 64 bit Steam account id to 32 bit
183///
184/// # Examples
185///
186/// ```
187/// use steam_webapi_rust_sdk::convert_64bit_account_id_to_32bit;
188///
189/// let _64bit_id = 76561197960361544;
190/// let converted = convert_64bit_account_id_to_32bit(_64bit_id);
191///
192/// let expected_id = 95816;
193/// assert_eq!(expected_id, converted);
194///
195/// ```
196pub fn convert_64bit_account_id_to_32bit(account_id_32bit: i64) -> i64 {
197 let valves_magic_constant = 76561197960265728;
198 let mut converted_to_32_bit = account_id_32bit;
199 converted_to_32_bit -= valves_magic_constant;
200 converted_to_32_bit
201}
202
203
204pub(crate) fn get_scheme() -> String {
205 "https".to_string()
206}
207
208pub(crate) fn get_host() -> String {
209 let host = "api.steampowered.com".to_string();
210 host
211}
212
213pub(crate) fn make_api_call(url: String) -> Result<String, String> {
214
215 let boxed_response = minreq::get(url).send();
216 if boxed_response.is_err() {
217 return Err("Operation timed out (API call)".to_string());
218 }
219
220 let raw_response : Vec<u8> = boxed_response.unwrap().into_bytes();
221
222 let response_string_boxed = String::from_utf8(raw_response);
223 if response_string_boxed.is_err() {
224 let error_message = response_string_boxed.err().unwrap().to_string();
225 if error_message == "invalid utf-8 sequence of 1 bytes from index 1" {
226 return Err("no response from API".to_string());
227 }
228 return Err("invalid utf-8 sequence".to_string());
229 }
230 let response_string: String = response_string_boxed.unwrap();
231
232 Ok(response_string)
233}