use bitflags::bitflags;
use minreq::Method;
use serde::{Deserialize, Serialize};
use crate::mojang_api::{client::fetch, error::ApiError};
bitflags! {
pub struct Metrics: u32 {
#[allow(missing_docs)] const MINECRAFT_ITEMS_SOLD = 0b00000001;
#[allow(missing_docs)] const MINECRAFT_PREPAID_CARDS_REDEEMED = 0b00000010;
#[allow(missing_docs)] const COBALT_ITEMS_SOLD = 0b00000100;
#[allow(missing_docs)] const COBALT_PREPAID_CARDS_REDEEMED = 0b00001000;
#[allow(missing_docs)] const SCROLLS_ITEMS_SOLD = 0b00010000;
#[allow(missing_docs)] const DUNGEONS_ITEM_SOLD = 0b00100000;
}
}
#[doc(hidden)]
pub mod keys {
pub const MINECRAFT_ITEMS_SOLD: &'static str = "item_sold_minecraft";
pub const MINECRAFT_PREPAID_CARDS_REDEEMED: &'static str = "prepaid_card_redeemed_minecraft";
pub const COBALT_ITEMS_SOLD: &'static str = "item_sold_cobalt";
pub const COBALT_PREPAID_CARDS_REDEEMED: &'static str = "prepaid_card_redeemed_cobalt";
pub const SCROLLS_ITEMS_SOLD: &'static str = "item_sold_scrolls";
pub const DUNGEONS_ITEM_SOLD: &'static str = "item_sold_dungeons";
}
macro_rules! add_keys {
($self:ident, $vec:ident, [$($name:ident),*]) => {
$(if $self.contains(Self::$name) {
$vec.push(keys::$name)
})*
};
}
impl Metrics {
pub fn minecraft() -> Self {
Self::MINECRAFT_ITEMS_SOLD | Self::MINECRAFT_PREPAID_CARDS_REDEEMED
}
pub fn cobalt() -> Self {
Self::COBALT_ITEMS_SOLD | Self::COBALT_PREPAID_CARDS_REDEEMED
}
pub fn scrolls() -> Self {
Self::SCROLLS_ITEMS_SOLD
}
pub fn dungeons() -> Self {
Self::DUNGEONS_ITEM_SOLD
}
}
impl Into<Vec<&'static str>> for Metrics {
fn into(self) -> Vec<&'static str> {
let mut vec = vec![];
add_keys!(
self,
vec,
[
MINECRAFT_ITEMS_SOLD,
MINECRAFT_PREPAID_CARDS_REDEEMED,
COBALT_ITEMS_SOLD,
COBALT_PREPAID_CARDS_REDEEMED,
SCROLLS_ITEMS_SOLD,
DUNGEONS_ITEM_SOLD
]
);
vec
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Stats {
pub total: u64,
pub last24h: u64,
#[serde(rename = "saleVelocityPerSeconds")]
pub sale_velocity_per_seconds: f32,
}
#[doc(hidden)]
#[derive(Serialize, Debug)]
pub struct Payload {
#[serde(rename = "metricKeys")]
metric_keys: Vec<&'static str>,
}
impl Stats {
pub fn fetch(keys: Metrics) -> Result<Self, ApiError> {
let body = Payload {
metric_keys: keys.into(),
};
let res = fetch(Method::Post, "https://api.mojang.com/orders/statistics")
.with_json(&body)?
.send()?;
if res.status_code == 200 {
Ok(res.json()?)
} else {
Err(ApiError::Request {
status: res.status_code,
reason: res.reason_phrase,
})
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_metric_keys_conversion() {
let keys: Vec<_> = Metrics::all().into();
assert_eq!(
keys,
vec![
"item_sold_minecraft",
"prepaid_card_redeemed_minecraft",
"item_sold_cobalt",
"prepaid_card_redeemed_cobalt",
"item_sold_scrolls",
"item_sold_dungeons",
]
);
let keys: Vec<_> =
(Metrics::MINECRAFT_ITEMS_SOLD | Metrics::MINECRAFT_PREPAID_CARDS_REDEEMED).into();
assert_eq!(
keys,
vec!["item_sold_minecraft", "prepaid_card_redeemed_minecraft",]
);
}
}