Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Board stream #14

Merged
merged 3 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
364 changes: 219 additions & 145 deletions Cargo.lock

Large diffs are not rendered by default.

18 changes: 6 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,22 @@ edition = "2021"
[dependencies]
askama = { version = "0.12.1", features = ["with-axum"] }
askama_axum = "0.4.0"
axum = "0.7.3"
axum = { version = "^0.7", features = ["tokio"] }
serde = { version = "1.0.195", features = ["derive"] }
serde_json = "1.0.111"
shuttle-axum = "0.36.0"
shuttle-runtime = "0.36.0"
shuttle-shared-db = { version = "0.36.0", features = ["postgres"] }
shuttle-axum = "^0.37"
shuttle-runtime = "^0.37"
shuttle-shared-db = { version = "^0.37", features = ["sqlx", "postgres"] }
sqlx = { version = "0.7.3", features = ["macros", "uuid", "time"] }
thiserror = "1.0.56"
time = { version = "0.3.31", features = ["serde"] }
tokio = "1.28.2"
tokio-stream = { version = "0.1.14", features = ["sync"] }
tower-http = { version = "0.5.1", features = ["fs"] }
uuid = { version = "1.7.0", features = ["serde"] }
pleco = "0.5.0"

tracing = "^0.1"
tracing-appender = "^0.2"
tracing-futures = { version = "^0.2", default-features = false, features = ["std-future"] }
tracing-subscriber = { version = "^0.3", default-features = false, features = ["ansi", "env-filter", "fmt", "local-time", "time", "tracing"] }
pleco = "0.5.0"


# TODO: add prop tests for database types
# [dev-dependencies]
# proptest = "1.4.0"
# proptest-derive = "0.4.0"
tracing-subscriber = { version = "^0.3", default-features = false, features = ["ansi", "env-filter", "fmt", "local-time", "time", "tracing"] }
8 changes: 6 additions & 2 deletions src/api/games/make_move.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ use axum::{
};
use sqlx::types::Uuid;

use crate::api::models::ApiGameBoard;
use crate::api::templates::GameBoardTemplate;
use crate::database::models::{Game, GameBoard, GameError};
use crate::AppState;

use super::watch_game_sse::{GameUpdate, GameUpdateStream};
use super::watch_game_sse::GameUpdateStream;

#[derive(serde::Deserialize, Debug)]
pub struct MakeMoveRequest {
Expand All @@ -34,9 +36,11 @@ pub async fn handler(
// Returns the updated board if the move was valid. Otherwise, returns the latest board.
GameBoard::make_move(&mut conn, game_id, &uci_move, resign).await?;

// Wow this really sucks, the client should just read this again
let api_game_board = ApiGameBoard::from(GameBoard::latest(&mut conn, game_id).await?);
conn.commit().await?;

if tx.send(GameUpdate).is_err() {
if tx.send(GameBoardTemplate { api_game_board }).is_err() {
tracing::warn!("failed to send game update: game_id={}", game_id);
}

Expand Down
1 change: 0 additions & 1 deletion src/api/games/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ pub mod create_game;
pub mod make_move;
pub mod read_all_games;
pub mod read_game;
pub mod read_game_board;
pub mod watch_game_sse;
12 changes: 3 additions & 9 deletions src/api/games/read_game.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use askama::Template;
use axum::{
extract::{Path, State},
response::{IntoResponse, Response},
};
use sqlx::types::Uuid;

use crate::api::models::ApiGameBoard;
use crate::api::templates::GameIndexTemplate;
use crate::database::models::{Game, GameBoard, GameError};
use crate::AppState;

Expand All @@ -21,14 +21,8 @@ pub async fn handler(
let game_board = GameBoard::latest(&mut conn, game_id).await?;

let api_game_board = ApiGameBoard::from(game_board);

Ok(TemplateApiGameBoard { api_game_board })
}

#[derive(Template)]
#[template(path = "game_index.html")]
struct TemplateApiGameBoard {
api_game_board: ApiGameBoard,

Ok(GameIndexTemplate { api_game_board })
}

#[derive(Debug, thiserror::Error)]
Expand Down
16 changes: 10 additions & 6 deletions src/api/games/watch_game_sse.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
use std::convert::Infallible;
use std::time::Duration;

use askama::Template;
use axum::{
extract::Path,
response::{sse::Event, Sse},
Extension,
};
use serde::Serialize;
use sqlx::types::Uuid;
use tokio::sync::broadcast::Sender;
use tokio_stream::wrappers::BroadcastStream;
use tokio_stream::{Stream, StreamExt as _};

pub type GameUpdateStream = Sender<GameUpdate>;

#[derive(Clone, Serialize, Debug)]
pub struct GameUpdate;
use crate::api::templates::GameBoardTemplate;

// TODO: generalize and use the read_game_board handler
pub type GameUpdateStream = Sender<GameBoardTemplate>;
pub async fn handler(
Path(game_id): Path<Uuid>,
Extension(tx): Extension<GameUpdateStream>,
Expand All @@ -28,7 +27,12 @@ pub async fn handler(
// Catch all updata events for this game
Sse::new(
stream
.map(move |_| Event::default().event(format!("game-update-{}", game_id)))
.map(move |tagb| {
let tagb = tagb.unwrap();
Event::default()
.event(format!("game-update-{}", game_id))
.data(tagb.render().unwrap())
})
.map(Ok),
)
.keep_alive(
Expand Down
1 change: 1 addition & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod games;
pub mod models;
pub mod templates;
1 change: 1 addition & 0 deletions src/api/models/api_game_board.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::database::models::GameStatus;
use crate::database::models::GameWinner;
use crate::database::types::DatabaseBoard as Board;

#[derive(Clone)]
pub struct ApiGameBoard {
pub game_id: String,
pub board: Board,
Expand Down
9 changes: 9 additions & 0 deletions src/api/templates/game_board.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use askama::Template;

use crate::api::models::ApiGameBoard;

#[derive(Template, Clone)]
#[template(path = "game_board.html")]
pub struct GameBoardTemplate {
pub api_game_board: ApiGameBoard,
}
9 changes: 9 additions & 0 deletions src/api/templates/game_index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use askama::Template;

use crate::api::models::ApiGameBoard;

#[derive(Template)]
#[template(path = "game_index.html")]
pub struct GameIndexTemplate {
pub api_game_board: ApiGameBoard,
}
5 changes: 5 additions & 0 deletions src/api/templates/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod game_board;
mod game_index;

pub use game_board::GameBoardTemplate;
pub use game_index::GameIndexTemplate;
8 changes: 3 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use tower_http::services::ServeDir;
mod api;
mod database;

use api::templates::GameBoardTemplate;

#[derive(Clone)]
pub struct AppState {
database: PgPool,
Expand Down Expand Up @@ -37,7 +39,7 @@ async fn main(
.expect("Looks like something went wrong with migrations :(");
// Setup State
let state = AppState::new(db);
let (tx, _rx) = channel::<api::games::watch_game_sse::GameUpdate>(10);
let (tx, _rx) = channel::<GameBoardTemplate>(10);

// Register panics as they happen
register_panic_logger();
Expand All @@ -59,10 +61,6 @@ async fn main(
"/games/:game_id/sse",
get(api::games::watch_game_sse::handler),
)
.route(
"/games/:game_id/board",
get(api::games::read_game_board::handler),
)
.with_state(state)
.layer(Extension(tx))
// Static assets
Expand Down
Loading
Loading