diff --git a/torn-api/Cargo.toml b/torn-api/Cargo.toml index 3840996..4699994 100644 --- a/torn-api/Cargo.toml +++ b/torn-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "torn-api" -version = "0.5.7" +version = "0.5.8" edition = "2021" authors = ["Pyrit [2111649]"] license = "MIT" @@ -31,7 +31,6 @@ serde_json = "1" chrono = { version = "0.4", features = [ "serde" ], default-features = false } async-trait = "0.1" thiserror = "1" -num-traits = "0.2" futures = "0.3" reqwest = { version = "0.11", default-features = false, features = [ "json" ], optional = true } diff --git a/torn-api/src/common.rs b/torn-api/src/common.rs index 953317f..412bcd2 100644 --- a/torn-api/src/common.rs +++ b/torn-api/src/common.rs @@ -39,3 +39,12 @@ pub struct Status<'a> { #[serde(deserialize_with = "de_util::zero_date_is_none")] pub until: Option>, } + +#[derive(Debug, Clone, Deserialize)] +pub struct Territory { + pub sector: i16, + pub size: i16, + pub density: i16, + pub daily_respect: i16, + pub faction: i32, +} diff --git a/torn-api/src/faction.rs b/torn-api/src/faction.rs index c3ba881..707b9a9 100644 --- a/torn-api/src/faction.rs +++ b/torn-api/src/faction.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use chrono::{serde::ts_seconds, DateTime, Utc}; use serde::Deserialize; @@ -7,7 +7,7 @@ use torn_api_macros::ApiCategory; use crate::de_util; -pub use crate::common::{LastAction, Status}; +pub use crate::common::{LastAction, Status, Territory}; #[derive(Debug, Clone, Copy, ApiCategory)] #[api(category = "faction")] @@ -20,6 +20,9 @@ pub enum Selection { #[api(type = "BTreeMap", field = "attacks")] Attacks, + + #[api(type = "HashMap", field = "territory")] + Territory, } #[derive(Debug, Clone, Deserialize)] @@ -164,12 +167,15 @@ mod tests { let response = Client::default() .torn_api(key) - .faction(|b| b.selections(&[Selection::Basic, Selection::Attacks])) + .faction(|b| { + b.selections(&[Selection::Basic, Selection::Attacks, Selection::Territory]) + }) .await .unwrap(); response.basic().unwrap(); response.attacks().unwrap(); response.attacks_full().unwrap(); + response.territory().unwrap(); } } diff --git a/torn-api/src/lib.rs b/torn-api/src/lib.rs index 806cceb..a12a4bf 100644 --- a/torn-api/src/lib.rs +++ b/torn-api/src/lib.rs @@ -165,7 +165,7 @@ impl ApiRequest where A: ApiCategoryResponse, { - pub fn url(&self, key: &str, id: Option) -> String { + pub fn url(&self, key: &str, id: Option<&str>) -> String { let mut url = format!("https://api.torn.com/{}/", A::Selection::category()); if let Some(id) = id { @@ -195,7 +195,7 @@ where A: ApiCategoryResponse, { request: ApiRequest, - id: Option, + id: Option, } impl Default for ApiRequestBuilder @@ -243,9 +243,9 @@ where #[must_use] pub fn id(mut self, id: I) -> Self where - I: num_traits::AsPrimitive, + I: ToString, { - self.id = Some(id.as_()); + self.id = Some(id.to_string()); self } } diff --git a/torn-api/src/local.rs b/torn-api/src/local.rs index 73a188e..a836f6b 100644 --- a/torn-api/src/local.rs +++ b/torn-api/src/local.rs @@ -49,23 +49,15 @@ where F: FnOnce( crate::ApiRequestBuilder, ) -> crate::ApiRequestBuilder, - I: num_traits::AsPrimitive + std::hash::Hash + std::cmp::Eq, - i64: num_traits::AsPrimitive, + I: ToString + std::hash::Hash + std::cmp::Eq, L: IntoIterator, { let mut builder = crate::ApiRequestBuilder::default(); builder = build(builder); self.executor - .execute_many( - self.client, - builder.request, - ids.into_iter().map(|i| i.as_()).collect(), - ) + .execute_many(self.client, builder.request, Vec::from_iter(ids)) .await - .into_iter() - .map(|(i, r)| (num_traits::AsPrimitive::as_(i), r)) - .collect() } #[cfg(feature = "faction")] @@ -93,23 +85,15 @@ where F: FnOnce( crate::ApiRequestBuilder, ) -> crate::ApiRequestBuilder, - I: num_traits::AsPrimitive + std::hash::Hash + std::cmp::Eq, - i64: num_traits::AsPrimitive, + I: ToString + std::hash::Hash + std::cmp::Eq, L: IntoIterator, { let mut builder = crate::ApiRequestBuilder::default(); builder = build(builder); self.executor - .execute_many( - self.client, - builder.request, - ids.into_iter().map(|i| i.as_()).collect(), - ) + .execute_many(self.client, builder.request, Vec::from_iter(ids)) .await - .into_iter() - .map(|(i, r)| (num_traits::AsPrimitive::as_(i), r)) - .collect() } #[cfg(feature = "torn")] @@ -137,23 +121,15 @@ where F: FnOnce( crate::ApiRequestBuilder, ) -> crate::ApiRequestBuilder, - I: num_traits::AsPrimitive + std::hash::Hash + std::cmp::Eq, - i64: num_traits::AsPrimitive, + I: ToString + std::hash::Hash + std::cmp::Eq, L: IntoIterator, { let mut builder = crate::ApiRequestBuilder::default(); builder = build(builder); self.executor - .execute_many( - self.client, - builder.request, - ids.into_iter().map(|i| i.as_()).collect(), - ) + .execute_many(self.client, builder.request, Vec::from_iter(ids)) .await - .into_iter() - .map(|(i, r)| (num_traits::AsPrimitive::as_(i), r)) - .collect() } #[cfg(feature = "key")] @@ -183,19 +159,20 @@ where &self, client: &C, request: ApiRequest, - id: Option, + id: Option, ) -> Result where A: ApiCategoryResponse; - async fn execute_many( + async fn execute_many( &self, client: &C, request: ApiRequest, - ids: Vec, - ) -> HashMap> + ids: Vec, + ) -> HashMap> where - A: ApiCategoryResponse; + A: ApiCategoryResponse, + I: ToString + std::hash::Hash + std::cmp::Eq; } #[async_trait(?Send)] @@ -209,30 +186,32 @@ where &self, client: &C, request: ApiRequest, - id: Option, + id: Option, ) -> Result where A: ApiCategoryResponse, { - let url = request.url(&self.key, id); + let url = request.url(&self.key, id.as_deref()); let value = client.request(url).await.map_err(ApiClientError::Client)?; Ok(A::from_response(ApiResponse::from_value(value)?)) } - async fn execute_many( + async fn execute_many( &self, client: &C, request: ApiRequest, - ids: Vec, - ) -> HashMap> + ids: Vec, + ) -> HashMap> where A: ApiCategoryResponse, + I: ToString + std::hash::Hash + std::cmp::Eq, { let request_ref = &request; - futures::future::join_all(ids.into_iter().map(|i| async move { - let url = request_ref.url(&self.key, Some(i)); + let tuples = futures::future::join_all(ids.into_iter().map(|i| async move { + let id_string = i.to_string(); + let url = request_ref.url(&self.key, Some(&id_string)); let value = client.request(url).await.map_err(ApiClientError::Client); @@ -243,9 +222,9 @@ where .map(A::from_response), ) })) - .await - .into_iter() - .collect() + .await; + + HashMap::from_iter(tuples) } } diff --git a/torn-api/src/send.rs b/torn-api/src/send.rs index ddd9eac..f211792 100644 --- a/torn-api/src/send.rs +++ b/torn-api/src/send.rs @@ -49,23 +49,15 @@ where F: FnOnce( crate::ApiRequestBuilder, ) -> crate::ApiRequestBuilder, - I: num_traits::AsPrimitive + std::hash::Hash + std::cmp::Eq, - i64: num_traits::AsPrimitive, + I: ToString + std::hash::Hash + std::cmp::Eq + Send + Sync, L: IntoIterator, { let mut builder = crate::ApiRequestBuilder::default(); builder = build(builder); self.executor - .execute_many( - self.client, - builder.request, - ids.into_iter().map(|i| i.as_()).collect(), - ) + .execute_many(self.client, builder.request, Vec::from_iter(ids)) .await - .into_iter() - .map(|(i, r)| (num_traits::AsPrimitive::as_(i), r)) - .collect() } #[cfg(feature = "faction")] @@ -93,23 +85,15 @@ where F: FnOnce( crate::ApiRequestBuilder, ) -> crate::ApiRequestBuilder, - I: num_traits::AsPrimitive + std::hash::Hash + std::cmp::Eq, - i64: num_traits::AsPrimitive, + I: ToString + std::hash::Hash + std::cmp::Eq + Send + Sync, L: IntoIterator, { let mut builder = crate::ApiRequestBuilder::default(); builder = build(builder); self.executor - .execute_many( - self.client, - builder.request, - ids.into_iter().map(|i| i.as_()).collect(), - ) + .execute_many(self.client, builder.request, Vec::from_iter(ids)) .await - .into_iter() - .map(|(i, r)| (num_traits::AsPrimitive::as_(i), r)) - .collect() } #[cfg(feature = "torn")] @@ -137,23 +121,15 @@ where F: FnOnce( crate::ApiRequestBuilder, ) -> crate::ApiRequestBuilder, - I: num_traits::AsPrimitive + std::hash::Hash + std::cmp::Eq, - i64: num_traits::AsPrimitive, + I: ToString + std::hash::Hash + std::cmp::Eq + Send + Sync, L: IntoIterator, { let mut builder = crate::ApiRequestBuilder::default(); builder = build(builder); self.executor - .execute_many( - self.client, - builder.request, - ids.into_iter().map(|i| i.as_()).collect(), - ) + .execute_many(self.client, builder.request, Vec::from_iter(ids)) .await - .into_iter() - .map(|(i, r)| (num_traits::AsPrimitive::as_(i), r)) - .collect() } #[cfg(feature = "key")] @@ -183,19 +159,20 @@ where &self, client: &C, request: ApiRequest, - id: Option, + id: Option, ) -> Result where A: ApiCategoryResponse; - async fn execute_many( + async fn execute_many( &self, client: &C, request: ApiRequest, - ids: Vec, - ) -> HashMap> + ids: Vec, + ) -> HashMap> where - A: ApiCategoryResponse; + A: ApiCategoryResponse, + I: ToString + std::hash::Hash + std::cmp::Eq + Send + Sync; } #[async_trait] @@ -209,30 +186,32 @@ where &self, client: &C, request: ApiRequest, - id: Option, + id: Option, ) -> Result where A: ApiCategoryResponse, { - let url = request.url(&self.key, id); + let url = request.url(&self.key, id.as_deref()); let value = client.request(url).await.map_err(ApiClientError::Client)?; Ok(A::from_response(ApiResponse::from_value(value)?)) } - async fn execute_many( + async fn execute_many( &self, client: &C, request: ApiRequest, - ids: Vec, - ) -> HashMap> + ids: Vec, + ) -> HashMap> where A: ApiCategoryResponse, + I: ToString + std::hash::Hash + std::cmp::Eq + Send + Sync, { let request_ref = &request; - futures::future::join_all(ids.into_iter().map(|i| async move { - let url = request_ref.url(&self.key, Some(i)); + let tuples = futures::future::join_all(ids.into_iter().map(|i| async move { + let id_string = i.to_string(); + let url = request_ref.url(&self.key, Some(&id_string)); let value = client.request(url).await.map_err(ApiClientError::Client); @@ -243,9 +222,9 @@ where .map(A::from_response), ) })) - .await - .into_iter() - .collect() + .await; + + HashMap::from_iter(tuples) } } diff --git a/torn-api/src/torn.rs b/torn-api/src/torn.rs index f8c69f4..f118b63 100644 --- a/torn-api/src/torn.rs +++ b/torn-api/src/torn.rs @@ -1,3 +1,6 @@ +use std::collections::HashMap; + +use chrono::{DateTime, Utc}; use serde::{ de::{self, MapAccess, Visitor}, Deserialize, @@ -16,6 +19,9 @@ pub enum Selection { type = "Option" )] Competition, + + #[api(type = "HashMap", field = "territorywars")] + TerritoryWars, } #[derive(Deserialize)] @@ -94,6 +100,17 @@ where deserializer.deserialize_option(CompetitionVisitor) } +#[derive(Debug, Clone, Deserialize)] +pub struct TerritoryWar { + pub assaulting_faction: i32, + pub defending_faction: i32, + + #[serde(with = "chrono::serde::ts_seconds")] + pub started: DateTime, + #[serde(with = "chrono::serde::ts_seconds")] + pub ends: DateTime, +} + #[cfg(test)] mod tests { use super::*; @@ -105,10 +122,11 @@ mod tests { let response = Client::default() .torn_api(key) - .torn(|b| b.selections(&[Selection::Competition])) + .torn(|b| b.selections(&[Selection::Competition, Selection::TerritoryWars])) .await .unwrap(); response.competition().unwrap(); + response.territory_wars().unwrap(); } } diff --git a/torn-key-pool/Cargo.toml b/torn-key-pool/Cargo.toml index 4245a6c..b1d4cf3 100644 --- a/torn-key-pool/Cargo.toml +++ b/torn-key-pool/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "torn-key-pool" -version = "0.5.3" +version = "0.5.4" edition = "2021" authors = ["Pyrit [2111649]"] license = "MIT" diff --git a/torn-key-pool/src/local.rs b/torn-key-pool/src/local.rs index 1d73568..a066f9d 100644 --- a/torn-key-pool/src/local.rs +++ b/torn-key-pool/src/local.rs @@ -21,7 +21,7 @@ where &self, client: &C, mut request: ApiRequest, - id: Option, + id: Option, ) -> Result where A: ApiCategoryResponse, @@ -33,7 +33,7 @@ where .acquire_key(self.domain.clone()) .await .map_err(|e| KeyPoolError::Storage(Arc::new(e)))?; - let url = request.url(key.value(), id); + let url = request.url(key.value(), id.as_deref()); let value = client.request(url).await?; match ApiResponse::from_value(value) { @@ -54,14 +54,15 @@ where } } - async fn execute_many( + async fn execute_many( &self, client: &C, mut request: ApiRequest, - ids: Vec, - ) -> HashMap> + ids: Vec, + ) -> HashMap> where A: ApiCategoryResponse, + I: ToString + std::hash::Hash + std::cmp::Eq, { let keys = match self .storage @@ -81,43 +82,47 @@ where request.comment = self.comment.map(ToOwned::to_owned); let request_ref = &request; - futures::future::join_all(std::iter::zip(ids, keys).map(|(id, mut key)| async move { - loop { - let url = request_ref.url(key.value(), Some(id)); - let value = match client.request(url).await { - Ok(v) => v, - Err(why) => return (id, Err(Self::Error::Client(why))), - }; + let tuples = + futures::future::join_all(std::iter::zip(ids, keys).map(|(id, mut key)| async move { + let id_string = id.to_string(); + loop { + let url = request_ref.url(key.value(), Some(&id_string)); + let value = match client.request(url).await { + Ok(v) => v, + Err(why) => return (id, Err(Self::Error::Client(why))), + }; - match ApiResponse::from_value(value) { - Err(ResponseError::Api { code, reason }) => { - match self.storage.flag_key(key, code).await { - Ok(false) => { - return ( - id, - Err(KeyPoolError::Response(ResponseError::Api { - code, - reason, - })), - ) + match ApiResponse::from_value(value) { + Err(ResponseError::Api { code, reason }) => { + match self.storage.flag_key(key, code).await { + Ok(false) => { + return ( + id, + Err(KeyPoolError::Response(ResponseError::Api { + code, + reason, + })), + ) + } + Ok(true) => (), + Err(why) => return (id, Err(KeyPoolError::Storage(Arc::new(why)))), } - Ok(true) => (), - Err(why) => return (id, Err(KeyPoolError::Storage(Arc::new(why)))), } - } - Err(parsing_error) => return (id, Err(KeyPoolError::Response(parsing_error))), - Ok(res) => return (id, Ok(A::from_response(res))), - }; + Err(parsing_error) => { + return (id, Err(KeyPoolError::Response(parsing_error))) + } + Ok(res) => return (id, Ok(A::from_response(res))), + }; - key = match self.storage.acquire_key(self.domain.clone()).await { - Ok(k) => k, - Err(why) => return (id, Err(Self::Error::Storage(Arc::new(why)))), - }; - } - })) - .await - .into_iter() - .collect() + key = match self.storage.acquire_key(self.domain.clone()).await { + Ok(k) => k, + Err(why) => return (id, Err(Self::Error::Storage(Arc::new(why)))), + }; + } + })) + .await; + + HashMap::from_iter(tuples) } } diff --git a/torn-key-pool/src/send.rs b/torn-key-pool/src/send.rs index e2cb563..f538b99 100644 --- a/torn-key-pool/src/send.rs +++ b/torn-key-pool/src/send.rs @@ -21,7 +21,7 @@ where &self, client: &C, mut request: ApiRequest, - id: Option, + id: Option, ) -> Result where A: ApiCategoryResponse, @@ -33,7 +33,7 @@ where .acquire_key(self.domain.clone()) .await .map_err(|e| KeyPoolError::Storage(Arc::new(e)))?; - let url = request.url(key.value(), id); + let url = request.url(key.value(), id.as_deref()); let value = client.request(url).await?; match ApiResponse::from_value(value) { @@ -54,14 +54,15 @@ where } } - async fn execute_many( + async fn execute_many( &self, client: &C, mut request: ApiRequest, - ids: Vec, - ) -> HashMap> + ids: Vec, + ) -> HashMap> where A: ApiCategoryResponse, + I: ToString + std::hash::Hash + std::cmp::Eq + Send + Sync, { let keys = match self .storage @@ -81,43 +82,47 @@ where request.comment = self.comment.map(ToOwned::to_owned); let request_ref = &request; - futures::future::join_all(std::iter::zip(ids, keys).map(|(id, mut key)| async move { - loop { - let url = request_ref.url(key.value(), Some(id)); - let value = match client.request(url).await { - Ok(v) => v, - Err(why) => return (id, Err(Self::Error::Client(why))), - }; + let tuples = + futures::future::join_all(std::iter::zip(ids, keys).map(|(id, mut key)| async move { + let id_string = id.to_string(); + loop { + let url = request_ref.url(key.value(), Some(&id_string)); + let value = match client.request(url).await { + Ok(v) => v, + Err(why) => return (id, Err(Self::Error::Client(why))), + }; - match ApiResponse::from_value(value) { - Err(ResponseError::Api { code, reason }) => { - match self.storage.flag_key(key, code).await { - Ok(false) => { - return ( - id, - Err(KeyPoolError::Response(ResponseError::Api { - code, - reason, - })), - ) + match ApiResponse::from_value(value) { + Err(ResponseError::Api { code, reason }) => { + match self.storage.flag_key(key, code).await { + Ok(false) => { + return ( + id, + Err(KeyPoolError::Response(ResponseError::Api { + code, + reason, + })), + ) + } + Ok(true) => (), + Err(why) => return (id, Err(KeyPoolError::Storage(Arc::new(why)))), } - Ok(true) => (), - Err(why) => return (id, Err(KeyPoolError::Storage(Arc::new(why)))), } - } - Err(parsing_error) => return (id, Err(KeyPoolError::Response(parsing_error))), - Ok(res) => return (id, Ok(A::from_response(res))), - }; + Err(parsing_error) => { + return (id, Err(KeyPoolError::Response(parsing_error))) + } + Ok(res) => return (id, Ok(A::from_response(res))), + }; - key = match self.storage.acquire_key(self.domain.clone()).await { - Ok(k) => k, - Err(why) => return (id, Err(Self::Error::Storage(Arc::new(why)))), - }; - } - })) - .await - .into_iter() - .collect() + key = match self.storage.acquire_key(self.domain.clone()).await { + Ok(k) => k, + Err(why) => return (id, Err(Self::Error::Storage(Arc::new(why)))), + }; + } + })) + .await; + + HashMap::from_iter(tuples) } }