Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start tracking game stats and sending them to uwhportal #225

Merged
merged 3 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions refbox/src/app/message.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::tournament_manager::PenaltyKind;
use crate::tournament_manager::penalty::PenaltyKind;
use tokio::time::Duration;
use uwh_common::{
game_snapshot::{Color as GameColor, GameSnapshot},
Expand Down Expand Up @@ -65,8 +65,7 @@ pub enum Message {
GotRemoteId(u32),
DeleteRemote(usize),
ConfirmationSelected(ConfirmationOption),
BlackTimeout(bool),
WhiteTimeout(bool),
TeamTimeout(GameColor, bool),
RefTimeout(bool),
PenaltyShot(bool),
EndTimeout,
Expand Down Expand Up @@ -125,8 +124,7 @@ impl Message {
| Self::GotRemoteId(_)
| Self::DeleteRemote(_)
| Self::ConfirmationSelected(_)
| Self::BlackTimeout(_)
| Self::WhiteTimeout(_)
| Self::TeamTimeout(_, _)
| Self::RefTimeout(_)
| Self::PenaltyShot(_)
| Self::EndTimeout
Expand Down
102 changes: 60 additions & 42 deletions refbox/src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
config::{Config, Mode},
penalty_editor::*,
sound_controller::*,
tournament_manager::*,
tournament_manager::{penalty::*, *},
};
use iced::{executor, widget::column, Application, Command, Subscription};
use iced_futures::{
Expand All @@ -29,7 +29,8 @@ use tokio_serial::SerialPortBuilder;
use uwh_common::{
config::Game as GameConfig,
drawing_support::*,
game_snapshot::{Color as GameColor, GamePeriod, GameSnapshot, TimeoutSnapshot},
game_snapshot::{GamePeriod, GameSnapshot, TimeoutSnapshot},
uwhportal::UwhPortalClient,
uwhscores::*,
};

Expand Down Expand Up @@ -64,6 +65,7 @@ pub struct RefBoxApp {
message_listener: MessageListener,
msg_tx: mpsc::UnboundedSender<Message>,
client: Option<Client>,
uwhportal_client: Option<UwhPortalClient>,
using_uwhscores: bool,
tournaments: Option<BTreeMap<u32, TournamentInfo>>,
games: Option<BTreeMap<u32, GameInfo>>,
Expand Down Expand Up @@ -117,7 +119,7 @@ impl RefBoxApp {
fn apply_snapshot(&mut self, mut new_snapshot: GameSnapshot) {
if new_snapshot.current_period != self.snapshot.current_period {
if new_snapshot.current_period == GamePeriod::BetweenGames {
self.handle_game_end(new_snapshot.next_game_number);
self.handle_game_end(new_snapshot.game_number, new_snapshot.next_game_number);
} else if self.snapshot.current_period == GamePeriod::BetweenGames {
self.handle_game_start(new_snapshot.game_number);
}
Expand Down Expand Up @@ -387,6 +389,18 @@ impl RefBoxApp {
}
}

fn post_game_stats(&self, tid: u32, gid: u32, stats: String) {
if let Some(ref uwhportal_client) = self.uwhportal_client {
let request = uwhportal_client.post_game_stats(tid, gid, stats);
tokio::spawn(async move {
match request.await {
Ok(()) => info!("Successfully posted game stats"),
Err(e) => error!("Failed to post game stats: {e}"),
}
});
}
}

fn handle_game_start(&mut self, new_game_num: u32) {
if self.using_uwhscores {
if let (Some(ref games), Some(ref pool)) = (&self.games, &self.current_pool) {
Expand Down Expand Up @@ -420,12 +434,28 @@ impl RefBoxApp {
}
}

fn handle_game_end(&self, next_game_num: u32) {
fn handle_game_end(&self, game_number: u32, next_game_num: u32) {
if self.using_uwhscores {
let mut stats = self
.tm
.lock()
.unwrap()
.last_game_stats()
.map(|s| s.as_json());

if let Some(ref stats) = stats {
info!("Game ended, stats were: {:?}", stats);
} else {
warn!("Game ended, but no stats were available");
}

if let Some(tid) = self.current_tid {
self.request_game_details(tid, next_game_num);
if let Some(stats) = stats.take() {
self.post_game_stats(tid, game_number, stats);
}
} else {
error!("Missing current tid to request game info");
error!("Missing current tid to handle game end");
}
}
}
Expand Down Expand Up @@ -480,6 +510,20 @@ impl Application for RefBoxApp {
}
};

let uwhportal_client = match UwhPortalClient::new(
&config.uwhportal.url,
Some(&config.uwhportal.email),
Some(&config.uwhportal.password),
require_https,
REQUEST_TIMEOUT,
) {
Ok(c) => Some(c),
Err(e) => {
error!("Failed to start UWH Portal Client: {e}");
None
}
};

let clock_running_receiver = tm.get_start_stop_rx();

let tm = Arc::new(Mutex::new(tm));
Expand Down Expand Up @@ -510,6 +554,7 @@ impl Application for RefBoxApp {
message_listener,
msg_tx,
client,
uwhportal_client,
using_uwhscores: false,
tournaments: None,
games: None,
Expand Down Expand Up @@ -649,10 +694,7 @@ impl Application for RefBoxApp {
Message::EditScores => {
let tm = self.tm.lock().unwrap();
self.app_state = AppState::ScoreEdit {
scores: BlackWhiteBundle {
black: tm.get_b_score(),
white: tm.get_w_score(),
},
scores: tm.get_scores(),
is_confirmation: false,
};
trace!("AppState changed to {:?}", self.app_state);
Expand All @@ -664,10 +706,7 @@ impl Application for RefBoxApp {
} else {
let mut tm = self.tm.lock().unwrap();
let now = Instant::now();
match color {
GameColor::Black => tm.add_b_score(0, now),
GameColor::White => tm.add_w_score(0, now),
}
tm.add_score(color, 0, now);
let snapshot = tm.generate_snapshot(now).unwrap(); // TODO: Remove this unwrap
std::mem::drop(tm);
self.apply_snapshot(snapshot);
Expand Down Expand Up @@ -704,7 +743,7 @@ impl Application for RefBoxApp {
self.post_game_score(game, scores);
}

tm.set_scores(scores.black, scores.white, now);
tm.set_scores(scores, now);
tm.start_clock(now);

// Update `tm` after game ends to get into Between Games
Expand All @@ -718,7 +757,7 @@ impl Application for RefBoxApp {
tm.stop_clock(now).unwrap();
AppState::ConfirmScores(scores)
} else {
tm.set_scores(scores.black, scores.white, now);
tm.set_scores(scores, now);
AppState::MainPage
}
} else {
Expand Down Expand Up @@ -897,18 +936,12 @@ impl Application for RefBoxApp {

let app_state = if tm.current_period() == GamePeriod::SuddenDeath {
tm.stop_clock(now).unwrap();
let mut scores = BlackWhiteBundle {
black: tm.get_b_score(),
white: tm.get_w_score(),
};
let mut scores = tm.get_scores();
scores[color] = scores[color].saturating_add(1);

AppState::ConfirmScores(scores)
} else {
match color {
GameColor::Black => tm.add_b_score(player.try_into().unwrap(), now),
GameColor::White => tm.add_w_score(player.try_into().unwrap(), now),
};
tm.add_score(color, player.try_into().unwrap(), now);
AppState::MainPage
};
let snapshot = tm.generate_snapshot(now).unwrap();
Expand Down Expand Up @@ -1467,7 +1500,7 @@ impl Application for RefBoxApp {
self.post_game_score(game, scores);
}

tm.set_scores(scores.black, scores.white, now);
tm.set_scores(scores, now);
tm.start_clock(now);
tm.update(now + Duration::from_millis(2)).unwrap(); // Need to update after game ends

Expand All @@ -1484,28 +1517,13 @@ impl Application for RefBoxApp {

trace!("AppState changed to {:?}", self.app_state);
}
Message::BlackTimeout(switch) => {
let mut tm = self.tm.lock().unwrap();
let now = Instant::now();
if switch {
tm.switch_to_b_timeout().unwrap();
} else {
tm.start_b_timeout(now).unwrap();
}
if let AppState::TimeEdit(_, _, ref mut time) = self.app_state {
*time = Some(tm.timeout_clock_time(now).unwrap());
}
let snapshot = tm.generate_snapshot(now).unwrap();
std::mem::drop(tm);
self.apply_snapshot(snapshot);
}
Message::WhiteTimeout(switch) => {
Message::TeamTimeout(color, switch) => {
let mut tm = self.tm.lock().unwrap();
let now = Instant::now();
if switch {
tm.switch_to_w_timeout().unwrap();
tm.switch_to_team_timeout(color).unwrap();
} else {
tm.start_w_timeout(now).unwrap();
tm.start_team_timeout(color, now).unwrap();
}
if let AppState::TimeEdit(_, _, ref mut time) = self.app_state {
*time = Some(tm.timeout_clock_time(now).unwrap());
Expand Down
20 changes: 11 additions & 9 deletions refbox/src/app/view_builders/shared_elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ use std::{
use uwh_common::{
config::Game as GameConfig,
drawing_support::*,
game_snapshot::{GamePeriod, GameSnapshot, PenaltySnapshot, PenaltyTime, TimeoutSnapshot},
game_snapshot::{
Color as GameColor, GamePeriod, GameSnapshot, PenaltySnapshot, PenaltyTime, TimeoutSnapshot,
},
uwhscores::GameInfo,
};

Expand Down Expand Up @@ -186,9 +188,9 @@ pub(in super::super) fn build_timeout_ribbon<'a>(
let black = match snapshot.timeout {
TimeoutSnapshot::None => make_multi_label_message_button(
("BLACK", "TIMEOUT"),
tm.can_start_b_timeout()
tm.can_start_team_timeout(GameColor::Black)
.ok()
.map(|_| Message::BlackTimeout(false)),
.map(|_| Message::TeamTimeout(GameColor::Black, false)),
)
.style(ButtonStyle::Black),
TimeoutSnapshot::Black(_) => {
Expand All @@ -198,9 +200,9 @@ pub(in super::super) fn build_timeout_ribbon<'a>(
TimeoutSnapshot::White(_) | TimeoutSnapshot::Ref(_) | TimeoutSnapshot::PenaltyShot(_) => {
make_multi_label_message_button(
("SWITCH TO", "BLACK"),
tm.can_switch_to_b_timeout()
tm.can_switch_to_team_timeout(GameColor::Black)
.ok()
.map(|_| Message::BlackTimeout(true)),
.map(|_| Message::TeamTimeout(GameColor::Black, true)),
)
.style(ButtonStyle::Black)
}
Expand All @@ -209,9 +211,9 @@ pub(in super::super) fn build_timeout_ribbon<'a>(
let white = match snapshot.timeout {
TimeoutSnapshot::None => make_multi_label_message_button(
("WHITE", "TIMEOUT"),
tm.can_start_w_timeout()
tm.can_start_team_timeout(GameColor::White)
.ok()
.map(|_| Message::WhiteTimeout(false)),
.map(|_| Message::TeamTimeout(GameColor::White, false)),
)
.style(ButtonStyle::White),
TimeoutSnapshot::White(_) => {
Expand All @@ -221,9 +223,9 @@ pub(in super::super) fn build_timeout_ribbon<'a>(
TimeoutSnapshot::Black(_) | TimeoutSnapshot::Ref(_) | TimeoutSnapshot::PenaltyShot(_) => {
make_multi_label_message_button(
("SWITCH TO", "WHITE"),
tm.can_switch_to_w_timeout()
tm.can_start_team_timeout(GameColor::White)
.ok()
.map(|_| Message::WhiteTimeout(true)),
.map(|_| Message::TeamTimeout(GameColor::White, true)),
)
.style(ButtonStyle::White)
}
Expand Down
26 changes: 26 additions & 0 deletions refbox/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,23 @@ impl Default for UwhScores {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct UwhPortal {
pub url: String,
pub email: String,
pub password: String,
}

impl Default for UwhPortal {
fn default() -> Self {
Self {
url: "https://api.uwhscores.prod.zmvp.host".to_string(),
email: String::new(),
password: String::new(),
}
}
}

#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Config {
pub mode: Mode,
Expand All @@ -50,6 +67,7 @@ pub struct Config {
pub game: Game,
pub hardware: Hardware,
pub uwhscores: UwhScores,
pub uwhportal: UwhPortal,
pub sound: SoundSettings,
}

Expand Down Expand Up @@ -84,6 +102,14 @@ mod test {
assert_eq!(deser, Ok(u));
}

#[test]
fn test_ser_uwhportal() {
let u: UwhPortal = Default::default();
let serialized = toml::to_string(&u).unwrap();
let deser = toml::from_str(&serialized);
assert_eq!(deser, Ok(u));
}

#[test]
fn test_ser_config() {
let config: Config = Default::default();
Expand Down
1 change: 1 addition & 0 deletions refbox/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {

let log_config = log_config
.logger(Logger::builder().build(APP_NAME, log_level)) // Setup the logging from the refbox app to use `log_level`
.logger(Logger::builder().build("uwh_common", log_level)) // Setup the logging from mio to use `LevelFilter::Warn`
.build(root)
.unwrap();

Expand Down
Loading