gn-matchmaking-state-types 0.1.1

Component for shared state-management-types in the game-night backend
Documentation
use std::{collections::HashMap, time::SystemTime};

use gn_redisadapter_derive::{
    RedisIdentifiable, RedisInsertWriter, RedisOutputReader, RedisUpdater,
};
use serde::Deserialize;

#[cfg(feature = "redis")]
use gn_matchmaking_state::adapters::redis::RedisFilter;

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(RedisInsertWriter, RedisIdentifiable)]
#[name("game_servers")]
pub struct GameServer {
    pub region: String,
    pub game: String,
    pub mode: String,
    pub server_pub: String,
    pub server_priv: String,
    pub healthy: bool,
    pub min_players: u32,
    pub max_players: u32,
}

#[derive(Debug, Clone)]
#[derive(RedisOutputReader, RedisIdentifiable)]
#[name("game_servers")]
pub struct DBGameServer {
    #[cfg_attr(feature = "redis", uuid)]
    pub uuid: String,
    pub region: String,
    pub game: String,
    pub mode: String,
    pub server_pub: String,
    pub server_priv: String,
    pub healthy: bool,
    pub min_players: u32,
    pub max_players: u32,
}

impl PartialEq for DBGameServer {
    fn eq(&self, other: &Self) -> bool {
        self.uuid == other.uuid
    }
}

#[derive(Debug, Clone, Default)]
#[derive(RedisUpdater)]
#[name("game_servers")]
pub struct GameServerUpdater {
    pub game: Option<String>,
    pub mode: Option<String>,
    pub region: Option<String>,
    pub server_pub: Option<String>,
    pub server_priv: Option<String>,
    pub healthy: Option<bool>,
    pub min_players: Option<u32>,
    pub max_players: Option<u32>,
}

#[derive(Debug, Default)]
pub struct GameServerFilter {
    pub game: Option<String>,
}

#[cfg(feature = "redis")]
impl RedisFilter<DBGameServer> for GameServerFilter {
    fn is_ok(&self, check: &DBGameServer) -> bool {
        if self.game.is_none() {
            return true;
        }
        return self.game.clone().unwrap() == check.game;
    }
}

#[derive(Debug, Clone)]
#[derive(RedisInsertWriter, RedisIdentifiable)]
#[name("host_requests")]

pub struct HostRequest {
    pub player_id: String,
    pub mode: String,
    pub game: String,
    pub region: String,
    pub join_token: String,
    pub joined_players: Vec<String>,
    pub start_requested: bool,
    pub min_players: u32,
    pub max_players: u32,
    pub wait_start: SystemTime,
}

#[derive(Debug, Clone)]
#[derive(RedisOutputReader, RedisIdentifiable)]
#[name("host_requests")]
pub struct HostRequestDB {
    #[cfg_attr(feature = "redis", uuid)]
    pub uuid: String,
    pub player_id: String,
    pub mode: String,
    pub game: String,
    pub region: String,
    pub join_token: String,
    pub joined_players: Vec<String>,
    pub start_requested: bool,
    pub min_players: u32,
    pub max_players: u32,
    pub wait_start: SystemTime,
}

#[derive(Debug, Clone, Default)]
#[derive(RedisUpdater)]
#[name("host_requests")]
pub struct HostRequestUpdate {
    pub player_id: Option<String>,
    pub mode: Option<String>,
    pub game: Option<String>,
    pub region: Option<String>,
    pub join_token: Option<String>,
    pub joined_players: Option<Vec<String>>,
    pub start_requested: Option<bool>,
    pub min_players: Option<u32>,
    pub max_players: Option<u32>,
    pub wait_start: Option<SystemTime>,
}
#[derive(Debug, Clone)]
#[derive(RedisInsertWriter, RedisIdentifiable)]
#[name("searchers")]
pub struct Searcher {
    pub player_id: String,
    pub elo: u32,
    pub mode: String,
    pub ai: bool,
    pub game: String,
    pub region: String,
    pub min_players: u32,
    pub max_players: u32,
    pub wait_start: SystemTime,
}

#[derive(Debug, Clone)]
#[derive(RedisUpdater)]
#[name("searchers")]
pub struct SearcherUpdate {
    pub player_id: Option<String>,
    pub elo: Option<u32>,
    pub mode: Option<String>,
    pub ai: Option<bool>,
    pub game: Option<String>,
    pub region: Option<String>,
    pub wait_start: Option<SystemTime>,
}

#[derive(Debug, Clone)]
#[derive(RedisOutputReader, RedisIdentifiable)]
#[name("searchers")]
pub struct DBSearcher {
    #[cfg_attr(feature = "redis", uuid)]
    pub uuid: String,
    pub player_id: String,
    pub elo: u32,
    pub mode: String,
    pub ai: bool,
    pub game: String,
    pub region: String,
    pub min_players: u32,
    pub max_players: u32,
    pub wait_start: SystemTime,
}

#[derive(Debug, Default)]
pub struct SearcherFilter {
    pub game: Option<String>,
    pub mode: Option<String>,
}

#[cfg(feature = "redis")]
#[derive(Debug, Clone, RedisInsertWriter, RedisOutputReader, RedisIdentifiable)]
#[name("config")]
#[single_instance(true)]
pub struct SearcherMatchConfig {
    pub max_elo_diff: u32,
    pub wait_time_to_elo_factor: f32,
    pub wait_time_to_server_factor: f32,
}

