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

Portal tokens and config migration #245

Merged
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
3 changes: 1 addition & 2 deletions refbox/src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,8 +512,7 @@ impl Application for RefBoxApp {

let uwhportal_client = match UwhPortalClient::new(
&config.uwhportal.url,
Some(&config.uwhportal.email),
Some(&config.uwhportal.password),
Some(&config.uwhportal.token),
require_https,
REQUEST_TIMEOUT,
) {
Expand Down
274 changes: 267 additions & 7 deletions refbox/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::sound_controller::SoundSettings;
use derivative::Derivative;
use enum_derive_2018::EnumDisplay;
use enum_derive_2018::{EnumDisplay, EnumFromStr};
use macro_attr_2018::macro_attr;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use time::UtcOffset;
use toml::Table;
pub use uwh_common::config::Game;

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
Expand All @@ -23,6 +25,26 @@ impl Default for Hardware {
}
}

impl Hardware {
pub fn migrate(old: &Table) -> Self {
let Self {
mut screen_x,
mut screen_y,
mut white_on_right,
} = Default::default();

get_integer_value(old, "screen_x", &mut screen_x);
get_integer_value(old, "screen_y", &mut screen_y);
get_boolean_value(old, "white_on_right", &mut white_on_right);

Self {
screen_x,
screen_y,
white_on_right,
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct UwhScores {
pub url: String,
Expand All @@ -42,23 +64,52 @@ impl Default for UwhScores {
}
}

impl UwhScores {
pub fn migrate(old: &Table) -> Self {
let Self {
mut url,
mut email,
mut password,
timezone,
} = Default::default();

get_string_value(old, "url", &mut url);
get_string_value(old, "email", &mut email);
get_string_value(old, "password", &mut password);

Self {
url,
email,
password,
timezone,
}
}
}

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

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

impl UwhPortal {
pub fn migrate(old: &Table) -> Self {
let Self { mut url, mut token } = Default::default();
get_string_value(old, "url", &mut url);
get_string_value(old, "token", &mut token);
Self { url, token }
}
}

#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Config {
pub mode: Mode,
Expand All @@ -71,8 +122,69 @@ pub struct Config {
pub sound: SoundSettings,
}

impl Config {
pub fn migrate(old: &Table) -> Self {
let Self {
mut mode,
mut hide_time,
mut collect_scorer_cap_num,
mut game,
mut hardware,
mut uwhscores,
mut uwhportal,
mut sound,
} = Default::default();

if let Some(old_mode) = old.get("mode") {
if let Some(old_mode) = old_mode.as_str() {
if let Ok(old_mode) = old_mode.parse() {
mode = old_mode;
}
}
}
get_boolean_value(old, "hide_time", &mut hide_time);
get_boolean_value(old, "collect_scorer_cap_num", &mut collect_scorer_cap_num);
if let Some(old_game) = old.get("game") {
if let Some(old_game) = old_game.as_table() {
game = Game::migrate(old_game);
}
}
if let Some(old_hardware) = old.get("hardware") {
if let Some(old_hardware) = old_hardware.as_table() {
hardware = Hardware::migrate(old_hardware);
}
}
if let Some(old_uwhscores) = old.get("uwhscores") {
if let Some(old_uwhscores) = old_uwhscores.as_table() {
uwhscores = UwhScores::migrate(old_uwhscores);
}
}
if let Some(old_uwhportal) = old.get("uwhportal") {
if let Some(old_uwhportal) = old_uwhportal.as_table() {
uwhportal = UwhPortal::migrate(old_uwhportal);
}
}
if let Some(old_sound) = old.get("sound") {
if let Some(old_sound) = old_sound.as_table() {
sound = SoundSettings::migrate(old_sound);
}
}

Self {
mode,
hide_time,
collect_scorer_cap_num,
game,
hardware,
uwhscores,
uwhportal,
sound,
}
}
}

macro_attr! {
#[derive(Debug, Clone, Copy, Derivative, PartialEq, Eq, Serialize, Deserialize, EnumDisplay!)]
#[derive(Debug, Clone, Copy, Derivative, PartialEq, Eq, Serialize, Deserialize, EnumDisplay!, EnumFromStr!)]
#[derivative(Default)]
pub enum Mode {
#[derivative(Default)]
Expand All @@ -82,9 +194,38 @@ macro_attr! {
}
}

fn get_integer_value<T: DeserializeOwned + TryFrom<i64>>(table: &Table, key: &str, save: &mut T) {
if let Some(value) = table.get(key) {
if let Some(value) = value.as_integer() {
if let Ok(value) = value.try_into() {
*save = value;
}
}
}
}

fn get_boolean_value(table: &Table, key: &str, save: &mut bool) {
if let Some(value) = table.get(key) {
if let Some(value) = value.as_bool() {
*save = value;
}
}
}

fn get_string_value(table: &Table, key: &str, save: &mut String) {
if let Some(value) = table.get(key) {
if let Some(value) = value.as_str() {
*save = value.to_string();
}
}
}

#[cfg(test)]
mod test {
use crate::sound_controller::Volume;

use super::*;
use std::time::Duration;

#[test]
fn test_ser_hardware() {
Expand Down Expand Up @@ -117,4 +258,123 @@ mod test {
let deser = toml::from_str(&serialized);
assert_eq!(deser, Ok(config));
}

#[test]
fn test_migrate_hardware() {
let mut old: Table = Default::default();
old.insert("screen_x".to_string(), toml::Value::Integer(123));
old.insert("screen_y".to_string(), toml::Value::Integer(456));
old.insert("white_on_right".to_string(), toml::Value::Boolean(true));
let hw = Hardware::migrate(&old);
assert_eq!(hw.screen_x, 123);
assert_eq!(hw.screen_y, 456);
assert_eq!(hw.white_on_right, true);
}

#[test]
fn test_migrate_uwhscores() {
let mut old: Table = Default::default();
old.insert(
"url".to_string(),
toml::Value::String("https://localhost/api/v1/".to_string()),
);
old.insert(
"email".to_string(),
toml::Value::String("test@test.com".to_string()),
);
old.insert(
"password".to_string(),
toml::Value::String("password".to_string()),
);
let u = UwhScores::migrate(&old);
assert_eq!(u.url, "https://localhost/api/v1/");
assert_eq!(u.email, "test@test.com");
assert_eq!(u.password, "password");
}

#[test]
fn test_migrate_uwhportal() {
let mut old: Table = Default::default();
old.insert(
"url".to_string(),
toml::Value::String("https://localhost/api/v1/".to_string()),
);
old.insert(
"token".to_string(),
toml::Value::String("token".to_string()),
);
let u = UwhPortal::migrate(&old);
assert_eq!(u.url, "https://localhost/api/v1/");
assert_eq!(u.token, "token");
}

#[test]
fn test_migrate_config() {
let mut old: Table = Default::default();
old.insert("mode".to_string(), toml::Value::String("Rugby".to_string()));
old.insert("hide_time".to_string(), toml::Value::Boolean(true));
old.insert(
"collect_scorer_cap_num".to_string(),
toml::Value::Boolean(true),
);
let mut game: Table = Default::default();
game.insert("half_play_duration".to_string(), toml::Value::Integer(123));
old.insert("game".to_string(), toml::Value::Table(game));
let mut hardware: Table = Default::default();
hardware.insert("screen_x".to_string(), toml::Value::Integer(123));
hardware.insert("screen_y".to_string(), toml::Value::Integer(456));
hardware.insert("white_on_right".to_string(), toml::Value::Boolean(true));
old.insert("hardware".to_string(), toml::Value::Table(hardware));
let mut uwhscores: Table = Default::default();
uwhscores.insert(
"url".to_string(),
toml::Value::String("https://localhost/api/v1/".to_string()),
);
uwhscores.insert(
"email".to_string(),
toml::Value::String("testing@test.com".to_string()),
);
uwhscores.insert(
"password".to_string(),
toml::Value::String("password".to_string()),
);
uwhscores.insert(
"timezone".to_string(),
toml::Value::String("UTC".to_string()),
);
old.insert("uwhscores".to_string(), toml::Value::Table(uwhscores));
let mut uwhportal: Table = Default::default();
uwhportal.insert(
"url".to_string(),
toml::Value::String("https://localhost/api/v1/".to_string()),
);
uwhportal.insert(
"token".to_string(),
toml::Value::String("token".to_string()),
);
old.insert("uwhportal".to_string(), toml::Value::Table(uwhportal));
let mut sound: Table = Default::default();
sound.insert("sound_enabled".to_string(), toml::Value::Boolean(false));
sound.insert(
"whistle_vol".to_string(),
toml::Value::String("Max".to_string()),
);
old.insert("sound".to_string(), toml::Value::Table(sound));
let config = Config::migrate(&old);
assert_eq!(config.mode, Mode::Rugby);
assert_eq!(config.hide_time, true);
assert_eq!(config.collect_scorer_cap_num, true);
assert_eq!(config.game.half_play_duration, Duration::from_secs(123));
assert_eq!(config.hardware.screen_x, 123);
assert_eq!(config.hardware.screen_y, 456);
assert_eq!(config.hardware.white_on_right, true);
assert_eq!(config.uwhscores.url, "https://localhost/api/v1/");
assert_eq!(config.uwhscores.email, "testing@test.com");
assert_eq!(config.uwhscores.password, "password");
assert_eq!(config.uwhscores.timezone, UtcOffset::UTC);
assert_eq!(config.uwhportal.url, "https://localhost/api/v1/");
assert_eq!(config.uwhportal.token, "token");
assert_eq!(config.sound.sound_enabled, false);
assert_eq!(config.sound.whistle_vol, Volume::Max);
}
}
27 changes: 21 additions & 6 deletions refbox/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,16 +262,31 @@ fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
vec![]
};

info!(
"Reading config file from {:?}",
confy::get_configuration_file_path(APP_NAME, None).unwrap()
);
let config_path = confy::get_configuration_file_path(APP_NAME, None).unwrap();
info!("Reading config file from {config_path:?}",);

let mut config: Config = match confy::load(APP_NAME, None) {
Ok(c) => c,
Err(e) => {
warn!("Failed to read config file, overwriting with default. Error: {e}");
let config = Config::default();
warn!("Failed to use config file. Error: {e}");
let config = match std::fs::read_to_string(config_path) {
Ok(file) => {
warn!("Found old config file, attempting migration");
match toml::from_str(&file) {
Ok(old_config) => Config::migrate(&old_config),
Err(e) => {
warn!("Failed to parse old config file. Error: {e}");
warn!("Using default config");
Config::default()
}
}
}
Err(e) => {
warn!("Failed to read old config file. Error: {e}");
warn!("Using default config");
Config::default()
}
};
confy::store(APP_NAME, None, &config).unwrap();
config
}
Expand Down
Loading