use serde::Deserialize;
use crate::{error::SteamError, SteamClient};
#[derive(Debug, Clone)]
pub struct GiftDetails {
pub gift_name: String,
pub package_id: u32,
pub owned: bool,
}
#[derive(Debug, Deserialize)]
struct GiftValidateResponse {
success: Option<i32>,
gift_name: Option<String>,
#[serde(deserialize_with = "deserialize_id")]
packageid: Option<String>,
owned: Option<bool>,
message: Option<String>,
}
fn deserialize_id<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::Deserialize;
let v: serde_json::Value = Deserialize::deserialize(deserializer)?;
match v {
serde_json::Value::String(s) => Ok(Some(s)),
serde_json::Value::Number(n) => Ok(Some(n.to_string())),
serde_json::Value::Null => Ok(None),
_ => Err(serde::de::Error::custom("expected string or number")),
}
}
#[derive(Debug, Deserialize)]
struct GiftRedeemResponse {
success: Option<i32>,
message: Option<String>,
}
fn extract_session_id(cookies: &str) -> Option<String> {
for part in cookies.split(';') {
let part = part.trim();
if let Some(value) = part.strip_prefix("sessionid=") {
return Some(value.to_string());
}
}
None
}
impl SteamClient {
pub async fn get_gift_details(&self, gift_id: &str, cookies: &str) -> Result<GiftDetails, SteamError> {
let session_id = extract_session_id(cookies).ok_or_else(|| SteamError::Other("No sessionid found in cookies".to_string()))?;
let url = format!("https://steamcommunity.com/gifts/{}/validateunpack", gift_id);
let response = self.http_client.post_form_with_cookies(&url, &[("sessionid", session_id.as_str())], cookies).await?;
if !response.is_success() {
return Err(SteamError::Other(format!("HTTP error: {}", response.status)));
}
let body: GiftValidateResponse = response.json().map_err(|e| SteamError::ProtocolError(format!("Failed to parse response: {}", e)))?;
if body.success != Some(1) {
return Err(SteamError::Other(body.message.unwrap_or_else(|| "Unknown error validating gift".to_string())));
}
let gift_name = body.gift_name.ok_or_else(|| SteamError::ProtocolError("Missing gift_name in response".to_string()))?;
let package_id: u32 = body.packageid.ok_or_else(|| SteamError::ProtocolError("Missing packageid in response".to_string()))?.parse().map_err(|_| SteamError::ProtocolError("Invalid packageid".to_string()))?;
Ok(GiftDetails { gift_name, package_id, owned: body.owned.unwrap_or(false) })
}
pub async fn redeem_gift(&self, gift_id: &str, cookies: &str) -> Result<(), SteamError> {
let session_id = extract_session_id(cookies).ok_or_else(|| SteamError::Other("No sessionid found in cookies".to_string()))?;
let url = format!("https://steamcommunity.com/gifts/{}/unpack", gift_id);
let response = self.http_client.post_form_with_cookies(&url, &[("sessionid", session_id.as_str())], cookies).await?;
if !response.is_success() {
return Err(SteamError::Other(format!("HTTP error: {}", response.status)));
}
let body: GiftRedeemResponse = response.json().map_err(|e| SteamError::ProtocolError(format!("Failed to parse response: {}", e)))?;
if body.success != Some(1) {
return Err(SteamError::Other(body.message.unwrap_or_else(|| "Unknown error redeeming gift".to_string())));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_session_id() {
let cookies = "sessionid=abc123; steamLoginSecure=xyz789";
assert_eq!(extract_session_id(cookies), Some("abc123".to_string()));
let cookies_no_session = "steamLoginSecure=xyz789";
assert_eq!(extract_session_id(cookies_no_session), None);
let cookies_with_spaces = " sessionid=def456 ; other=value";
assert_eq!(extract_session_id(cookies_with_spaces), Some("def456".to_string()));
}
#[test]
fn test_gift_details_struct() {
let details = GiftDetails { gift_name: "Test Game".to_string(), package_id: 12345, owned: false };
assert_eq!(details.gift_name, "Test Game");
assert_eq!(details.package_id, 12345);
assert!(!details.owned);
}
}