Skip to content

Commit

Permalink
feat: socket start route, fix errors
Browse files Browse the repository at this point in the history
  • Loading branch information
DonWick32 committed Feb 7, 2024
1 parent 82d21ec commit cead954
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 64 deletions.
40 changes: 22 additions & 18 deletions src/api/attack/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ async fn init_attack(
.get()
.map_err(|err| error::handle_error(err.into()))?;

if let Ok(Some(_)) = util::get_from_redis(attacker_id, redis_conn) {
//Check if attacker is already in a game
if let Ok(Some(_)) = util::get_game_id_from_redis(attacker_id, redis_conn) {
return Err(ErrorBadRequest("Only one attack is allowed at a time"));
}

//Generate random opponent id
let random_opponent_id = web::block(move || {
Ok(util::get_random_opponent_id(attacker_id, &mut conn)?) as anyhow::Result<Option<i32>>
})
Expand Down Expand Up @@ -84,6 +86,7 @@ async fn init_attack(

let mut conn = pool.get().map_err(|err| error::handle_error(err.into()))?;

//Fetch base details and shortest paths data
let opponent_base = web::block(move || {
Ok(util::get_opponent_base_details(opponent_id, &mut conn)?)
as anyhow::Result<DefenseResponse>
Expand Down Expand Up @@ -115,6 +118,7 @@ async fn init_attack(
.await?
.map_err(|err| error::handle_error(err.into()))?;

//Generate attack token to validate the /attack/start
let attack_token = util::encode_attack_token(attacker_id, opponent_id).unwrap();
let response: AttackResponse = AttackResponse {
base: opponent_base,
Expand All @@ -131,14 +135,11 @@ async fn socket_handler(
req: HttpRequest,
stream: web::Payload,
) -> Result<HttpResponse, Error> {
//From the req.query_string() get the user_token and attack_token
//query_string() will be like this: user_token=123&attack_token=456

let user_token = req.query_string().split("&").collect::<Vec<&str>>()[0]
.split("=")
let user_token = req.query_string().split('&').collect::<Vec<&str>>()[0]
.split('=')
.collect::<Vec<&str>>()[1];
let attack_token = req.query_string().split("&").collect::<Vec<&str>>()[1]
.split("=")
let attack_token = req.query_string().split('&').collect::<Vec<&str>>()[1]
.split('=')
.collect::<Vec<&str>>()[1];

let attacker_id = util::decode_user_token(user_token).unwrap();
Expand All @@ -150,6 +151,18 @@ async fn socket_handler(

let defender_id = attack_token_data.defender_id;

if attacker_id == defender_id {
return Err(ErrorBadRequest("Can't attack yourself"));
}

let redis_conn = redis_pool
.get()
.map_err(|err| error::handle_error(err.into()))?;

if let Ok(Some(_)) = util::get_game_id_from_redis(attacker_id, redis_conn) {
return Err(ErrorBadRequest("Only one attack is allowed at a time"));
}

//Fetch map_id of the defender
let mut conn = pool.get().map_err(|err| error::handle_error(err.into()))?;

Expand Down Expand Up @@ -190,19 +203,10 @@ async fn socket_handler(
let redis_conn = redis_pool
.get()
.map_err(|err| error::handle_error(err.into()))?;
if let Err(_) = util::add_to_redis(attacker_id, game_id, redis_conn) {
if util::add_game_id_to_redis(attacker_id, defender_id, game_id, redis_conn).is_err() {
return Err(ErrorBadRequest("Internal Server Error"));
}

// let redis_conn = redis_pool
// .get()
// .map_err(|err| error::handle_error(err.into()))?;
// if let Ok(Some(game_id)) = util::get_from_redis(user_id, redis_conn) {
// // Maybe can start the websocket here
// } else {
// return Err(ErrorBadRequest("No game found for the user"));
// }

let mut conn = pool.get().map_err(|err| error::handle_error(err.into()))?;
let defenders = web::block(move || {
Ok(util::get_defenders(&mut conn, map_id)?) as anyhow::Result<Vec<DefenderDetails>>
Expand Down
70 changes: 60 additions & 10 deletions src/api/attack/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::simulation::blocks::{Coords, SourceDest};
use crate::simulation::{RenderAttacker, RenderMine};
use crate::simulation::{RenderDefender, Simulator};
use crate::util::function;
use crate::validator::util::{self, BuildingDetails, Coordinates, DefenderDetails, MineDetails};
use crate::validator::util::{BuildingDetails, Coordinates, DefenderDetails, MineDetails};
use anyhow::{Context, Result};
use chrono::{Duration, Local, Utc};
use diesel::dsl::exists;
Expand All @@ -28,7 +28,6 @@ use diesel::select;
use diesel::PgConnection;
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
use rand::seq::IteratorRandom;
use redis::geo::Coord;
use redis::Commands;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
Expand Down Expand Up @@ -760,16 +759,37 @@ pub fn get_opponent_base_details(
Ok(response)
}

pub fn add_to_redis(user_id: i32, game_id: i32, mut redis_conn: RedisConn) -> Result<()> {
pub fn add_game_id_to_redis(
attacker_id: i32,
defender_id: i32,
game_id: i32,
mut redis_conn: RedisConn,
) -> Result<()> {
redis_conn
.set_ex(
format!("Game:{}", attacker_id),
game_id,
(GAME_ID_EXPIRATION_TIME_IN_MINUTES * 60)
.try_into()
.unwrap(),
)
.map_err(|err| anyhow::anyhow!("Failed to set key: {}", err))?;

redis_conn
.set(user_id, game_id)
.set_ex(
format!("Game:{}", defender_id),
game_id,
(GAME_ID_EXPIRATION_TIME_IN_MINUTES * 60)
.try_into()
.unwrap(),
)
.map_err(|err| anyhow::anyhow!("Failed to set key: {}", err))?;
Ok(())
}

pub fn get_from_redis(user_id: i32, mut redis_conn: RedisConn) -> Result<Option<i32>> {
pub fn get_game_id_from_redis(user_id: i32, mut redis_conn: RedisConn) -> Result<Option<i32>> {
let game_id: Option<i32> = redis_conn
.get(user_id)
.get(format!("Game:{}", user_id))
.map_err(|err| anyhow::anyhow!("Failed to get key: {}", err))?;
Ok(game_id)
}
Expand Down Expand Up @@ -807,7 +827,7 @@ pub fn encode_attack_token(attacker_id: i32, defender_id: i32) -> Result<String>
pub fn decode_user_token(token: &str) -> Result<i32> {
let jwt_secret = env::var("COOKIE_KEY").expect("COOKIE_KEY must be set!");
let token_data = decode::<TokenClaims>(
&token,
token,
&DecodingKey::from_secret(jwt_secret.as_str().as_ref()),
&Validation::new(Algorithm::HS256),
)
Expand All @@ -819,7 +839,7 @@ pub fn decode_user_token(token: &str) -> Result<i32> {
pub fn decode_attack_token(token: &str) -> Result<AttackToken> {
let jwt_secret = env::var("COOKIE_KEY").expect("COOKIE_KEY must be set!");
let token_data = decode::<AttackToken>(
&token,
token,
&DecodingKey::from_secret(jwt_secret.as_str().as_ref()),
&Validation::new(Algorithm::HS256),
)
Expand Down Expand Up @@ -873,7 +893,7 @@ pub fn get_defenders(conn: &mut PgConnection, map_id: i32) -> Result<Vec<Defende

for (defender_id, (map_space, (_, _, defender_type))) in result.iter().enumerate() {
let (hut_x, hut_y) = (map_space.x_coordinate, map_space.y_coordinate);
let path = vec![(hut_x, hut_y)];
// let path = vec![(hut_x, hut_y)];
defenders.push(DefenderDetails {
id: defender_id as i32 + 1,
radius: defender_type.radius,
Expand Down Expand Up @@ -921,10 +941,40 @@ pub fn get_buildings(conn: &mut PgConnection, map_id: i32) -> Result<Vec<Buildin
width: building_type.width,
})
.collect();
update_buidling_artifacts(conn, map_id, buildings)
}

pub fn update_buidling_artifacts(
conn: &mut PgConnection,
map_id: i32,
mut buildings: Vec<BuildingDetails>,
) -> Result<Vec<BuildingDetails>> {
use crate::schema::{artifact, map_spaces};

let result: Vec<(MapSpaces, Artifact)> = map_spaces::table
.inner_join(artifact::table)
.filter(map_spaces::map_id.eq(map_id))
.load::<(MapSpaces, Artifact)>(conn)
.map_err(|err| DieselError {
table: "map_spaces",
function: function!(),
error: err,
})?;

// From the above table, create a hashmap, key being map_space_id and value being the artifact count
let mut artifact_count: HashMap<i32, i64> = HashMap::new();

for (map_space, artifact) in result.iter() {
artifact_count.insert(map_space.id, artifact.count.into());
}

// Update the buildings with the artifact count
for building in buildings.iter_mut() {
building.artifacts_obtained = *artifact_count.get(&building.id).unwrap_or(&0) as i32;
}

Ok(buildings)
}

// pub fn get_super_buildings(conn: &mut PgConnection, map_id: i32) -> Result<Vec<BuildingDetails>> {
// use crate::schema::{block_type, building_type, map_spaces, artifact};

Expand Down
1 change: 1 addition & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ pub const WIN_THRESHOLD: i32 = 50;
pub const SCALE_FACTOR: f32 = 20.0;
pub const HIGHEST_TROPHY: f32 = 2_000.0;
pub const BONUS_SCALE: i32 = 2;
pub const GAME_ID_EXPIRATION_TIME_IN_MINUTES: i32 = 10;
26 changes: 16 additions & 10 deletions src/validator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,22 @@ pub fn game_handler(_game_id: i32, socket_request: &SocketRequest) -> Result<Soc
// iterate through input data and call appropriate instance functions
// form response and send

if socket_request.action_type == ActionType::PlaceAttacker {
// place_attacker
} else if socket_request.action_type == ActionType::MoveAttacker {
// move_attacker
} else if socket_request.action_type == ActionType::PlaceBombs {
// place_bombs
} else if socket_request.action_type == ActionType::Idle {
// idle (waiting for user to choose next attacker)
} else if socket_request.action_type == ActionType::Terminate {
// terminate
match socket_request.action_type {
ActionType::PlaceAttacker => {
// place_attacker
}
ActionType::MoveAttacker => {
// move_attacker
}
ActionType::PlaceBombs => {
// place_bombs
}
ActionType::Idle => {
// idle (waiting for user to choose next attacker)
}
ActionType::Terminate => {
// terminate
}
}

let socket_response = SocketResponse {
Expand Down
Loading

0 comments on commit cead954

Please sign in to comment.