From 5c99bd761d409554cf8201d5d45ac7fbe185bd1f Mon Sep 17 00:00:00 2001 From: Thilo Behnke Date: Thu, 23 Jun 2022 20:23:32 +0200 Subject: [PATCH] define uuid for players --- client/svelte-client/src/App.svelte | 1 - client/svelte-client/src/api/session.ts | 13 ++++------- .../src/components/ModeSelect.svelte | 2 +- .../svelte-client/src/store/model/session.ts | 8 +++++++ client/svelte-client/src/store/session.ts | 17 +++++++------- server/Cargo.toml | 1 + server/src/actor.rs | 13 +++++++++++ server/src/http.rs | 23 +++++++++++++++---- server/src/request_handler.rs | 8 ++----- 9 files changed, 57 insertions(+), 29 deletions(-) diff --git a/client/svelte-client/src/App.svelte b/client/svelte-client/src/App.svelte index d664c0e..2ea66f1 100644 --- a/client/svelte-client/src/App.svelte +++ b/client/svelte-client/src/App.svelte @@ -9,7 +9,6 @@ import SessionWrapper from "./components/SessionWrapper.svelte"; import api from "./api/session"; import Error from "./components/Error.svelte"; - import session from "./api/session"; let error: string = null; let errorAt: number = null; diff --git a/client/svelte-client/src/api/session.ts b/client/svelte-client/src/api/session.ts index 081add9..d6a74c8 100644 --- a/client/svelte-client/src/api/session.ts +++ b/client/svelte-client/src/api/session.ts @@ -66,17 +66,12 @@ async function sessionResponseHandler(response: Response): Promise { console.debug(`session action result: ${JSON.stringify(data)}`) return data; - }).then((event: NetworkSessionEventPayload) => event.session); + }).then((event: NetworkSessionEventPayload) => ({you: event.actor, ...event.session})); } -async function createEventWebsocket(session: Session): Promise { - return new Promise((res, rej) => { - if (session.type === SessionType.LOCAL) { - return rej("Websocket not allowed for local session!"); - } - const url = `/pong/ws?session_id=${session.session_id}&connection_type=${session.type.toLowerCase()}`; - return createWebsocket(url); - }) +async function createEventWebsocket(session: NetworkSession): Promise { + const url = `/pong/ws?session_id=${session.session_id}&player_id=${session.you.id}&connection_type=${session.type.toLowerCase()}`; + return createWebsocket(url); } async function createWebsocket(path: string): Promise { diff --git a/client/svelte-client/src/components/ModeSelect.svelte b/client/svelte-client/src/components/ModeSelect.svelte index b733709..de7801d 100644 --- a/client/svelte-client/src/components/ModeSelect.svelte +++ b/client/svelte-client/src/components/ModeSelect.svelte @@ -16,7 +16,7 @@ if (!window.location.search.startsWith("?")) { return; } - const params = window.location.search.slice(1).split("?").map(p => p.split('=')).reduce((acc, [key, val]) => ({...acc, [key]: val}), {}) as any; + const params = window.location.search.slice(1).split("&").map(p => p.split('=')).reduce((acc, [key, val]) => ({...acc, [key]: val}), {}) as any; console.log(params) if (!params.session_id) { return; diff --git a/client/svelte-client/src/store/model/session.ts b/client/svelte-client/src/store/model/session.ts index 1fdcbf8..200a3fb 100644 --- a/client/svelte-client/src/store/model/session.ts +++ b/client/svelte-client/src/store/model/session.ts @@ -29,3 +29,11 @@ export type NetworkSession = { you: Player } export type Session = LocalSession | NetworkSession; + +export function isNetworkSession(session: Session): session is NetworkSession { + return !isLocalSession(session) +} + +export function isLocalSession(session: Session): session is LocalSession { + return session.type === SessionType.LOCAL +} diff --git a/client/svelte-client/src/store/session.ts b/client/svelte-client/src/store/session.ts index eab7176..d3bd803 100644 --- a/client/svelte-client/src/store/session.ts +++ b/client/svelte-client/src/store/session.ts @@ -2,8 +2,8 @@ import {derived, get, readable, Readable, writable} from "svelte/store"; import {keysPressed} from "./io"; import {onDestroy} from "svelte"; import api from "../api/session"; -import type {Session} from "./model/session"; -import {SessionType} from "./model/session"; +import type {NetworkSession, Session} from "./model/session"; +import {isLocalSession, SessionType} from "./model/session"; export type Input = { input: 'UP' | 'DOWN', @@ -43,7 +43,7 @@ const player2KeyboardInputs = derived( } ) -const sessionEvents = (session: Session) => readable([], function(set) { +const networkSessionEvents = (session: Session) => readable([], function(set) { const websocket = writable(null); api.createEventWebsocket(session).then(ws => { websocket.set(ws); @@ -70,12 +70,12 @@ const sessionEvents = (session: Session) => readable([], function(set) { } }) -const inputEvents = (session: Session): Readable => derived(sessionEvents(session), $sessionEvents => $sessionEvents.filter(({input}) => input === 'topic')); +const networkInputEvents = (session: NetworkSession): Readable => derived(networkSessionEvents(session), $sessionEvents => $sessionEvents.filter(({input}) => input === 'topic')); export const sessionInputs = (session: Session) => readable([], function(setInputs) { let player1Inputs = writable([]); let player2Inputs = writable([]); - if (session.type === SessionType.LOCAL) { + if (isLocalSession(session)) { player1KeyboardInputs.subscribe(inputs => { player1Inputs.set(inputs) setInputs([...get(player1Inputs), ...get(player2Inputs)]) @@ -87,12 +87,13 @@ export const sessionInputs = (session: Session) => readable([], function(setInpu return () => { } } + if (session.type === SessionType.HOST) { player1KeyboardInputs.subscribe(inputs => { player1Inputs.set(inputs) setInputs([...get(player1Inputs), ...get(player2Inputs)]) }) - inputEvents(session).subscribe(inputs => { + networkInputEvents(session).subscribe(inputs => { player2Inputs.set(inputs) setInputs([...get(player1Inputs), ...get(player2Inputs)]) }) @@ -100,7 +101,7 @@ export const sessionInputs = (session: Session) => readable([], function(setInpu } } if (session.type === SessionType.PEER) { - inputEvents(session).subscribe(inputs => { + networkInputEvents(session).subscribe(inputs => { player1Inputs.set(inputs) setInputs([...get(player1Inputs), ...get(player2Inputs)]) }) @@ -112,7 +113,7 @@ export const sessionInputs = (session: Session) => readable([], function(setInpu } } if (session.type === SessionType.OBSERVER) { - const events = inputEvents(session); + const events = networkInputEvents(session); events.subscribe(inputs => { player1Inputs.set(inputs) setInputs([...get(player1Inputs), ...get(player2Inputs)]) diff --git a/server/Cargo.toml b/server/Cargo.toml index 4fcc803..ed097a4 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -17,6 +17,7 @@ pong = { path = "../pong", version = "0.1.0" } hyper-tungstenite = "0.8.0" futures = { version = "0.3.12" } async-trait = "0.1.56" +uuid = { version = "1.1.2", features = ["v4"] } [dev-dependencies] rstest = "0.12.0" diff --git a/server/src/actor.rs b/server/src/actor.rs index 80d3bac..710325b 100644 --- a/server/src/actor.rs +++ b/server/src/actor.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use uuid::Uuid; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(tag = "actor_type")] @@ -19,6 +20,18 @@ impl Actor { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Player { pub id: String, + pub ip: String, + pub nr: u8 +} + +impl Player { + pub fn new(nr: u8, ip: String) -> Player { + Player { + ip, + id: Uuid::new_v4().to_string(), + nr + } + } } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] diff --git a/server/src/http.rs b/server/src/http.rs index de344dc..f526b3b 100644 --- a/server/src/http.rs +++ b/server/src/http.rs @@ -4,6 +4,7 @@ use std::str::FromStr; use std::sync::Arc; use futures::{stream::StreamExt}; +use futures::future::err; use hyper::{Body, Request, Response, Server, StatusCode}; use hyper::server::conn::AddrStream; use hyper::service::{make_service_fn, service_fn}; @@ -82,6 +83,13 @@ async fn handle_potential_ws_upgrade(session_manager: Arc> StatusCode::BAD_REQUEST, ); } + if !params.contains_key("player_id") { + eprintln!("Missing player id request param for websocket connection, don't upgrade connection to ws."); + return build_error_res( + "Missing request param: player_id", + StatusCode::BAD_REQUEST, + ); + } if !params.contains_key("connection_type") { eprintln!("Missing connection type request param for websocket connection, don't upgrade connection to ws."); let res = build_error_res( @@ -90,11 +98,12 @@ async fn handle_potential_ws_upgrade(session_manager: Arc> ); return res; } - let session_id = params.get("session_id").unwrap(); - let request_player_id = addr.ip().to_string(); - let session = session_manager.lock().await.get_session(session_id); + let request_session_id = *params.get("session_id").unwrap(); + let request_player_id = *params.get("player_id").unwrap(); + let request_player_ip = addr.ip().to_string(); + let session = session_manager.lock().await.get_session(request_session_id); if let None = session { - let error = format!("Session does not exist: {}", session_id); + let error = format!("Session does not exist: {}", request_session_id); eprintln!("{}", error); return build_error_res(error.as_str(), StatusCode::NOT_FOUND); } @@ -105,6 +114,12 @@ async fn handle_potential_ws_upgrade(session_manager: Arc> eprintln!("{}", error); return build_error_res(error.as_str(), StatusCode::FORBIDDEN); } + let matching_player = matching_player.unwrap(); + if matching_player.ip != request_player_ip { + let error = format!("Player with wrong ip tried to join session: {} (expected) vs {} (actual)", matching_player.ip, request_player_ip); + eprintln!("{}", error); + return build_error_res(error.as_str(), StatusCode::FORBIDDEN); + } let connection_type_raw = params.get("connection_type").unwrap(); let connection_type = WebSocketConnectionType::from_str(connection_type_raw); diff --git a/server/src/request_handler.rs b/server/src/request_handler.rs index 36e7092..9cebd9e 100644 --- a/server/src/request_handler.rs +++ b/server/src/request_handler.rs @@ -71,9 +71,7 @@ async fn handle_session_create( ) -> Result, Infallible> { println!("Called to create new session: {:?}", req); let mut locked = session_manager.lock().await; - let player = Player { - id: addr.ip().to_string(), - }; + let player = Player::new(1, addr.ip().to_string()); let session_create_res = locked.create_session(player.clone()).await; if let Err(e) = session_create_res { return Ok(Response::builder() @@ -99,9 +97,7 @@ async fn handle_session_join( println!("Received request to join session: {:?}", req); let mut locked = session_manager.lock().await; let body = read_json_body::(&mut req).await; - let player = Player { - id: addr.ip().to_string() - }; + let player = Player::new(2, addr.ip().to_string()); let session_join_res = locked.join_session(body.session_id, player.clone()).await; if let Err(e) = session_join_res { eprintln!("Failed to join session: {:?}", e);