module Api exposing ( GameDetails , Player , gameDetails , profile , startGame ) import Dict exposing (Dict) import Http import Json.Decode as D import Json.Encode as E endpointGameDetails = "/game-details" endpointGetProfile = "/profile" endpointStartGame = "/start-game" {-| Full report on how a game is going. -} type alias GameDetails gameState = { name : String , turns : List { player : Int, action : E.Value, state : gameState } , winner : Maybe Int } {-| General format of a player who's allowed to participate. -} type alias Player = { name : String , games : Dict String (Dict String E.Value) , profile : Dict String E.Value , url : String } {-| Builds a generalized API call to the webclient server. -} callWebClient : { body : Maybe D.Value , decoder : D.Decoder a , method : String , toMsg : Result Http.Error a -> msg , url : String } -> Cmd msg callWebClient data = Http.request { method = data.method , headers = [] , url = data.url , body = data.body |> Maybe.map Http.jsonBody |> Maybe.withDefault Http.emptyBody , expect = Http.expectJson data.toMsg data.decoder , timeout = Nothing , tracker = Nothing } {-| Retrieves all the latest details about a game. A game might still be ongoing and therefore might be incomplete. -} gameDetails : { baseUrl : String , decoder : D.Decoder gameState , gameId : String , toMsg : Result Http.Error (GameDetails gameState) -> msg } -> Cmd msg gameDetails data = callWebClient { body = Just (E.object [ ( "game_id", E.string data.gameId ) ]) , decoder = gameDetailsDecoder data.decoder , method = "GET" , toMsg = data.toMsg , url = data.baseUrl ++ endpointGameDetails } {-| Decodes a game's details from JSON. -} gameDetailsDecoder : D.Decoder gameState -> D.Decoder (GameDetails gameState) gameDetailsDecoder decoder = D.map3 GameDetails (D.field "name" D.string) (D.map3 (\action player state -> { player = player, action = action, state = state } ) (D.field "action" D.value) (D.field "player" D.int) (D.field "state" decoder) |> D.list |> D.field "turns" ) (D.field "winner" <| D.oneOf [ D.map Just D.int, D.null Nothing ]) {-| Decodes a Player from JSON. -} playerDecoder : D.Decoder Player playerDecoder = D.map4 Player (D.field "name" D.string) (D.field "games" <| D.dict <| D.dict D.value) (D.field "profile" <| D.dict D.value) (D.field "url" D.string) {-| Gets the profile of a given player with a given URL. -} profile : { baseUrl : String , playerUrl : String , toMsg : Result Http.Error Player -> msg } -> Cmd msg profile data = callWebClient { body = Just (E.object [ ( "url", E.string data.playerUrl ) ]) , decoder = playerDecoder , method = "GET" , toMsg = data.toMsg , url = data.baseUrl ++ endpointGetProfile } {-| Instructs the server to start a game with the PyClient. The players list provides a set of URLs that should be considered as its players, even if the players haven't been verified (yet). The server responds with a unique identifier for the game. This allows the front-end to query updates about the game while it's still being processed. -} startGame : { baseUrl : String , game : String , players : List String , toMsg : Result Http.Error String -> msg } -> Cmd msg startGame data = callWebClient { body = Just (E.object [ ( "game", E.string data.game ) , ( "players", E.list E.string data.players ) ] ) , decoder = D.string , method = "POST" , toMsg = data.toMsg , url = data.baseUrl ++ endpointStartGame }