Skip to content

Commit d79c52d

Browse files
committed
fix: implementation of std::marker::Send is not general enough for ws client
1 parent 0ebabfc commit d79c52d

File tree

5 files changed

+57
-73
lines changed

5 files changed

+57
-73
lines changed

src/worldstate/client.rs

Lines changed: 24 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use std::{
1313
};
1414

1515
use moka::future::Cache;
16-
use reqwest::StatusCode;
1716

1817
use super::{
1918
Queryable,
@@ -81,8 +80,8 @@ type ItemCache = Cache<(Language, Box<str>), Option<Item>>;
8180
#[derive(Debug, Clone)]
8281
pub struct Client {
8382
pub(crate) http: reqwest::Client,
84-
pub(crate) base_url: String,
85-
pub(crate) config: ClientConfig,
83+
pub(crate) base_url: Arc<str>,
84+
pub(crate) config: Arc<ClientConfig>,
8685
type_cache: TypeCache,
8786
items_cache: ItemCache,
8887
}
@@ -94,8 +93,8 @@ impl Default for Client {
9493
fn default() -> Self {
9594
Self {
9695
http: reqwest::Client::new(),
97-
base_url: "https://api.warframestat.us".to_owned(),
98-
config: ClientConfig::default(),
96+
base_url: "https://api.warframestat.us".into(),
97+
config: Arc::new(ClientConfig::default()),
9998
type_cache: Cache::builder()
10099
.time_to_live(Duration::from_mins(5))
101100
.build(),
@@ -111,15 +110,15 @@ impl Client {
111110
#[must_use]
112111
pub fn new(
113112
reqwest_client: reqwest::Client,
114-
base_url: String,
113+
base_url: &str,
115114
config: ClientConfig,
116115
type_cache: TypeCache,
117116
items_cache: ItemCache,
118117
) -> Self {
119118
Self {
120119
http: reqwest_client,
121-
base_url,
122-
config,
120+
base_url: base_url.into(),
121+
config: Arc::new(config),
123122
type_cache,
124123
items_cache,
125124
}
@@ -128,7 +127,7 @@ impl Client {
128127
async fn type_cached<T, F>(&self, language: Language, fallback: F) -> Result<T::Return, Error>
129128
where
130129
T: Queryable,
131-
F: AsyncFn() -> Result<T::Return, Error>,
130+
F: AsyncFnOnce() -> Result<T::Return, Error>,
132131
{
133132
let type_id = TypeId::of::<T::Return>();
134133

@@ -178,8 +177,7 @@ impl Client {
178177
where
179178
T: Queryable,
180179
{
181-
self.type_cached::<T, _>(Language::EN, || T::query(&self.base_url, &self.http))
182-
.await
180+
self.fetch_using_lang::<T>(Language::EN).await
183181
}
184182

185183
/// Fetches an instance of a specified model in a supplied Language.
@@ -211,8 +209,8 @@ impl Client {
211209
where
212210
T: Queryable,
213211
{
214-
self.type_cached::<T, _>(language, || {
215-
T::query_with_language(&self.base_url, &self.http, language)
212+
self.type_cached::<T, _>(language, async || {
213+
T::query(&self.base_url.clone(), &self.http.clone(), language).await
216214
})
217215
.await
218216
}
@@ -224,7 +222,7 @@ impl Client {
224222
fallback: F,
225223
) -> Result<Option<Item>, Error>
226224
where
227-
F: AsyncFn() -> Result<Option<Item>, Error>,
225+
F: AsyncFnOnce() -> Result<Option<Item>, Error>,
228226
{
229227
let key = (language, Box::from(query));
230228
if let Some(item) = self.items_cache.get(&key).await {
@@ -270,14 +268,7 @@ impl Client {
270268
/// }
271269
/// ```
272270
pub async fn query_item(&self, query: &str) -> Result<Option<Item>, Error> {
273-
self.cached_item(Language::EN, query, || {
274-
self.query_by_url(format!(
275-
"{}/items/{}/?language=en",
276-
self.base_url,
277-
urlencoding::encode(query),
278-
))
279-
})
280-
.await
271+
self.query_item_using_lang(query, Language::EN).await
281272
}
282273

283274
/// Queries an item by its name and returns the closest matching item.
@@ -310,28 +301,18 @@ impl Client {
310301
query: &str,
311302
language: Language,
312303
) -> Result<Option<Item>, Error> {
313-
self.cached_item(language, query, || {
314-
self.query_by_url(format!(
315-
"{}/items/{}/?language={}",
316-
self.base_url,
317-
urlencoding::encode(query),
318-
language
319-
))
304+
self.cached_item(language, query, async move || {
305+
Item::query(
306+
self.http.clone(),
307+
format!(
308+
"{}/items/{}/?language={}",
309+
self.base_url,
310+
urlencoding::encode(query),
311+
language
312+
),
313+
)
314+
.await
320315
})
321316
.await
322317
}
323-
324-
async fn query_by_url(&self, url: String) -> Result<Option<Item>, Error> {
325-
let response = self.http.get(url).send().await?;
326-
327-
if response.status() == StatusCode::NOT_FOUND {
328-
return Ok(None);
329-
}
330-
331-
let json = response.text().await?;
332-
333-
let item = serde_json::from_str::<Item>(&json)?;
334-
335-
Ok(Some(item))
336-
}
337318
}

src/worldstate/models/base.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ use crate::worldstate::language::Language;
2222

2323
/// Types implementing this have an actual endpoint on the API.
2424
pub trait Endpoint {
25-
/// Returns the URL to the english endpoint.
26-
///
27-
/// Getting the english endpoint is free, as concatenating is done at compile time.
28-
fn endpoint_en(base_url: &str) -> String;
29-
3025
/// Returns the URL to the endpoint of the specified language.
3126
///
3227
/// Getting this endpoint is __NOT__ free, as concatenating is done at runtime.
@@ -80,23 +75,6 @@ pub trait Queryable: Endpoint + Clone + 'static {
8075
fn query(
8176
base_url: &str,
8277
request_executor: &reqwest::Client,
83-
) -> impl std::future::Future<Output = Result<Self::Return, Error>> + Send {
84-
async {
85-
Ok(request_executor
86-
.get(Self::endpoint_en(base_url))
87-
.send()
88-
.await?
89-
.json::<Self::Return>()
90-
.await?)
91-
}
92-
}
93-
94-
/// Queries a model with the specified language and returns an instance of
95-
/// [`itself`](Queryable::Return).
96-
#[must_use]
97-
fn query_with_language(
98-
base_url: &str,
99-
request_executor: &reqwest::Client,
10078
language: Language,
10179
) -> impl std::future::Future<Output = Result<Self::Return, Error>> + Send {
10280
async move {

src/worldstate/models/items/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub use modification::Mod;
1010
pub use node::Node;
1111
pub use pet::Pet;
1212
pub use relic::Relic;
13+
use reqwest::StatusCode;
1314
pub use resource::Resource;
1415
pub use sentinel::Sentinel;
1516
pub use serde::Deserialize;
@@ -20,6 +21,8 @@ pub use warframe::{
2021
};
2122
use weapon::Weapon;
2223

24+
use crate::worldstate::Error;
25+
2326
mod arcane;
2427
mod archwing;
2528
mod gear;
@@ -225,6 +228,23 @@ pub enum Item {
225228
)]
226229
Weapon(Box<Weapon>),
227230
}
231+
232+
impl Item {
233+
pub(crate) async fn query(http: reqwest::Client, url: String) -> Result<Option<Item>, Error> {
234+
let response = http.get(url).send().await?;
235+
236+
if response.status() == StatusCode::NOT_FOUND {
237+
return Ok(None);
238+
}
239+
240+
let json = response.text().await?;
241+
242+
let item = serde_json::from_str::<Item>(&json)?;
243+
244+
Ok(Some(item))
245+
}
246+
}
247+
228248
#[cfg(test)]
229249
mod test {
230250
use rstest::rstest;

src/worldstate/models/mod.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//! use warframe::worldstate::{
1515
//! Client,
1616
//! Error,
17+
//! Language,
1718
//! Queryable,
1819
//! queryable::{
1920
//! Cetus,
@@ -24,9 +25,18 @@
2425
//! async fn main() -> Result<(), Error> {
2526
//! let reqwest_client = reqwest::Client::new();
2627
//!
27-
//! let cetus: Cetus = Cetus::query("https://api.warframestat.us/", &reqwest_client).await?;
28-
//! let fissures: Vec<Fissure> =
29-
//! Fissure::query("https://api.warframestat.us/", &reqwest_client).await?;
28+
//! let cetus: Cetus = Cetus::query(
29+
//! "https://api.warframestat.us/",
30+
//! &reqwest_client,
31+
//! Language::EN,
32+
//! )
33+
//! .await?;
34+
//! let fissures: Vec<Fissure> = Fissure::query(
35+
//! "https://api.warframestat.us/",
36+
//! &reqwest_client,
37+
//! Language::EN,
38+
//! )
39+
//! .await?;
3040
//!
3141
//! Ok(())
3242
//! }

warframe-macros/src/model/struct_impl/args.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,8 @@ pub struct QueryableImpl {
3535
fn get_endpoint_impl(struct_name: &Ident, endpoint: &LitStr) -> syn::Result<TokenStream> {
3636
let endpoint_value = endpoint.value();
3737

38-
let endpoint_en = format!("/pc{endpoint_value}/?language=en");
39-
4038
Ok(quote! {
4139
impl crate::worldstate::models::base::Endpoint for #struct_name {
42-
fn endpoint_en(base_url: &str) -> String {
43-
format!("{}{}", base_url, #endpoint_en)
44-
}
4540
fn endpoint(base_url: &str, language: crate::worldstate::language::Language) -> String {
4641
format!(
4742
"{}/pc{}/?language={}",

0 commit comments

Comments
 (0)