From 8fbf71b667d8b02777361adb7189939bd2d6fd02 Mon Sep 17 00:00:00 2001 From: Kjetil Orbekk Date: Wed, 16 Nov 2022 09:10:41 -0500 Subject: Generate and display table in the webapp --- server/src/error.rs | 3 +++ server/src/main.rs | 12 ++++++++---- server/src/play.rs | 15 ++++++++++++++- webapp/src/components/table.rs | 27 ++++++++++++++++++++------- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/server/src/error.rs b/server/src/error.rs index 03735a7..6c2dc41 100644 --- a/server/src/error.rs +++ b/server/src/error.rs @@ -50,6 +50,9 @@ pub enum BridgeError { #[error("Duration out of range")] DurationOutOfRange(#[from] time::OutOfRangeError), + #[error("Not found: {0}")] + NotFound(String), + #[error("Sequence number mismatch: {0} ≠ {1}")] UpdateConflict(i64, i64), } diff --git a/server/src/main.rs b/server/src/main.rs index dd7956a..900d261 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -9,7 +9,7 @@ use axum::{ routing::{delete, get, post}, Json, Router, }; -use protocol::{Table, UserInfo}; +use protocol::{Table, UserInfo, bridge_engine}; use server::ContextExtension; use tower_cookies::{Cookie, CookieManagerLayer, Cookies}; use tower_http::trace::TraceLayer; @@ -82,11 +82,15 @@ async fn main() { async fn get_table_view( _session: AuthenticatedSession, - _extension: ContextExtension, + extension: ContextExtension, Path(id): Path -) -> Result, BridgeError> { +) -> Result, BridgeError> { info!("Getting table state for table {id:}"); - Ok(Json(protocol::TableView { m: format!("hello") })) + let jnl = DbJournal::new(extension.db.clone(), id); + let table = play::Table::new_or_replay(jnl).await?; + let response: Json = Json(table.game().clone()); + info!("Response: {response:#?}"); + Ok(response) } async fn leave_table( diff --git a/server/src/play.rs b/server/src/play.rs index 2632b24..01f4847 100644 --- a/server/src/play.rs +++ b/server/src/play.rs @@ -75,6 +75,10 @@ where game: GameState, } +impl Table { + pub fn game(&self) -> &GameState { &self.game } +} + impl Table { pub async fn new(mut journal: J) -> Result { let game = GameState::Bidding { @@ -88,7 +92,16 @@ impl Table { pub async fn replay(mut journal: J) -> Result { let games = journal.replay(0).await?; if games.is_empty() { - return Err(BridgeError::Internal(format!("empty journal"))); + return Err(BridgeError::NotFound("table journal missing".to_string())); + } + let game = serde_json::from_value(games[games.len() - 1].clone())?; + Ok(Table { journal, game } ) + } + + pub async fn new_or_replay(mut journal: J) -> Result { + let games = journal.replay(0).await?; + if games.is_empty() { + return Self::new(journal).await; } let game = serde_json::from_value(games[games.len() - 1].clone())?; Ok(Table { journal, game } ) diff --git a/webapp/src/components/table.rs b/webapp/src/components/table.rs index bccbfe4..3561131 100644 --- a/webapp/src/components/table.rs +++ b/webapp/src/components/table.rs @@ -1,3 +1,4 @@ +use gloo_net::http::Request; use log::info; use yew::prelude::*; @@ -7,15 +8,26 @@ use crate::use_app_context; pub fn table(props: &TableProps) -> Html { let ctx = use_app_context(); - // let table_state: UseStateHandle> = use_state(|| None); + let table_state: UseStateHandle> = use_state(|| None); { // TODO update this from server state - // let table_state = table_state.clone(); - let ctx = ctx.clone(); - ctx.spawn_async(async move { - info!("Getting table state"); - Err(anyhow::anyhow!("Not implemented yet")) - }); + let table_state = table_state.clone(); + let props = props.clone(); + let ctx = ctx.clone(); + use_effect_with_deps( + move |_| { + ctx.spawn_async(async move { + let response = Request::get(&format!("/api/table/{}", props.table.id)) + .send() + .await?; + let table: protocol::bridge_engine::GameState = response.json().await?; + table_state.set(Some(format!("{:#?}", table))); + Ok(()) + }); + || () + }, + (), + ); } let leave_table = { @@ -31,6 +43,7 @@ pub fn table(props: &TableProps) -> Html { +
{ table_state.as_ref().map_or("".to_string(), |t| format!("{}", t)) }
} } -- cgit v1.2.3