bitbroker 0.1.0

A language agnostic message broker designed for real-time communication.
Documentation
use std::collections::HashMap;

use tracing::info;

use crate::{broker::ConnectionListener, BitBrokerMessage, Connection, Error, Result};

pub struct BrokerSetup {
    pub players: HashMap<u8, Connection>,
    num_players: usize,
    pub game: Option<Connection>,
}

impl BrokerSetup {
    pub fn new(num_players: usize) -> Self {
        Self {
            players: HashMap::new(),
            num_players,
            game: None,
        }
    }

    pub async fn run(mut self, host: &str, port: usize) -> Result<Self> {
        let listener = ConnectionListener::new(host, port).await?;
        info!("Tcp listener setup");

        while self.expecting_connection() {
            info!("{}", self.expecting_msg());
            info!("Waiting for connection...");
            let mut connection = listener.accept().await?;
            let message: BitBrokerMessage = connection.read_message().await?;
            match message.codes() {
                (0x00, 0x01) => self.handle_game_connection(connection)?,
                (0x00, 0x02) => self.handle_player_connection(connection)?,
                _ => return Err(Error::from(message)),
            }
        }

        info!("All players and game connected");
        Ok(self)
    }

    fn handle_player_connection(&mut self, connection: Connection) -> Result<()> {
        info!("Handling new player connection");
        if self.expecting_player() {
            let player_id = self.players.len() as u8;
            self.players.insert(player_id, connection);
            Ok(())
        } else {
            Err(Error::BrokerError("Too many players tried to connect"))
        }
    }

    fn handle_game_connection(&mut self, connection: Connection) -> Result<()> {
        info!("Handling new game connection");
        if self.expecting_game() {
            self.game = Some(connection);
            Ok(())
        } else {
            Err(Error::BrokerError("Multiple games tried to connect"))
        }
    }

    fn expecting_msg(&self) -> String {
        let player_part = format!("{} player(s)", self.num_players - self.players.len());
        if self.expecting_game() {
            format!("Expecting {player_part} and a game")
        } else {
            format!("Expecting {player_part}")
        }
    }

    fn expecting_game(&self) -> bool {
        self.game.is_none()
    }

    fn expecting_player(&self) -> bool {
        self.players.len() < self.num_players
    }

    fn expecting_connection(&self) -> bool {
        self.expecting_game() || self.expecting_player()
    }
}