Compare commits

...

2 Commits

3 changed files with 119 additions and 66 deletions

View File

@@ -3,5 +3,7 @@ CREATE TABLE IF NOT EXISTS user_skins (
user_id uuid REFERENCES users(id) NOT NULL, user_id uuid REFERENCES users(id) NOT NULL,
skin_id uuid REFERENCES skins(id), skin_id uuid REFERENCES skins(id),
agent_id uuid REFERENCES agents(id), agent_id uuid REFERENCES agents(id),
float float DEFAULT 0 NOT NULL,
pattern integer DEFAULT 0 NOT NULL,
team integer NOT NULL -- 0 = CT, 1 = T, 2 = BOTH team integer NOT NULL -- 0 = CT, 1 = T, 2 = BOTH
); );

View File

@@ -17,7 +17,7 @@ use tower_sessions_sqlx_store::sqlx::PgPool as SessionPgPool;
mod error; mod error;
mod skins; mod skins;
mod users; mod users;
use skins::{gloves, knife, weapons}; use skins::{skin_info, weapons};
use users::{login, logout, me, reload, update}; use users::{login, logout, me, reload, update};
#[tokio::main] #[tokio::main]
@@ -39,8 +39,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
.route("/update", post(update)) .route("/update", post(update))
.route("/reload", get(reload)) .route("/reload", get(reload))
.route("/weapons", get(weapons)) .route("/weapons", get(weapons))
.route("/knife", get(knife)) .route("/skin", get(skin_info))
.route("/gloves", get(gloves))
.layer( .layer(
CorsLayer::new() CorsLayer::new()
.allow_origin("http://localhost:5173".parse::<HeaderValue>().unwrap()) .allow_origin("http://localhost:5173".parse::<HeaderValue>().unwrap())
@@ -50,10 +49,10 @@ async fn main() -> Result<(), Box<dyn Error>> {
) )
.layer(session) .layer(session)
.with_state(pool); .with_state(pool);
let listener = TcpListener::bind("0.0.0.0:8080").await?; let listener = TcpListener::bind(var("BIND_ADDRESS")?).await?;
Ok(serve(listener, app).await?) Ok(serve(listener, app).await?)
} }
async fn status() -> &'static str { async fn status() -> &'static str {
"api online" "API online"
} }

View File

