Skip to content
Merged
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@
.vscode/launch.json
.idea/
*.iml

# Local Commitlint stuff
/node_modules
/package-lock.json
/package.json
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use warframe::worldstate::{Client, Error, queryable::Cetus, Opposite, TimedEvent

#[tokio::main]
async fn main() -> Result<(), Error> {
let client = Client::new();
let client = Client::default();

let cetus = client.fetch::<Cetus>().await?;
println!(
Expand Down
9 changes: 9 additions & 0 deletions devtools.nu
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,13 @@ export def worldstate_req [
} else {
return (http get $"https://api.warframestat.us/($prefix)($endpoint)?language=($language)")
}
}



export def "worldstate-fixture create" [
file_name:string, # The name of the fixture file to create
]: nothing -> nothing {
let file_path = $"src/worldstate/models/fixtures/($file_name).json"
clipboard paste | save $file_path
}
5 changes: 4 additions & 1 deletion src/market/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ pub use models::{
location::LocationI18N,
mission::MissionI18N,
npc::NpcI18N,
order::Order,
order::{
Order,
OrderType,
},
riven::RivenI18N,
riven_attribute::{
RivenAttributeI18N,
Expand Down
17 changes: 14 additions & 3 deletions src/market/models/order.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
use chrono::{
DateTime,
Utc,
};
use serde::Deserialize;

#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "camelCase")]
pub enum OrderType {
Sell,
Buy,
}

#[derive(Debug, Clone, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "camelCase")]
pub struct Order {
/// Is the unique identifier of the order.
pub id: String,

/// Specifies whether the order is a 'buy' or 'sell'.
pub r#type: String,
pub r#type: OrderType,

/// Is the total platinum currency involved in the order.
pub platinum: u32,
Expand Down Expand Up @@ -37,10 +48,10 @@ pub struct Order {
pub visible: bool,

/// Records the creation time of the order.
pub created_at: String,
pub created_at: DateTime<Utc>,

/// Records the last modification time of the order.
pub updated_at: String,
pub updated_at: DateTime<Utc>,

/// Is the unique identifier of the item involved in the order.
pub item_id: String,
Expand Down
4 changes: 2 additions & 2 deletions src/market/models/order_with_user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ impl_queryable!(OrderWithUser, Array, "/orders/recent");
/// field.
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OrderWithUser {
#[serde(flatten)]
/// The order details.
#[serde(flatten)]
pub order: Order,

/// Represents the user who created the order, with basic profile information.
Expand All @@ -31,7 +31,7 @@ mod test {
};

#[rstest::rstest]
fn riven(
fn order_with_user(
#[files("src/market/models/fixtures/orders.json")]
#[mode = str]
json: &str,
Expand Down
56 changes: 37 additions & 19 deletions src/worldstate/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use super::{
///
/// #[tokio::main]
/// async fn main() -> Result<(), Error> {
/// let client = Client::new();
/// let client = Client::default();
///
/// let cetus: Cetus = client.fetch::<Cetus>().await?;
/// let fissures: Vec<Fissure> = client.fetch::<Fissure>().await?;
Expand All @@ -41,16 +41,32 @@ use super::{
/// ```
///
/// Check the [queryable](crate::worldstate::queryable) module for all queryable types.
#[derive(Default, Debug, Clone)]
#[derive(Debug, Clone)]
pub struct Client {
session: reqwest::Client,
http: reqwest::Client,
base_url: String,
}

impl Client {
impl Default for Client {
/// Creates a new [Client].
///
/// Requests are sent to `https://api.warframestat.us/` by default.
fn default() -> Self {
Self {
http: reqwest::Client::new(),
base_url: "https://api.warframestat.us".to_string(),
}
}
}

impl Client {
/// Creates a new [Client] with the option to supply a custom reqwest client and a base url.
#[must_use]
pub fn new() -> Self {
Self::default()
pub fn new(reqwest_client: reqwest::Client, base_url: String) -> Self {
Self {
http: reqwest_client,
base_url,
}
}
}

Expand All @@ -71,7 +87,7 @@ impl Client {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Error> {
/// let client = Client::new();
/// let client = Client::default();
///
/// let cetus: Cetus = client.fetch::<Cetus>().await?;
/// let fissures: Vec<Fissure> = client.fetch::<Fissure>().await?;
Expand All @@ -83,7 +99,7 @@ impl Client {
where
T: Queryable,
{
<T as Queryable>::query(&self.session).await
<T as Queryable>::query(&self.base_url, &self.http).await
}

/// Fetches an instance of a specified model in a supplied Language.
Expand All @@ -103,7 +119,7 @@ impl Client {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Error> {
/// let client = Client::new();
/// let client = Client::default();
///
/// let cetus: Cetus = client.fetch_using_lang::<Cetus>(Language::ZH).await?;
/// let fissures: Vec<Fissure> = client.fetch_using_lang::<Fissure>(Language::ZH).await?;
Expand All @@ -115,7 +131,7 @@ impl Client {
where
T: Queryable,
{
T::query_with_language(&self.session, language).await
T::query_with_language(&self.base_url, &self.http, language).await
}

/// Queries an item by its name and returns the closest matching item.
Expand All @@ -134,7 +150,7 @@ impl Client {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Error> {
/// let client = Client::new();
/// let client = Client::default();
///
/// let weapon = client.query_item("Acceltra Prime").await?;
///
Expand All @@ -148,7 +164,8 @@ impl Client {
/// ```
pub async fn query_item(&self, query: &str) -> Result<Option<Item>, Error> {
self.query_by_url(format!(
"https://api.warframestat.us/items/{}/?language=en",
"{}/items/{}/?language=en",
self.base_url,
urlencoding::encode(query),
))
.await
Expand All @@ -168,7 +185,7 @@ impl Client {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Error> {
/// let client = Client::new();
/// let client = Client::default();
///
/// let nano_spores = client
/// .query_item_using_lang("Nanosporen", Language::DE)
Expand All @@ -185,15 +202,16 @@ impl Client {
language: Language,
) -> Result<Option<Item>, Error> {
self.query_by_url(format!(
"https://api.warframestat.us/items/{}/?language={}",
"{}/items/{}/?language={}",
self.base_url,
urlencoding::encode(query),
language
))
.await
}

async fn query_by_url(&self, url: String) -> Result<Option<Item>, Error> {
let response = self.session.get(url).send().await?;
let response = self.http.get(url).send().await?;

if response.status() == StatusCode::NOT_FOUND {
return Ok(None);
Expand Down Expand Up @@ -242,7 +260,7 @@ impl Client {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn Error>> {
/// let client = Client::new();
/// let client = Client::default();
///
/// client.call_on_update(on_cetus_update); // don't forget to start it as a bg task (or .await it)s
/// Ok(())
Expand Down Expand Up @@ -331,7 +349,7 @@ impl Client {
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn Error>> {
/// // initialize a client (included in the prelude)
/// let client = Client::new();
/// let client = Client::default();
///
/// // Pass the function to the handler
/// // (will return a Future)
Expand Down Expand Up @@ -425,7 +443,7 @@ impl Client {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn Error>> {
/// let client = Client::new();
/// let client = Client::default();
///
/// // Note that the state will be cloned into the handler, so Arc is preferred
/// let state = Arc::new(MyState {
Expand Down Expand Up @@ -524,7 +542,7 @@ impl Client {
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn Error>> {
/// let client = Client::new();
/// let client = Client::default();
///
/// // Note that the state will be cloned into the handler, so Arc is preferred
/// let state = Arc::new(MyState {
Expand Down
Loading
Loading