use std::time::Duration;
use reqwest::{Client, ClientBuilder, Method};
use serde::{de::DeserializeOwned, Serialize};
use crate::{auth::Credentials, error::LcuError};
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
pub fn build_lcu_client() -> Result<Client, LcuError> {
Ok(ClientBuilder::new()
.danger_accept_invalid_certs(true)
.danger_accept_invalid_hostnames(true)
.timeout(DEFAULT_TIMEOUT)
.build()?)
}
async fn send<T, B>(
client: &Client,
credentials: &Credentials,
method: Method,
endpoint: &str,
body: Option<&B>,
) -> Result<T, LcuError>
where
T: DeserializeOwned,
B: Serialize + ?Sized,
{
let url = format!("{}{}", credentials.lcu_base_url(), endpoint);
let mut req = client
.request(method, &url)
.header("Authorization", credentials.basic_auth())
.header("Accept", "application/json");
if let Some(b) = body {
req = req.json(b);
}
let resp = req.send().await?;
let status = resp.status();
if !status.is_success() {
let body = resp.text().await.unwrap_or_default();
return Err(LcuError::Status {
code: status.as_u16(),
body,
});
}
Ok(resp.json::<T>().await?)
}
pub async fn lcu_request<T: DeserializeOwned>(
client: &Client,
credentials: &Credentials,
method: Method,
endpoint: &str,
) -> Result<T, LcuError> {
send::<T, ()>(client, credentials, method, endpoint, None).await
}
pub async fn lcu_request_with_body<T, B>(
client: &Client,
credentials: &Credentials,
method: Method,
endpoint: &str,
body: &B,
) -> Result<T, LcuError>
where
T: DeserializeOwned,
B: Serialize + ?Sized,
{
send(client, credentials, method, endpoint, Some(body)).await
}
pub async fn lcu_get<T: DeserializeOwned>(
client: &Client,
credentials: &Credentials,
endpoint: &str,
) -> Result<T, LcuError> {
lcu_request(client, credentials, Method::GET, endpoint).await
}
pub async fn lcu_post<T, B>(
client: &Client,
credentials: &Credentials,
endpoint: &str,
body: &B,
) -> Result<T, LcuError>
where
T: DeserializeOwned,
B: Serialize + ?Sized,
{
lcu_request_with_body(client, credentials, Method::POST, endpoint, body).await
}
pub async fn lcu_delete<T: DeserializeOwned>(
client: &Client,
credentials: &Credentials,
endpoint: &str,
) -> Result<T, LcuError> {
lcu_request(client, credentials, Method::DELETE, endpoint).await
}
pub fn parse_marketing_version(raw: &str) -> Option<String> {
let parts: Vec<&str> = raw.split('.').collect();
if parts.len() < 2 {
return None;
}
let internal_major: u32 = parts[0].parse().ok()?;
let minor = parts[1];
Some(format!("{}.{:0>2}", internal_major + 10, minor))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn version_parsing() {
assert_eq!(parse_marketing_version("4.21.614.6789"), Some("14.21".into()));
assert_eq!(parse_marketing_version("4.3.614.6789"), Some("14.03".into()));
assert_eq!(parse_marketing_version("bad"), None);
assert_eq!(parse_marketing_version(""), None);
}
}