Skip to main content

manabrew_server/analytics/
event.rs

1use serde::Serialize;
2use serde_json::Value;
3
4use crate::protocol::{EngineKind, GameFormat};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
7#[serde(rename_all = "snake_case")]
8pub enum GameEndReason {
9    GameOver,
10    EngineFatal,
11    HostEnded,
12    ReconnectTimeout,
13    HostLost,
14    StaleExpired,
15    Abandoned,
16}
17
18impl GameEndReason {
19    pub fn as_str(self) -> &'static str {
20        match self {
21            Self::GameOver => "game_over",
22            Self::EngineFatal => "engine_fatal",
23            Self::HostEnded => "host_ended",
24            Self::ReconnectTimeout => "reconnect_timeout",
25            Self::HostLost => "host_lost",
26            Self::StaleExpired => "stale_expired",
27            Self::Abandoned => "abandoned",
28        }
29    }
30}
31
32#[derive(Debug, Serialize)]
33pub struct SeatInfo {
34    pub username: String,
35    pub is_bot: bool,
36    pub deck_name: Option<String>,
37    pub commander: Option<String>,
38}
39
40#[derive(Debug, Serialize)]
41pub struct CardEntry {
42    pub name: String,
43    pub set_code: String,
44    pub count: u32,
45}
46
47#[derive(Debug, Serialize)]
48#[serde(tag = "event", rename_all = "snake_case")]
49pub enum AnalyticsEvent {
50    GameStarted {
51        ts: String,
52        game_id: String,
53        room_id: String,
54        format: GameFormat,
55        engine: EngineKind,
56        hosted: bool,
57        official: bool,
58        starting_life: i32,
59        players: Vec<SeatInfo>,
60    },
61    GameEnded {
62        ts: String,
63        game_id: String,
64        room_id: String,
65        reason: GameEndReason,
66        duration_s: f64,
67        game_over: bool,
68        winner: Option<String>,
69        conceded: Vec<String>,
70        fatal_message: Option<String>,
71    },
72    DeckSelected {
73        ts: String,
74        room_id: String,
75        username: String,
76        is_bot: bool,
77        deck_name: String,
78        commander: Option<String>,
79        cards: Vec<CardEntry>,
80        sideboard_count: usize,
81    },
82    SeatJoined {
83        ts: String,
84        room_id: String,
85        username: String,
86        is_bot: bool,
87        observer: bool,
88    },
89    SeatLeft {
90        ts: String,
91        room_id: String,
92        username: String,
93    },
94}
95
96#[derive(Serialize)]
97pub struct CaptureLine<'a> {
98    pub ts: String,
99    pub from: &'a str,
100    pub envelope: &'a Value,
101}