Skip to main content

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}