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    pub published_deck_id: Option<String>,
39    pub deck_fingerprint: Option<String>,
40}
41
42#[derive(Debug, Serialize)]
43pub struct CardEntry {
44    pub name: String,
45    pub set_code: String,
46    pub count: u32,
47}
48
49#[derive(Debug, Serialize)]
50#[serde(tag = "event", rename_all = "snake_case")]
51pub enum AnalyticsEvent {
52    GameStarted {
53        ts: String,
54        game_id: String,
55        room_id: String,
56        format: GameFormat,
57        engine: EngineKind,
58        hosted: bool,
59        official: bool,
60        starting_life: i32,
61        players: Vec<SeatInfo>,
62    },
63    GameEnded {
64        ts: String,
65        game_id: String,
66        room_id: String,
67        reason: GameEndReason,
68        duration_s: f64,
69        game_over: bool,
70        winner: Option<String>,
71        conceded: Vec<String>,
72        fatal_message: Option<String>,
73    },
74    DeckSelected {
75        ts: String,
76        room_id: String,
77        username: String,
78        is_bot: bool,
79        deck_name: String,
80        commander: Option<String>,
81        cards: Vec<CardEntry>,
82        sideboard_count: usize,
83    },
84    SeatJoined {
85        ts: String,
86        room_id: String,
87        username: String,
88        is_bot: bool,
89        observer: bool,
90    },
91    SeatLeft {
92        ts: String,
93        room_id: String,
94        username: String,
95    },
96}
97
98#[derive(Serialize)]
99pub struct CaptureLine<'a> {
100    pub ts: String,
101    pub from: &'a str,
102    pub envelope: &'a Value,
103}