Skip to main content

lichess_api/model/board/stream/
game.rs

1use crate::model::{Clock, Room, Speed, Variant};
2use serde::{Deserialize, Serialize};
3use serde_with::skip_serializing_none;
4
5#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
6#[serde(rename_all = "lowercase")]
7pub enum GameColor {
8    White,
9    Black,
10}
11
12#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
13#[serde(rename_all = "camelCase")]
14pub enum GameStatusName {
15    Created,
16    Started,
17    Aborted,
18    Mate,
19    Resign,
20    Stalemate,
21    Timeout,
22    Draw,
23    Outoftime,
24    Cheat,
25    NoStart,
26    UnknownFinish,
27    VariantEnd,
28}
29
30#[derive(Default, Clone, Debug, Serialize)]
31pub struct GetQuery;
32
33pub type GetRequest = crate::model::Request<GetQuery>;
34
35impl GetRequest {
36    pub fn new(game_id: &str) -> Self {
37        Self::get(format!("/api/board/game/stream/{game_id}"), None, None)
38    }
39}
40
41impl<S: AsRef<str>> From<S> for GetRequest {
42    fn from(s: S) -> Self {
43        Self::new(s.as_ref())
44    }
45}
46
47#[skip_serializing_none]
48#[derive(Clone, Debug, Deserialize, Serialize)]
49#[serde(tag = "type")]
50#[serde(rename_all = "camelCase")]
51// Boxing would ripple through every match arm across the crate for a rarely-streamed enum; not worth it.
52#[allow(clippy::large_enum_variant)]
53pub enum Event {
54    GameFull {
55        #[serde(flatten)]
56        game_full: GameFullEvent,
57    },
58    GameState {
59        #[serde(flatten)]
60        game_state: GameStateEvent,
61    },
62    ChatLine {
63        #[serde(flatten)]
64        chat_line: ChatLineEvent,
65    },
66    OpponentGone {
67        #[serde(flatten)]
68        opponent_gone: OpponentGoneEvent,
69    },
70}
71
72#[skip_serializing_none]
73#[derive(Clone, Debug, Deserialize, Serialize)]
74#[serde(rename_all = "camelCase")]
75pub struct GameFullEvent {
76    pub id: String,
77    pub variant: Variant,
78    pub rated: bool,
79    pub clock: Option<Clock>,
80    pub speed: Speed,
81    pub perf: Perf,
82    pub created_at: u64,
83    pub white: GameEventPlayer,
84    pub black: GameEventPlayer,
85    pub initial_fen: Option<String>,
86    pub state: Option<GameStateEvent>,
87    pub tournament_id: Option<String>,
88}
89
90#[skip_serializing_none]
91#[derive(Clone, Debug, Deserialize, Serialize)]
92#[serde(rename_all = "camelCase")]
93pub struct GameStateEvent {
94    // Will always be gameState, but needed to avoid cycles.
95    pub r#type: Option<String>,
96    pub moves: String,
97    pub wtime: u64,
98    pub btime: u64,
99    pub winc: u64,
100    pub binc: u64,
101    pub status: GameStatusName,
102    pub winner: Option<GameColor>,
103    pub wdraw: Option<bool>,
104    pub bdraw: Option<bool>,
105    pub wtakeback: Option<bool>,
106    pub btakeback: Option<bool>,
107}
108
109#[skip_serializing_none]
110#[derive(Clone, Debug, Deserialize, Serialize)]
111#[serde(rename_all = "camelCase")]
112pub struct ChatLineEvent {
113    pub room: Room,
114    pub username: String,
115    pub text: String,
116}
117
118#[skip_serializing_none]
119#[derive(Clone, Debug, Deserialize, Serialize)]
120#[serde(rename_all = "camelCase")]
121pub struct OpponentGoneEvent {
122    pub gone: bool,
123    pub claim_win_in_seconds: Option<u32>,
124}
125
126#[derive(Clone, Debug, Deserialize, Serialize)]
127#[serde(rename_all = "camelCase")]
128pub struct GameEventPlayer {
129    pub id: String,
130    pub name: String,
131    #[serde(skip_serializing_if = "Option::is_none")]
132    pub ai_level: Option<u32>,
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub title: Option<String>,
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub rating: Option<u32>,
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub provisional: Option<bool>,
139}
140
141#[derive(Clone, Debug, Serialize, Deserialize)]
142pub struct Perf {
143    pub name: String,
144}