use std::sync::Arc;
use std::time::Duration;
use crate::cache::ApiCache;
use crate::error::{Error, Result};
use crate::internal::{
build_default_rate_limiter, build_http_client, build_rate_limiter, fetch_items_internal,
};
use crate::models::{Item, ItemIndex, Language, Platform};
use super::{Client, ClientConfig, Unauthenticated};
const DEFAULT_CACHE_MAX_AGE: Duration = Duration::from_secs(24 * 60 * 60);
#[derive(Debug, Clone, Default)]
pub struct ClientBuilder {
config: ClientConfig,
}
impl ClientBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn platform(mut self, platform: Platform) -> Self {
self.config.platform = platform;
self
}
pub fn language(mut self, language: Language) -> Self {
self.config.language = language;
self
}
pub fn crossplay(mut self, enabled: bool) -> Self {
self.config.crossplay = enabled;
self
}
pub fn rate_limit(mut self, requests_per_second: u32) -> Self {
self.config.rate_limit = requests_per_second;
self
}
pub fn config(mut self, config: ClientConfig) -> Self {
self.config = config;
self
}
pub async fn build(self) -> Result<Client<Unauthenticated>> {
let http = build_http_client(
self.config.platform,
self.config.language,
self.config.crossplay,
)
.map_err(Error::Network)?;
let limiter = if self.config.rate_limit == 3 {
build_default_rate_limiter()
} else {
build_rate_limiter(self.config.rate_limit)
};
let items = fetch_items_internal(&http).await?;
let item_index = Arc::new(ItemIndex::new(items));
Ok(Client::new_unauthenticated(
http,
self.config,
limiter,
item_index,
))
}
pub async fn build_with_cache(self, cache: &mut ApiCache) -> Result<Client<Unauthenticated>> {
let http = build_http_client(
self.config.platform,
self.config.language,
self.config.crossplay,
)
.map_err(Error::Network)?;
let limiter = if self.config.rate_limit == 3 {
build_default_rate_limiter()
} else {
build_rate_limiter(self.config.rate_limit)
};
let items = if cache.has_fresh_items(DEFAULT_CACHE_MAX_AGE) {
cache.get_items().unwrap().to_vec()
} else {
let items = fetch_items_internal(&http).await?;
cache.set_items(items.clone());
items
};
let item_index = Arc::new(ItemIndex::new(items));
Ok(Client::new_unauthenticated(
http,
self.config,
limiter,
item_index,
))
}
pub fn build_with_items(self, items: Vec<Item>) -> Result<Client<Unauthenticated>> {
let http = build_http_client(
self.config.platform,
self.config.language,
self.config.crossplay,
)
.map_err(Error::Network)?;
let limiter = if self.config.rate_limit == 3 {
build_default_rate_limiter()
} else {
build_rate_limiter(self.config.rate_limit)
};
let item_index = Arc::new(ItemIndex::new(items));
Ok(Client::new_unauthenticated(
http,
self.config,
limiter,
item_index,
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builder_default() {
let builder = ClientBuilder::new();
assert_eq!(builder.config.platform, Platform::Pc);
assert_eq!(builder.config.language, Language::English);
assert!(builder.config.crossplay);
assert_eq!(builder.config.rate_limit, 3);
}
#[test]
fn test_builder_chain() {
let builder = ClientBuilder::new()
.platform(Platform::Ps4)
.language(Language::German)
.crossplay(false)
.rate_limit(5);
assert_eq!(builder.config.platform, Platform::Ps4);
assert_eq!(builder.config.language, Language::German);
assert!(!builder.config.crossplay);
assert_eq!(builder.config.rate_limit, 5);
}
#[test]
fn test_builder_build_with_items() {
let client = ClientBuilder::new().build_with_items(vec![]);
assert!(client.is_ok());
assert_eq!(client.unwrap().items().len(), 0);
}
}