server/services/action/play_card.rs
1use crate::{
2 domain::{Card, GameCommand, GameId, UserId},
3 error::{ServerError, bug},
4 server_state::ServerState,
5 services::queries::get_game,
6};
7
8/// Plays a card for the user in the pegging phase of a game.
9///
10/// This function updates the game state by playing the specified card
11/// from the user's hand. It validates that the action is allowed for
12/// the given user and that the play is legal according to game rules.
13///
14/// # Parameters
15///
16/// - `server_state`: The shared server state containing the game and database.
17/// - `user_id`: The ID of the user playing the card.
18/// - `game_id`: The ID of the game in which the card is being played.
19/// - `card`: The card to play.
20///
21/// # Returns
22///
23/// Returns `Ok(())` if the card was successfully played.
24/// Returns a `ServerError` if the action is forbidden, the game is not found,
25/// the play is illegal, or another internal error occurs.
26pub async fn play_card(
27 server_state: ServerState,
28 user_id: UserId,
29 game_id: GameId,
30 card: Card,
31) -> Result<(), ServerError> {
32 if let Some(game) = get_game(server_state.clone(), game_id).await? {
33 let player = game
34 .validate_user(user_id)
35 .ok_or(ServerError::Forbidden("play".into()))?;
36
37 let aggregate_id = game_id.value().to_string();
38
39 let command = GameCommand::PlayCard { player, card };
40
41 server_state
42 .cqrs
43 .execute(&aggregate_id, command)
44 .await
45 .map_err(bug!())?;
46
47 Ok(())
48 } else {
49 Err(ServerError::NotFound)
50 }
51}