#[derive(Debug, Clone)]
#[derive(RedisInsertWriter, RedisIdentifiable)]
#[name("active_matches")]
pub struct ActiveMatch {
    pub game: String,
    pub mode: String,
    pub ai: bool,
    pub server_pub: String,
    pub server_priv: String,
    pub region: String,
    pub read: String,
    pub player_write: HashMap<String, String>,
}

#[derive(Debug, Clone)]
#[derive(RedisOutputReader, RedisIdentifiable)]
#[name("active_matches")]
pub struct ActiveMatchDB {
    #[cfg_attr(feature = "redis", uuid)]
    pub uuid: String,
    pub game: String,
    pub mode: String,
    pub ai: bool,
    pub server_pub: String,
    pub server_priv: String,
    pub region: String,
    pub read: String,
    pub player_write: HashMap<String, String>,
}

#[cfg(test)]
mod tests {
    use std::error::Error;

    use gn_matchmaking_state::adapters::{Gettable, Insertable, Removable, Updateable};

    #[test]

    fn test_redis_adapter_insert_game_server() {
        use gn_matchmaking_state::adapters::redis::publisher::native::RedisInfoPublisher;
        use gn_matchmaking_state::adapters::redis::RedisAdapter;
        use gn_matchmaking_state::adapters::Insertable;
        use super::*;

        let adapter = RedisAdapter::connect("redis://0.0.0.0:6379").unwrap();
        let publisher = RedisInfoPublisher::new(adapter.client.get_connection().unwrap());
        let adapter = adapter.with_publisher(publisher);


        let game_server = GameServer {
            region: "eu".to_owned(),
            game: "Test Server".to_owned(),
            mode: "Test Mode".to_owned(),
            server_pub: "127.0.0.1:3456".to_owned(),
            server_priv: "127.0.0.1:3456".to_owned(),
            healthy: true,
            min_players: 2,
            max_players: 2,
        };
        adapter.insert(game_server).unwrap();
    }

    #[test]
    fn test_redis_adapter_all_game_server() {
        use gn_matchmaking_state::adapters::redis::publisher::native::RedisInfoPublisher;
        use gn_matchmaking_state::adapters::redis::{RedisAdapter};
        use super::*;

        let adapter = RedisAdapter::connect("redis://0.0.0.0:6379").unwrap();
        let publisher = RedisInfoPublisher::new(adapter.client.get_connection().unwrap());
        let adapter = adapter.with_publisher(publisher);



        let game_server = GameServer {
            region: "eu".to_owned(),
            game: "Test Server".to_owned(),
            mode: "Test Mode".to_owned(),
            server_pub: "127.0.0.1:3456".to_owned(),
            server_priv: "127.0.0.1:3456".to_owned(),
            healthy: true,
            min_players: 2,
            max_players: 2,
        };
        adapter.insert(game_server.clone()).unwrap();

        let found_server = adapter.all().unwrap().collect::<Vec<DBGameServer>>();

        for game in &found_server {
            println!("{:?}", game);
        }

        assert!(found_server.len() > 0);
        assert!(found_server.iter().any(|x| x.game == game_server.game));
    }

    #[test]
    fn test_redis_adapter_remove_game_server() {
        use gn_matchmaking_state::adapters::redis::publisher::native::RedisInfoPublisher;
        use gn_matchmaking_state::adapters::redis::{RedisAdapter};
        use super::*;

        let adapter = RedisAdapter::connect("redis://0.0.0.0:6379").unwrap();
        let publisher = RedisInfoPublisher::new(adapter.client.get_connection().unwrap());
        let adapter = adapter.with_publisher(publisher);

        let game_server = GameServer {
            region: "eu".to_owned(),
            game: "Test Server".to_owned(),
            mode: "Test Mode".to_owned(),
            server_pub: "127.0.0.1:3456".to_owned(),
            server_priv: "127.0.0.1:3456".to_owned(),
            healthy: true,
            min_players: 2,
            max_players: 2,
        };
        let uuid = adapter.insert(game_server.clone()).unwrap();

        adapter.remove(&uuid).unwrap();

        let game: Result<DBGameServer, Box<dyn Error>> = adapter.get(&uuid);
        assert!(game.is_err());
    }

    #[test]
    fn test_redis_adapter_update_game_server() {
        use gn_matchmaking_state::adapters::redis::publisher::native::RedisInfoPublisher;
        use gn_matchmaking_state::adapters::redis::{RedisAdapter};
        use super::*;



        let adapter = RedisAdapter::connect("redis://0.0.0.0:6379").unwrap();
        let publisher = RedisInfoPublisher::new(adapter.client.get_connection().unwrap());
        let adapter = adapter.with_publisher(publisher);


        let game_server = GameServer {
            region: "eu".to_owned(),
            game: "Test Server".to_owned(),
            mode: "Test Mode".to_owned(),
            server_pub: "127.0.0.1:3456".to_owned(),
            server_priv: "127.0.0.1:3456".to_owned(),
            healthy: true,
            min_players: 2,
            max_players: 2,
        };
        let uuid = adapter.insert(game_server.clone()).unwrap();

        let mut update = GameServerUpdater::default();
        update.game = Some("CSS Battle (Cum Sum Sus Battle)".to_owned());
        adapter.update(&uuid, update).unwrap();

        let result: DBGameServer = adapter.get(&uuid).unwrap();

        assert!(result.game == "CSS Battle (Cum Sum Sus Battle)");
    }
}