improvements

This commit is contained in:
sparshg
2024-09-23 22:34:35 +05:30
parent 44e72d77f2
commit 64f2c27bfc
6 changed files with 104 additions and 75 deletions

View File

@@ -12,15 +12,16 @@ export class State {
turn = $state(-1); // -1 not my turn, 0 might be, 1 is turn = $state(-1); // -1 not my turn, 0 might be, 1 is
socket: Socket; socket: Socket;
constructor(hostname: string) { constructor(hostname: string, newSession: boolean = true) {
let session = sessionStorage.getItem('session'); // let session = sessionStorage.getItem('session');
this.socket = io(`ws://${hostname}:3000/`, { this.socket = io(`ws://${hostname}:3000/`, {
transports: ['websocket'], transports: ['websocket'],
auth: { session } auth: { session: !newSession ? sessionStorage.getItem('session') : null }
}); });
this.socket.on('connect', () => { this.socket.on('connect', () => {
console.log(this.socket.id);
sessionStorage.setItem('session', this.socket.id!); sessionStorage.setItem('session', this.socket.id!);
}); });

View File

@@ -43,7 +43,7 @@
class="btn btn-error text-xl" class="btn btn-error text-xl"
onclick={() => { onclick={() => {
gameState.socket.emit('leave'); gameState.socket.emit('leave');
gameState = new State(window.location.hostname); gameState = new State(window.location.hostname, true);
}}>Leave</button }}>Leave</button
> >
</div> </div>

View File

@@ -4,7 +4,9 @@ CREATE TYPE STAT AS ENUM ('waiting', 'p1turn', 'p2turn');
CREATE TABLE IF NOT EXISTS players ( CREATE TABLE IF NOT EXISTS players (
id CHAR(16) PRIMARY KEY, id CHAR(16) PRIMARY KEY,
board CHAR(10) [10], board CHAR(10) [10],
room_code CHAR(4) NOT NULL room_code CHAR(4) NOT NULL,
abandoned BOOLEAN DEFAULT FALSE NOT NULL,
time TIMESTAMP DEFAULT NOW() NOT NULL
); );
CREATE TABLE IF NOT EXISTS rooms ( CREATE TABLE IF NOT EXISTS rooms (
@@ -24,12 +26,6 @@ CREATE TABLE IF NOT EXISTS rooms (
) )
); );
CREATE TABLE IF NOT EXISTS abandoned_players (
time TIMESTAMP PRIMARY KEY,
id CHAR(16) NOT NULL,
CONSTRAINT fk_player_id FOREIGN KEY (id) REFERENCES players (id) ON DELETE CASCADE ON UPDATE CASCADE
);
ALTER TABLE players ALTER TABLE players
ADD CONSTRAINT fk_room_code FOREIGN KEY (room_code) REFERENCES rooms (code) ON DELETE ADD CONSTRAINT fk_room_code FOREIGN KEY (room_code) REFERENCES rooms (code) ON DELETE
SET NULL; SET NULL;
@@ -40,22 +36,5 @@ SET NULL ON UPDATE CASCADE,
ADD CONSTRAINT fk_player2 FOREIGN KEY (player2_id) REFERENCES players (id) ON DELETE ADD CONSTRAINT fk_player2 FOREIGN KEY (player2_id) REFERENCES players (id) ON DELETE
SET NULL ON UPDATE CASCADE; SET NULL ON UPDATE CASCADE;
-- delete room if both players are null
CREATE OR REPLACE FUNCTION delete_room() RETURNS TRIGGER AS $$ BEGIN IF (
SELECT player1_id IS NULL
AND player2_id IS NULL
FROM rooms
WHERE code = OLD.room_code
) THEN
DELETE FROM rooms
WHERE code = OLD.room_code;
END IF;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER delete_room_trigger
AFTER DELETE ON players FOR EACH ROW EXECUTE FUNCTION delete_room();
CREATE INDEX idx_player_room_code ON players (room_code); CREATE INDEX idx_player_room_code ON players (room_code);
CREATE INDEX idx_room_status ON rooms (stat); CREATE INDEX idx_room_status ON players (abandoned);

View File

@@ -0,0 +1,39 @@
-- delete room if both players are null
CREATE OR REPLACE FUNCTION delete_room() RETURNS TRIGGER AS $$ BEGIN IF (
SELECT player1_id IS NULL
AND player2_id IS NULL
FROM rooms
WHERE code = OLD.room_code
) THEN
DELETE FROM rooms
WHERE code = OLD.room_code;
END IF;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER delete_room_trigger
AFTER DELETE ON players FOR EACH ROW EXECUTE FUNCTION delete_room();
-- retain only 1000 recent abandoned players according to timestamp
CREATE OR REPLACE FUNCTION delete_player() RETURNS TRIGGER AS $$ BEGIN IF (
SELECT COUNT(*)
FROM players
WHERE abandoned = TRUE
) > 10000 THEN
DELETE FROM players
WHERE id IN (
SELECT id
FROM players
WHERE abandoned = TRUE
ORDER BY time DESC OFFSET 10000
);
END IF;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER delete_player_trigger
AFTER
INSERT ON players FOR EACH ROW EXECUTE FUNCTION delete_player();

View File

@@ -1,3 +1,4 @@
use rand::Rng;
use serde::Serialize; use serde::Serialize;
use socketioxide::socket::Sid; use socketioxide::socket::Sid;
use thiserror::Error; use thiserror::Error;
@@ -20,6 +21,8 @@ pub enum Error {
NotInRoom, NotInRoom,
#[error("Invalid Move")] #[error("Invalid Move")]
InvalidMove, InvalidMove,
#[error("Code Generation Limit Reached")]
CodeGenerationLimitReached,
#[error("SQL Error\n{0:?}")] #[error("SQL Error\n{0:?}")]
Sqlx(#[from] sqlx::Error), Sqlx(#[from] sqlx::Error),
} }
@@ -41,8 +44,28 @@ pub async fn room_if_player_exists(sid: &str, pool: &sqlx::PgPool) -> Result<Opt
) )
} }
pub async fn add_room(sid: Sid, code: String, pool: &sqlx::PgPool) -> Result<()> { async fn generate_code(pool: &sqlx::PgPool) -> Result<String> {
for _ in 0..50 {
let code: String = rand::thread_rng()
.sample_iter(&rand::distributions::Alphanumeric)
.take(ROOM_CODE_LENGTH)
.map(|x| char::to_ascii_uppercase(&(x as char)))
.collect();
if sqlx::query!(r"SELECT code FROM rooms WHERE code = $1", code)
.fetch_optional(pool)
.await?
.is_none()
{
return Ok(code);
}
}
Err(Error::CodeGenerationLimitReached)
}
pub async fn add_room(sid: Sid, pool: &sqlx::PgPool) -> Result<String> {
delete_sid(sid.as_str(), pool).await?; delete_sid(sid.as_str(), pool).await?;
let code = generate_code(&pool).await?;
sqlx::query!( sqlx::query!(
r"WITH new_user AS (INSERT INTO players (id, room_code) VALUES ($1, $2) RETURNING id) INSERT INTO rooms (player1_id, code) SELECT $1, $2 FROM new_user", r"WITH new_user AS (INSERT INTO players (id, room_code) VALUES ($1, $2) RETURNING id) INSERT INTO rooms (player1_id, code) SELECT $1, $2 FROM new_user",
sid.as_str(), sid.as_str(),
@@ -50,7 +73,7 @@ pub async fn add_room(sid: Sid, code: String, pool: &sqlx::PgPool) -> Result<()>
) )
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(code)
} }
pub async fn join_room(sid: Sid, code: String, pool: &sqlx::PgPool) -> Result<()> { pub async fn join_room(sid: Sid, code: String, pool: &sqlx::PgPool) -> Result<()> {
@@ -286,9 +309,13 @@ pub async fn attack(
} }
pub async fn update_sid(oldsid: &str, newsid: &str, pool: &sqlx::PgPool) -> Result<()> { pub async fn update_sid(oldsid: &str, newsid: &str, pool: &sqlx::PgPool) -> Result<()> {
sqlx::query!(r"UPDATE players SET id = $1 WHERE id = $2", newsid, oldsid) sqlx::query!(
.execute(pool) r"UPDATE players SET id = $1, abandoned = FALSE WHERE id = $2",
.await?; newsid,
oldsid
)
.execute(pool)
.await?;
Ok(()) Ok(())
} }
@@ -300,32 +327,17 @@ pub async fn delete_sid(sid: &str, pool: &sqlx::PgPool) -> Result<()> {
} }
pub async fn to_delete_sid(sid: &str, pool: &sqlx::PgPool) -> Result<()> { pub async fn to_delete_sid(sid: &str, pool: &sqlx::PgPool) -> Result<()> {
sqlx::query!( sqlx::query!(r"UPDATE players SET abandoned = TRUE WHERE id = $1", sid)
r"INSERT INTO abandoned_players (time, id) VALUES (NOW(), $1)", .execute(pool)
sid .await?;
)
.execute(pool)
.await?;
Ok(()) Ok(())
} }
pub async fn in_delete_sid(sid: &str, pool: &sqlx::PgPool) -> Result<bool> { pub async fn in_delete_sid(sid: &str, pool: &sqlx::PgPool) -> Result<bool> {
Ok( Ok(
sqlx::query!(r"SELECT id FROM abandoned_players WHERE id = $1", sid) sqlx::query!(r"SELECT abandoned FROM players WHERE id = $1", sid)
.fetch_optional(pool) .fetch_one(pool)
.await? .await?
.is_some(), .abandoned,
) )
} }
pub async fn delete_abandoned(pool: &sqlx::PgPool) -> Result<()> {
sqlx::query!(
r"DELETE FROM players
WHERE id IN (SELECT id FROM abandoned_players
ORDER BY time DESC
OFFSET 1000)"
)
.execute(pool)
.await?;
Ok(()) // TODO: REMOVE duliplcates id from abandoned
}

