use crate::Client;
use crate::RoliError;
use reqwest::header;
use serde::{Deserialize, Serialize};
const CREATE_TRADE_AD_API: &str = "https://www.rolimons.com/tradeapi/create";
const RECENT_TRADE_ADS_API: &str = "https://www.rolimons.com/tradeadsapi/getrecentads";
#[allow(missing_docs)]
#[derive(
Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default,
)]
#[serde(rename_all = "lowercase")]
pub enum RequestTag {
#[default]
Any,
Demand,
Rares,
Robux,
Upgrade,
Downgrade,
Rap,
Wishlist,
Projecteds,
Adds,
}
impl TryFrom<u8> for RequestTag {
type Error = RoliError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::Demand),
2 => Ok(Self::Rares),
3 => Ok(Self::Robux),
4 => Ok(Self::Any),
5 => Ok(Self::Upgrade),
6 => Ok(Self::Downgrade),
7 => Ok(Self::Rap),
8 => Ok(Self::Wishlist),
9 => Ok(Self::Projecteds),
10 => Ok(Self::Adds),
_ => Err(RoliError::MalformedResponse),
}
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)]
pub struct TradeAd {
pub trade_id: u64,
pub timestamp: u64,
pub user_id: u64,
pub username: String,
pub offer: Offer,
pub request: Request,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Eq, PartialOrd, Ord, Hash)]
pub struct Offer {
pub items: Vec<u64>,
pub robux: Option<u64>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Eq, PartialOrd, Ord, Hash)]
pub struct Request {
pub items: Vec<u64>,
pub tags: Vec<RequestTag>,
}
impl TryFrom<RequestRaw> for Request {
type Error = RoliError;
fn try_from(value: RequestRaw) -> Result<Self, Self::Error> {
let mut tags = Vec::new();
for tag in value.tags {
tags.push(RequestTag::try_from(tag)?);
}
Ok(Self {
items: value.items,
tags,
})
}
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct RecentTradeAdsResponse {
pub success: bool,
#[serde(rename = "trade_ad_count")]
pub trade_ad_count: u64,
#[serde(rename = "trade_ads")]
pub trade_ads: Vec<(u64, u64, u64, String, Offer, RequestRaw)>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct RequestRaw {
#[serde(default)]
pub tags: Vec<u8>,
#[serde(default)]
pub items: Vec<u64>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)]
pub struct CreateTradeAdParams {
pub player_id: u64,
pub offer_item_ids: Vec<u64>,
pub request_item_ids: Vec<u64>,
pub request_tags: Vec<RequestTag>,
}
impl Client {
pub async fn create_trade_ad(
&self,
create_trade_ad_params: CreateTradeAdParams,
) -> Result<(), RoliError> {
let mut headers = header::HeaderMap::new();
headers.insert(
header::USER_AGENT,
header::HeaderValue::from_static(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0",
),
);
headers.insert(
header::CONNECTION,
header::HeaderValue::from_static("keep-alive"),
);
headers.insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/json;charset=utf-8"),
);
match &self.roli_verification {
Some(roli_verification) => {
let header_safe = match header::HeaderValue::from_str(&format!(
"_RoliVerification={}",
roli_verification
)) {
Ok(x) => x,
Err(_) => return Err(RoliError::RoliVerificationContainsInvalidCharacters),
};
headers.insert(header::COOKIE, header_safe);
}
None => {
return Err(RoliError::RoliVerificationNotSet);
}
}
let result = self
.reqwest_client
.post(CREATE_TRADE_AD_API)
.headers(headers)
.json(&create_trade_ad_params)
.send()
.await;
match result {
Ok(resp) => {
let status_code = resp.status().as_u16();
match status_code {
201 => Ok(()),
400 => Err(RoliError::CooldownNotExpired),
422 => Err(RoliError::RoliVerificationInvalidOrExpired),
429 => Err(RoliError::TooManyRequests),
_ => Err(RoliError::UnidentifiedStatusCode(status_code)),
}
}
Err(e) => Err(RoliError::ReqwestError(e)),
}
}
pub async fn recent_trade_ads(&self) -> Result<Vec<TradeAd>, RoliError> {
let mut headers = header::HeaderMap::new();
headers.insert(
header::USER_AGENT,
header::HeaderValue::from_static(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0",
),
);
headers.insert(
header::CONNECTION,
header::HeaderValue::from_static("keep-alive"),
);
headers.insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/json;charset=utf-8"),
);
let result = self
.reqwest_client
.get(RECENT_TRADE_ADS_API)
.headers(headers)
.send()
.await;
match result {
Ok(response) => {
let status_code = response.status().as_u16();
match status_code {
200 => {
let raw = match response.json::<RecentTradeAdsResponse>().await {
Ok(x) => x,
Err(_) => return Err(RoliError::MalformedResponse),
};
let mut trade_ads = Vec::new();
for (trade_id, timestamp, user_id, username, offer, request_raw) in
raw.trade_ads
{
let request = Request::try_from(request_raw)?;
trade_ads.push(TradeAd {
trade_id,
timestamp,
user_id,
username,
offer,
request,
});
}
Ok(trade_ads)
}
429 => Err(RoliError::TooManyRequests),
500 => Err(RoliError::InternalServerError),
_ => Err(RoliError::UnidentifiedStatusCode(status_code)),
}
}
Err(e) => Err(RoliError::ReqwestError(e)),
}
}
}