steam_partner/statistics/
mod.rs1use reqwest::{
2 header::{HeaderMap, HeaderValue, ACCEPT, CONTENT_TYPE, COOKIE},
3 Client, Response,
4};
5
6use crate::SteamPartner;
7use std::{
8 fmt::{Display, Write},
9 str::FromStr,
10};
11
12#[derive(Clone, Debug)]
13pub struct SteamStatistic {
14 pub statistic_id: u64,
16 pub name: String,
17 pub display: String,
18 pub aggregated: bool,
19 pub monotonic_increase: bool,
20 pub range: SteamStatisticsRange,
21}
22
23#[derive(Copy, Clone, Debug)]
24pub enum SteamStatisticsRange {
25 Integer { min: Option<i64>, max: Option<i64>, default: Option<i64>, delta: Option<i64> },
26 Decimal { min: Option<f64>, max: Option<f64>, default: Option<f64>, delta: Option<f64> },
27}
28
29impl SteamStatistic {
30 pub fn make_body(&self, session_id: &str) -> Result<String, std::fmt::Error> {
31 let mut out = format!("sessionid={session_id}");
32 write!(out, "&statid={}", self.statistic_id)?;
33 write!(out, "&apiname={}", self.name)?;
34 write!(out, "&displayname={}", self.display)?;
35 write!(out, "&aggregated={}", self.aggregated)?;
36 write!(out, "&incrementonly={}", self.monotonic_increase)?;
37 self.range.write_body(&mut out)?;
38 Ok(out)
39 }
40 pub async fn request(&self, steam: &SteamPartner, app: u64) -> Result<Response, Box<dyn std::error::Error>> {
41 let client = Client::new();
42 let mut headers = HeaderMap::new();
43 headers.insert(ACCEPT, HeaderValue::from_static("application/json"));
44 headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/x-www-form-urlencoded; charset=UTF-8"));
45 headers.insert(COOKIE, steam.get_cookies()?);
46 let response = client
47 .post(format!("https://partner.steamgames.com/apps/savestat/{app}"))
48 .headers(headers.clone())
49 .body(self.make_body(&steam.session_id)?)
50 .send()
51 .await?;
52 Ok(response)
53 }
54}
55
56impl SteamStatisticsRange {
57 fn write_body(&self, out: &mut String) -> Result<(), std::fmt::Error> {
58 match self {
59 Self::Integer { min, max, default, delta } => {
60 write!(out, "&stattype=INT")?;
61 if let Some(min) = min {
62 write!(out, "&min={}", min)?;
63 }
64 if let Some(max) = max {
65 write!(out, "&max={}", max)?;
66 }
67 if let Some(default) = default {
68 write!(out, "&default={}", default)?;
69 }
70 if let Some(delta) = delta {
71 write!(out, "&maxchange={}", delta)?;
72 }
73 }
74 Self::Decimal { min, max, default, delta } => {
75 write!(out, "&stattype=FLOAT")?;
76 if let Some(min) = min {
77 write!(out, "&min={}", min)?;
78 }
79 if let Some(max) = max {
80 write!(out, "&max={}", max)?;
81 }
82 if let Some(default) = default {
83 write!(out, "&default={}", default)?;
84 }
85 if let Some(delta) = delta {
86 write!(out, "&maxchange={}", delta)?;
87 }
88 }
89 }
90 Ok(())
91 }
92}