use reqwest::Method;
use serde::{Deserialize, Serialize};
use crate::client::LichessClient;
use crate::config::Host;
use crate::error::Result;
use crate::http;
use crate::model::{LichessLightUser, LichessVariantKey};
#[derive(Debug)]
pub struct SimulsApi<'a> {
client: &'a LichessClient,
}
impl<'a> SimulsApi<'a> {
pub(crate) fn new(client: &'a LichessClient) -> Self {
Self { client }
}
pub async fn current(&self) -> Result<LichessSimuls> {
let request = self
.client
.request(Method::GET, Host::Default, "/api/simul");
http::json(request, "LichessSimuls").await
}
}
impl LichessClient {
#[must_use]
pub fn simuls(&self) -> SimulsApi<'_> {
SimulsApi::new(self)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct LichessSimulHost {
#[serde(flatten)]
pub user: LichessLightUser,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub rating: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub provisional: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub game_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub online: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct LichessSimulVariant {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub key: Option<LichessVariantKey>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct LichessSimul {
pub id: String,
pub host: LichessSimulHost,
pub name: String,
pub full_name: String,
pub variants: Vec<LichessSimulVariant>,
pub is_created: bool,
pub is_finished: bool,
pub is_running: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub estimated_start_at: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub started_at: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub finished_at: Option<i64>,
pub nb_applicants: u32,
pub nb_pairings: u32,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct LichessSimuls {
#[serde(default)]
pub pending: Vec<LichessSimul>,
#[serde(default)]
pub created: Vec<LichessSimul>,
#[serde(default)]
pub started: Vec<LichessSimul>,
#[serde(default)]
pub finished: Vec<LichessSimul>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_simul_with_flattened_host() {
let json = r#"{
"id":"abc","name":"Sunday","fullName":"Sunday Simul",
"host":{"id":"bobby","name":"Bobby","rating":2400,"online":true},
"variants":[{"key":"standard","name":"Standard"}],
"isCreated":true,"isFinished":false,"isRunning":false,
"nbApplicants":3,"nbPairings":0
}"#;
let simul: LichessSimul = serde_json::from_str(json).unwrap();
assert_eq!(simul.host.user.id, "bobby");
assert_eq!(simul.host.rating, Some(2400));
assert_eq!(simul.variants[0].key, Some(LichessVariantKey::Standard));
assert!(simul.is_created);
}
#[test]
fn simuls_default_missing_groups_to_empty() {
let simuls: LichessSimuls = serde_json::from_str(r#"{"started":[]}"#).unwrap();
assert!(simuls.pending.is_empty());
assert!(simuls.finished.is_empty());
}
}