Skip to content

Commit

Permalink
Lobby: store DE Connector socket addr (#628)
Browse files Browse the repository at this point in the history
  • Loading branch information
Indy2222 authored Jul 16, 2023
1 parent 5d5abb8 commit 6434bcd
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 32 deletions.
11 changes: 9 additions & 2 deletions crates/lobby/src/games/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ use crate::{
db_error,
};

// This should correspond to the longest valid socket address. IPv6 hast up to
// 39 characters + colon + 5 characters for port number.
const SERVER_LEN: usize = 45;

#[derive(Clone)]
pub(super) struct Games {
pool: &'static Pool<Sqlite>,
Expand All @@ -33,6 +37,7 @@ impl Games {
game_name_len = MAX_GAME_NAME_LEN,
map_name_len = MAX_MAP_NAME_LEN,
map_hash_len = MAP_HASH_LEN,
server_len = SERVER_LEN,
);

info!("Initializing games...");
Expand Down Expand Up @@ -66,16 +71,18 @@ impl Games {

/// This method creates a new game in the DB and places all users to it.
pub(super) async fn create(&self, game: Game) -> Result<(), CreationError> {
let game_config = game.config();
let game_setup = game.setup();
let game_config = game_setup.config();

let mut transaction = self.pool.begin().await.map_err(CreationError::Database)?;

let result =
query("INSERT INTO games (name, max_players, map_hash, map_name) VALUES(?, ?, ?, ?);")
query("INSERT INTO games (name, max_players, map_hash, map_name, server) VALUES(?, ?, ?, ?, ?);")
.bind(game_config.name())
.bind(game_config.max_players())
.bind(game_config.map().hash())
.bind(game_config.map().name())
.bind(game_setup.server().to_string())
.execute(&mut transaction)
.await;
db_error!(
Expand Down
12 changes: 6 additions & 6 deletions crates/lobby/src/games/endpoints.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use actix_web::{get, post, put, web, HttpResponse, Responder};
use de_lobby_model::{Game, GameConfig, Validatable};
use de_lobby_model::{Game, GameSetup, Validatable};
use log::{error, warn};

use super::db::{AdditionError, CreationError, Games, RemovalError};
Expand All @@ -20,15 +20,15 @@ pub(super) fn configure(cfg: &mut web::ServiceConfig) {
async fn create(
claims: web::ReqData<Claims>,
games: web::Data<Games>,
game_config: web::Json<GameConfig>,
game_setup: web::Json<GameSetup>,
) -> impl Responder {
let game_config = game_config.into_inner();
if let Err(error) = game_config.validate() {
warn!("Invalid game configuration: {:?}", error);
let game_setup = game_setup.into_inner();
if let Err(error) = game_setup.validate() {
warn!("Invalid game setup: {:?}", error);
return HttpResponse::BadRequest().json(format!("{error}"));
}

let game = Game::new(game_config, claims.username().to_owned());
let game = Game::from_author(game_setup, claims.username().to_owned());
match games.create(game).await {
Ok(_) => HttpResponse::Ok().json(()),
Err(CreationError::NameTaken) => {
Expand Down
3 changes: 2 additions & 1 deletion crates/lobby/src/games/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ CREATE TABLE IF NOT EXISTS games (
name CHARACTER({game_name_len}) NOT NULL PRIMARY KEY,
max_players TINYINT NOT NULL,
map_hash CHARACTER({map_hash_len}) NOT NULL,
map_name CHARACTER({map_name_len}) NOT NULL
map_name CHARACTER({map_name_len}) NOT NULL,
server CHARACTER({server_len}) NOT NULL
);

CREATE TABLE IF NOT EXISTS players (
Expand Down
21 changes: 12 additions & 9 deletions crates/lobby_client/src/endpoints.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::borrow::Cow;

use de_lobby_model::{GameConfig, GameListing, Token, UserWithPassword, UsernameAndPassword};
use de_lobby_model::{GameListing, GameSetup, Token, UserWithPassword, UsernameAndPassword};
use reqwest::{header::HeaderValue, Method, Request};
use serde::Serialize;
use url::Url;
Expand Down Expand Up @@ -55,11 +55,11 @@ impl LobbyRequestCreator for SignInRequest {
}
}

pub struct CreateGameRequest(GameConfig);
pub struct CreateGameRequest(GameSetup);

impl CreateGameRequest {
pub fn new(config: GameConfig) -> Self {
Self(config)
pub fn new(setup: GameSetup) -> Self {
Self(setup)
}
}

Expand Down Expand Up @@ -158,7 +158,7 @@ fn encode(parts: &[&str]) -> Cow<'static, str> {

#[cfg(test)]
mod tests {
use de_lobby_model::{GameMap, User};
use de_lobby_model::{GameConfig, GameMap, User};

use super::*;

Expand Down Expand Up @@ -204,14 +204,16 @@ mod tests {

#[test]
fn test_create() {
let request = CreateGameRequest::new(GameConfig::new(
let config = GameConfig::new(
"Druhá Hra".to_owned(),
2,
GameMap::new(
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef".to_owned(),
"custom".to_owned(),
),
));
);
let request =
CreateGameRequest::new(GameSetup::new("127.0.0.1:8082".parse().unwrap(), config));
assert_eq!(request.path().as_ref(), "/a/games");

let request = request.create(Url::parse("http://example.com/a/games").unwrap());
Expand All @@ -220,9 +222,10 @@ mod tests {

let body = String::from_utf8(request.body().unwrap().as_bytes().unwrap().to_vec()).unwrap();
let expected_body = concat!(
r#"{"name":"Druhá Hra","maxPlayers":2,"map":{"hash":"#,
r#"{"server":"127.0.0.1:8082","config":{"name":"Druhá Hra","maxPlayers":2,"#,
r#""map":{"hash":"#,
r#""0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef","#,
r#""name":"custom"}}"#
r#""name":"custom"}}}"#
);

assert_eq!(body, expected_body);
Expand Down
46 changes: 38 additions & 8 deletions crates/lobby_model/src/games.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::net::SocketAddr;

use serde::{Deserialize, Serialize};

use crate::{ensure, validation};
Expand All @@ -10,21 +12,22 @@ const MAX_PLAYERS: u8 = 4;
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Game {
config: GameConfig,
setup: GameSetup,
players: Vec<String>,
}

impl Game {
/// Creates a new game with the author being the only player.
pub fn new(config: GameConfig, author: String) -> Self {
Self {
config,
players: vec![author],
}
pub fn from_author(setup: GameSetup, author: String) -> Self {
Self::new(setup, vec![author])
}

pub fn config(&self) -> &GameConfig {
&self.config
pub fn new(setup: GameSetup, players: Vec<String>) -> Self {
Self { setup, players }
}

pub fn setup(&self) -> &GameSetup {
&self.setup
}

pub fn players(&self) -> &[String] {
Expand Down Expand Up @@ -74,6 +77,33 @@ impl GamePartial {
}
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GameSetup {
server: SocketAddr,
config: GameConfig,
}

impl GameSetup {
pub fn new(server: SocketAddr, config: GameConfig) -> Self {
Self { server, config }
}

pub fn server(&self) -> SocketAddr {
self.server
}

pub fn config(&self) -> &GameConfig {
&self.config
}
}

impl validation::Validatable for GameSetup {
fn validate(&self) -> validation::Result {
self.config.validate()
}
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GameConfig {
Expand Down
4 changes: 2 additions & 2 deletions crates/lobby_model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ pub use auth::{
MIN_PASSWORD_LEN,
};
pub use games::{
Game, GameConfig, GameListing, GameMap, GamePartial, MAP_HASH_LEN, MAX_GAME_NAME_LEN,
MAX_MAP_NAME_LEN,
Game, GameConfig, GameListing, GameMap, GamePartial, GameSetup, MAP_HASH_LEN,
MAX_GAME_NAME_LEN, MAX_MAP_NAME_LEN,
};
pub use validation::Validatable;

Expand Down
10 changes: 7 additions & 3 deletions crates/menu/src/create.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::net::SocketAddr;

use bevy::prelude::*;
use de_gui::{
ButtonCommands, ButtonOps, GuiCommands, LabelCommands, OuterStyle, TextBoxCommands,
TextBoxQuery, ToastEvent,
};
use de_lobby_client::CreateGameRequest;
use de_lobby_model::{GameConfig, GameMap, Validatable};
use de_lobby_model::{GameConfig, GameMap, GameSetup, Validatable};
use de_map::hash::MapHash;

use crate::{
Expand Down Expand Up @@ -255,13 +257,15 @@ fn create_game_system(
}
};

let game_server: SocketAddr = "127.0.0.1:8082".parse().unwrap();
let game_config = GameConfig::new(name, max_players, selected_map.0.clone());
if let Err(error) = game_config.validate() {
let game_setup = GameSetup::new(game_server, game_config);
if let Err(error) = game_setup.validate() {
toasts.send(ToastEvent::new(format!("{error}")));
return;
}

sender.send(CreateGameRequest::new(game_config));
sender.send(CreateGameRequest::new(game_setup));
}

fn response_system(
Expand Down
12 changes: 11 additions & 1 deletion docs/src/multiplayer/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ paths:
content:
application/json:
schema:
$ref: "#/components/schemas/game-config"
$ref: "#/components/schemas/game-setup"
responses:
"200":
description: The game was successfully crated and the user joined it.
Expand Down Expand Up @@ -189,6 +189,16 @@ components:
A unique user name. It is a non-empty Unicode string with maximum
length of 32 bytes when encoded in UTF-8. It does not start or end
with whitespace.
game-setup:
type: object
properties:
server:
type: string
description: >-
An IPv4 or IPv6 socket address. For example 127.0.0.1:8082.
config:
$ref: "#/components/schemas/game-config"

game-config:
type: object
properties:
Expand Down

0 comments on commit 6434bcd

Please sign in to comment.