View File

@@ -32,10 +32,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let pool = sqlx::postgres::PgPool::connect(&url).await?; let pool = sqlx::postgres::PgPool::connect(&url).await?;
sqlx::migrate!("./migrations").run(&pool).await?; sqlx::migrate!("./migrations").run(&pool).await?;
sqlx::query("DELETE FROM players").execute(&pool).await?; sqlx::query("DELETE FROM players").execute(&pool).await?;
sqlx::query("DELETE FROM abandoned_players")
.execute(&pool)
.await?;
sqlx::query("DELETE FROM rooms").execute(&pool).await?;
let (layer, io) = SocketIo::builder().with_state(pool).build_layer(); let (layer, io) = SocketIo::builder().with_state(pool).build_layer();
io.ns("/", on_connect); io.ns("/", on_connect);
@@ -90,18 +86,15 @@ async fn on_connect(socket: SocketRef, Data(auth): Data<AuthPayload>, pool: Stat
return; return;
} }
let room: String = rand::thread_rng() let room = match add_room(socket.id, &pool).await {
.sample_iter(&rand::distributions::Alphanumeric) Err(e) => {
.take(ROOM_CODE_LENGTH) tracing::error!("{:?}", e);
.map(|x| char::to_ascii_uppercase(&(x as char))) return;
.collect(); }
tracing::info!("Creating room: {:?}", room); Ok(c) => c,
// TODO: Handle duplicates };
if let Err(e) = add_room(socket.id, room.clone(), &pool).await { tracing::info!("Creating room: {:?}", room);
tracing::error!("{:?}", e);
return;
}
socket.leave_all().unwrap(); socket.leave_all().unwrap();
socket.join(room.clone()).unwrap(); socket.join(room.clone()).unwrap();
emit_update_room( emit_update_room(
@@ -202,17 +195,17 @@ async fn on_connect(socket: SocketRef, Data(auth): Data<AuthPayload>, pool: Stat
"leave", "leave",
|socket: SocketRef, pool: State<PgPool>| async move { |socket: SocketRef, pool: State<PgPool>| async move {
tracing::info!("Leaving Rooms: {:?}", socket.id); tracing::info!("Leaving Rooms: {:?}", socket.id);
leave_and_inform(&socket, &pool).await; leave_and_inform(&socket, &pool, true).await;
}, },
); );
socket.on_disconnect(|socket: SocketRef, pool: State<PgPool>| async move { socket.on_disconnect(|socket: SocketRef, pool: State<PgPool>| async move {
tracing::info!("Disconnecting: {:?}", socket.id); tracing::info!("Disconnecting: {:?}", socket.id);
leave_and_inform(&socket, &pool).await; leave_and_inform(&socket, &pool, false).await;
}); });
} }
async fn leave_and_inform(socket: &SocketRef, pool: &PgPool) { async fn leave_and_inform(socket: &SocketRef, pool: &PgPool, delete: bool) {
let room = socket let room = socket
.rooms() .rooms()
.unwrap() .unwrap()
@@ -225,7 +218,12 @@ async fn leave_and_inform(socket: &SocketRef, pool: &PgPool) {
let ops = socket.within(room.clone()); let ops = socket.within(room.clone());
socket.leave_all().unwrap(); socket.leave_all().unwrap();
emit_update_room(socket, &room.to_string(), ops.sockets().unwrap().len()); emit_update_room(socket, &room.to_string(), ops.sockets().unwrap().len());
if let Err(e) = to_delete_sid(socket.id.as_str(), pool).await { let sid = socket.id.as_str();
if let Err(e) = if delete {
delete_sid(sid, &pool).await
} else {
to_delete_sid(sid, &pool).await
} {
tracing::error!("{:?}", e); tracing::error!("{:?}", e);
} }
} }