1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use reqwest::header::LOCATION;
use reqwest::redirect::Policy;
use reqwest::{Client, ClientBuilder, StatusCode};
use serde::Deserialize;
pub use steamid_ng::SteamID;
use thiserror::Error;
#[derive(Deserialize)]
struct SteamApiResponse {
response: VanityUrlResponse,
}
#[derive(Deserialize)]
struct VanityUrlResponse {
#[serde(default)]
steamid: Option<SteamID>,
success: u8,
}
#[derive(Debug, Error)]
pub enum Error {
#[error("Invalid api key")]
InvalidKey,
#[error("Error while making request to steam api")]
Request(#[from] reqwest::Error),
#[error("Received malformed steam id")]
SteamId(#[from] steamid_ng::SteamIDError),
}
pub async fn resolve_vanity_url(url: &str, api_key: &str) -> Result<Option<SteamID>, Error> {
let response: reqwest::Response = Client::new()
.get("http://api.steampowered.com/ISteamUser/ResolveVanityURL/v0001/")
.query(&[("key", api_key), ("vanityurl", url)])
.send()
.await?;
if response.status() == StatusCode::FORBIDDEN {
return Err(Error::InvalidKey);
}
let api_response: SteamApiResponse = response.json().await?;
Ok(api_response
.response
.steamid
.filter(|_| api_response.response.success == 1))
}
pub async fn get_vanity_url(steam_id: SteamID) -> Result<Option<String>, Error> {
let response: reqwest::Response = ClientBuilder::new()
.redirect(Policy::none())
.build()
.unwrap()
.get(&format!(
"https://steamcommunity.com/profiles/{}",
u64::from(steam_id)
))
.send()
.await?;
Ok(match response.status() {
StatusCode::FOUND => response
.headers()
.into_iter()
.find_map(|(name, value)| if name == LOCATION { Some(value) } else { None })
.and_then(|value| value.to_str().ok())
.map(|value| value.split_at("https://steamcommunity.com/id/".len()).1)
.map(|value| value.trim_end_matches("/").to_string()),
_ => None,
})
}
#[cfg(test)]
#[tokio::test]
async fn test_valid() {
let key = dotenv::var("STEAM_API_KEY").unwrap();
assert_eq!(
Some(SteamID::from(76561198024494988)),
resolve_vanity_url("icewind1991", &key).await.unwrap()
)
}
#[cfg(test)]
#[tokio::test]
async fn test_invalid_key() {
assert!(matches!(
resolve_vanity_url("icewind1991", "foo").await.unwrap_err(),
Error::InvalidKey
))
}
#[cfg(test)]
#[tokio::test]
async fn test_not_found() {
let key = dotenv::var("STEAM_API_KEY").unwrap();
assert_eq!(
None,
resolve_vanity_url("hopefully_non_existing_steam_id", &key)
.await
.unwrap()
)
}
#[cfg(test)]
#[tokio::test]
async fn test_get_vanity() {
assert_eq!(
Some("icewind1991".to_string()),
get_vanity_url(SteamID::from(76561198024494988))
.await
.unwrap()
)
}
#[cfg(test)]
#[tokio::test]
async fn test_get_vanity_not_found() {
assert_eq!(
None,
get_vanity_url(SteamID::from(76561198024494987))
.await
.unwrap()
)
}