@@ -1,11 +1,8 @@
use std::error::Error;
use axum::{ use axum::{
Json, Json,
extract::{Query, State}, extract::{Query, State},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value;
use sqlx::{PgPool, query, query_as, types::Uuid}; use sqlx::{PgPool, query, query_as, types::Uuid};
use tower_sessions::Session; use tower_sessions::Session;
@@ -22,11 +19,14 @@ pub struct Weapon {
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct WeaponInfo { pub struct SkinInfo {
id: Uuid, id: Uuid,
name: String, name: String,
display: String,
paint_index: i32, paint_index: i32,
color: String, color: String,
float: f64,
pattern: i32,
} }
#[axum::debug_handler] #[axum::debug_handler]
@@ -37,70 +37,122 @@ pub async fn weapons(State(pool): State<PgPool>) -> Result<Json<Vec<Weapon>>, Ap
Ok(Json(weapons)) Ok(Json(weapons))
} }
#[derive(Deserialize, Serialize, Copy, Clone, Debug)]
enum Teams {
CT,
T,
BOTH,
}
impl Teams {
fn as_i32(self) -> i32 {
match self {
Teams::CT => 0,
Teams::T => 1,
Teams::BOTH => 2,
}
}
}
#[derive(Deserialize, Serialize, Copy, Clone, Debug)]
enum Categories {
Knives,
Gloves,
Rifles,
SMGs,
Pistols,
Heavy,
Equipment,
}
impl Categories {
fn as_str(self) -> &'static str {
match self {
Categories::Knives => "Knives",
Categories::Gloves => "Gloves",
Categories::Rifles => "Rifles",
Categories::SMGs => "SMGs",
Categories::Pistols => "Pistols",
Categories::Heavy => "Heavy",
Categories::Equipment => "Equipment",
}
}
}
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct TeamQuery { pub struct SkinInfoQuery {
team: String, category: Option<Categories>,
team: Option<Teams>,
} }
pub async fn knife( pub async fn skin_info(
State(pool): State<PgPool>, State(pool): State<PgPool>,
session: Session, session: Session,
Query(team): Query<TeamQuery>, Query(info_query): Query<SkinInfoQuery>,
) -> Result<Json<WeaponInfo>, AppError> { ) -> Result<Json<Vec<SkinInfo>>, AppError> {
if let Some(uuid) = session.get::<Uuid>("uuid").await? { if let Some(uuid) = session.get::<Uuid>("uuid").await? {
let team = match team.team.as_str() { let mut skins = query!("SELECT sk.id, w.team, w.category FROM user_skins sk left join skins s on s.id = sk.skin_id left join weapons w on w.id = s.weapon LEFT JOIN users us ON us.id = sk.user_id WHERE us.id = $1", uuid).fetch_all(&pool).await?;
"CT" => 0, if let Some(team) = info_query.team {
"T" => 1, skins = skins
_ => 2, .into_iter()
}; .filter(|x| team.as_i32() == x.team || Teams::BOTH.as_i32() == x.team)
let knife = match query_as!(WeaponInfo, "SELECT us.id, wp.name, sk.paint_index, r.color FROM user_skins us LEFT JOIN skins sk ON sk.id = us.skin_id LEFT JOIN rarity r ON r.id = sk.rarity LEFT JOIN weapons wp ON wp.id = sk.weapon WHERE us.user_id = $1 AND us.team = $2 AND wp.category='Knives'", uuid, team).fetch_optional(&pool).await? { .collect();
Some(knife) => knife, }
None => { if let Some(category) = info_query.category {
let name = match team { skins = skins
0 => "weapon_knife", .into_iter()
_ => "weapon_knife_t" .filter(|x| category.as_str() == x.category)
}; .collect();
let info = query!("SELECT wp.name, r.color FROM weapons wp LEFT JOIN skins sk ON sk.weapon = wp.id LEFT JOIN rarity r ON r.id = sk.rarity WHERE wp.name = $1", name).fetch_one(&pool).await?; }
WeaponInfo { let mut skin_infos = Vec::new();
id: Uuid::nil(), let ids: Vec<Uuid> = skins.iter().map(|x| x.id).collect();
for id in ids {
let info = query!("SELECT w.name, w.display as wdisplay, s.display as sdisplay, s.paint_index, r.color, us.float, us.pattern FROM user_skins us JOIN skins s ON s.id = us.skin_id JOIN rarity r on r.id = s.rarity JOIN weapons w on w.id = s.weapon WHERE us.id = $1", id).fetch_one(&pool).await?;
let display = if info.sdisplay.is_empty() {
info.wdisplay
} else {
format!("{} | {}", info.wdisplay, info.sdisplay)
};
let skin_info = SkinInfo {
id,
display,
name: info.name, name: info.name,
paint_index: 0, paint_index: info.paint_index,
color: info.color color: info.color,
}} float: info.float,
}; pattern: info.pattern,
Ok(Json(knife)) };
} else { skin_infos.push(skin_info);
Err(AppError::Unauthorised) }
} if skin_infos.is_empty() {
} // fetch default skins
let mut infos = query!("SELECT w.name, w.display, w.team, w.category, r.color FROM skins s JOIN rarity r ON r.id = s.rarity JOIN weapons w ON w.id = s.weapon WHERE s.paint_index = 0").fetch_all(&pool).await?;
pub async fn gloves( if let Some(team) = info_query.team {
State(pool): State<PgPool>, infos = infos
session: Session, .into_iter()
Query(team): Query<TeamQuery>, .filter(|x| team.as_i32() == x.team)
) -> Result<Json<WeaponInfo>, AppError> { .collect();
if let Some(uuid) = session.get::<Uuid>("uuid").await? { }
let team = match team.team.as_str() { if let Some(category) = info_query.category {
"CT" => 0, infos = infos
"T" => 1, .into_iter()
_ => 2, .filter(|x| category.as_str() == x.category)
}; .collect();
let gloves = match query_as!(WeaponInfo, "SELECT us.id, wp.name, sk.paint_index, r.color FROM user_skins us LEFT JOIN skins sk ON sk.id = us.skin_id LEFT JOIN rarity r ON r.id = sk.rarity LEFT JOIN weapons wp ON wp.id = sk.weapon WHERE us.user_id = $1 AND us.team = $2 AND wp.category = 'Gloves'", uuid, team).fetch_optional(&pool).await? { }
Some(gloves) => gloves, skin_infos = infos
None => { .into_iter()
let name = match team { .map(|x| SkinInfo {
0 => "ct_gloves", id: Uuid::nil(),
_ => "t_gloves" name: x.name,
}; display: x.display,
let info = query!("SELECT wp.name, r.color FROM weapons wp LEFT JOIN skins sk ON sk.weapon = wp.id LEFT JOIN rarity r ON r.id = sk.rarity WHERE wp.name = $1", name).fetch_one(&pool).await?; color: x.color,
WeaponInfo { paint_index: 0,
id: Uuid::nil(), float: 0.0,
name: info.name, pattern: 0,
paint_index: 0, })
color: info.color .collect();
}} }
}; Ok(Json(skin_infos))
Ok(Json(gloves))
} else { } else {
Err(AppError::Unauthorised) Err(AppError::Unauthorised)
} }