steam_partner/statistics/
mod.rs

1use 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    /// **WARNING**: This ID shares the ID used for achievements. If there is a conflict, all achievements will be deleted.
15    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}