168 lines
4.0 KiB
Elm
168 lines
4.0 KiB
Elm
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
|
|
}
|