summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2022-12-18 13:40:53 -0500
committerKjetil Orbekk <kj@orbekk.com>2022-12-18 13:40:53 -0500
commit4512c5ead9406206de32e37490b7a4ac792d93bf (patch)
treed3905c1e951b834f674f9c4c868e9dabe1fd0587 /server
parent3746208a1fbc71d104fc04bd50a54921ac8eca90 (diff)
Add bidding API
Diffstat (limited to 'server')
-rw-r--r--server/src/main.rs70
-rw-r--r--server/src/play.rs2
2 files changed, 55 insertions, 17 deletions
diff --git a/server/src/main.rs b/server/src/main.rs
index 68baab7..a8429ec 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -9,8 +9,8 @@ use axum::{
routing::{delete, get, post},
Json, Router,
};
+use protocol::bridge_engine::{Bid, GameStatePlayerView, Player};
use protocol::{Table, UserInfo};
-use protocol::bridge_engine::{GameStatePlayerView, Player};
use server::ContextExtension;
use tower_cookies::{Cookie, CookieManagerLayer, Cookies};
use tower_http::trace::TraceLayer;
@@ -18,37 +18,46 @@ use tracing::{info, log::warn};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
mod auth;
mod error;
-mod play;
-mod server;
#[cfg(debug_assertions)]
mod fake_auth;
+mod play;
+mod server;
use crate::{
auth::{OauthAuthenticator, SessionId},
- server::ServerContext, play::advance_play,
+ play::advance_play,
+ server::ServerContext,
};
use crate::{
error::BridgeError,
play::{DbJournal, Journal},
};
-use sqlx::{postgres::PgPoolOptions, PgPool};
use auth::Authenticator;
+use sqlx::{postgres::PgPoolOptions, PgPool};
-async fn create_default_authenticator(db_pool: &PgPool) -> Box<dyn Authenticator + Send + Sync> {
+async fn create_default_authenticator(
+ db_pool: &PgPool,
+) -> Box<dyn Authenticator + Send + Sync> {
Box::new(OauthAuthenticator::from_env(db_pool.clone()).await)
}
#[cfg(debug_assertions)]
-async fn create_authenticator(db_pool: &PgPool) -> Box<dyn Authenticator + Send + Sync> {
+async fn create_authenticator(
+ db_pool: &PgPool,
+) -> Box<dyn Authenticator + Send + Sync> {
const FAKE_AUTHENTICATOR: &str = "fake";
- if std::env::var("AUTHENTICATOR").unwrap_or("".to_string()) == FAKE_AUTHENTICATOR {
- Box::new(fake_auth::FakeAuthenticator::new())
+ if std::env::var("AUTHENTICATOR").unwrap_or("".to_string())
+ == FAKE_AUTHENTICATOR
+ {
+ Box::new(fake_auth::FakeAuthenticator::new())
} else {
create_default_authenticator(db_pool).await
}
}
#[cfg(not(debug_assertions))]
-async fn create_authenticator(db_pool: &PgPool) -> Box<dyn Authenticator + Send + Sync> {
+async fn create_authenticator(
+ db_pool: &PgPool,
+) -> Box<dyn Authenticator + Send + Sync> {
create_default_authenticator(db_pool)
}
@@ -96,14 +105,14 @@ async fn main() {
let app = Router::new();
#[cfg(debug_assertions)]
- let app = app
- .route("/api/fake_login", get(fake_login));
+ let app = app.route("/api/fake_login", get(fake_login));
let app = app
.route("/api/user/info", get(user_info))
.route("/api/table", post(create_table))
.route("/api/table", delete(leave_table))
.route("/api/table/:id", get(get_table_view))
+ .route("/api/table/:id/bid", post(post_bid))
// .route("/api/user/table", get(user_table))
.route("/api/login", get(login))
.route(auth::LOGIN_CALLBACK, get(login_callback))
@@ -119,7 +128,8 @@ async fn main() {
#[cfg(debug_assertions)]
async fn fake_login() -> Html<&'static str> {
- Html(r#"
+ Html(
+ r#"
<!DOCTYPE html>
<html lang="en">
<body>
@@ -129,7 +139,8 @@ async fn fake_login() -> Html<&'static str> {
</ul>
</body>
</html>
- "#)
+ "#,
+ )
}
async fn get_table_view(
@@ -145,12 +156,39 @@ async fn get_table_view(
while table.game().current_player() != Some(player_position) {
advance_play(&mut table).await?;
}
- let response =
- Json(GameStatePlayerView::from_game_state(table.game(), player_position));
+ let response = Json(GameStatePlayerView::from_game_state(
+ table.game(),
+ player_position,
+ ));
info!("Response: {response:#?}");
Ok(response)
}
+async fn post_bid(
+ _session: AuthenticatedSession,
+ extension: ContextExtension,
+ Path(id): Path<Uuid>,
+ Json(bid): Json<Bid>,
+) -> Result<Json<()>, BridgeError> {
+ info!("Getting table state for {id:}");
+ let jnl = DbJournal::new(extension.db.clone(), id);
+ let mut table = play::Table::new_or_replay(jnl).await?;
+ if !table.game().is_bidding() {
+ return Err(BridgeError::InvalidRequest(
+ "Posting a bid requires that the game is in the bidding phase"
+ .to_string(),
+ ));
+ }
+ let player_position = Player::South;
+ if table.game().current_player() != Some(player_position) {
+ return Err(BridgeError::InvalidRequest(format!(
+ "It is not {player_position:?} to play"
+ )));
+ }
+ table.bid(bid).await?;
+ Ok(Json(()))
+}
+
async fn leave_table(
session: AuthenticatedSession,
extension: ContextExtension,
diff --git a/server/src/play.rs b/server/src/play.rs
index a6e78f2..e78a19e 100644
--- a/server/src/play.rs
+++ b/server/src/play.rs
@@ -115,7 +115,7 @@ impl<J: Journal> Table<J> {
Ok(game)
}
- async fn bid(&mut self, bid: Bid) -> Result<(), BridgeError> {
+ pub async fn bid(&mut self, bid: Bid) -> Result<(), BridgeError> {
let game = self.game.clone().bid(bid)?;
self.journal.append(self.journal.next(), json!(game)).await?;
self.game = game;